-1

So if I had the following:

public abstract ClassA {}

public class ClassB extends ClassA {}

public class ClassC extends ClassA {}

Is there a way to do the following:

ClassB b = new ClassB();
ClassC c = (ClassC)b;

I know you can not directly do it but is there a way that avoids having to write a translator that would have every field like c.setField1(b.getField1).

Patrick Aquilone
  • 584
  • 2
  • 11
  • 28
  • 6
    It makes no sense to do this with casting, so no, you can't. You would need to write some sort of conversion code, one that creates new objects of the type you're interested from the type of the source. The questions hints at being a possible [XY Problem](http://xyproblem.info/) type question which are best solved by your telling the overall problem that you're trying to solve and not how you're trying to solve it, since you're likely barking up the wrong tree. – Hovercraft Full Of Eels Sep 25 '17 at 20:57
  • What if `ClassC` needs to have properties initialized that `ClassB` doesn't have? – tadman Sep 25 '17 at 20:57
  • In our case, we have a DTO object gets mapped into a database object and then used to insert into the database. I was just hoping to not have to create a conversion/translation of the object. – Patrick Aquilone Sep 25 '17 at 21:00
  • 3
    This is the equivalent to "can I treat this microwave like a refrigerator?" Yes, they are both kitchen appliances, but... – Joe C Sep 25 '17 at 21:00
  • 1
    So, the real question is about how to avoid conversion/mapping between a DTO and an Entity on the data access layer? – Mick Mnemonic Sep 25 '17 at 21:03
  • 1
    You can write a generic translator that inspects the two objects using reflection and finds out which getters and setters to combine . You might find that writing it out by hand is less brittle, though. – Thorbjørn Ravn Andersen Sep 25 '17 at 21:32
  • lol... the infamous DTO to Domain translation. I had a question or 2 regarding this a while back. The solution that I reached? Don't create additional DTO object, just expose the domain object itself and deal with the differences using some jackson annotations. (it worked out well for me, it may not for you) https://stackoverflow.com/questions/44572188/microservices-restful-api-dtos-or-not – so-random-dude Sep 25 '17 at 21:38
  • @Joanna, yes, the "correct" thing to do probably _depends_.. It's a tradeoff between tightly coupling the data structures / message format you use in integration APIs with your data model and having to duplicate some/quite a bit of code. If you're going with DTOs, there are [mapping frameworks](https://stackoverflow.com/questions/1432764/any-tool-for-java-object-to-object-mapping/1432956#1432956) that make things easier. – Mick Mnemonic Sep 25 '17 at 21:47

1 Answers1

0

It is not possible to cast a child to a child nor was it possible to cast a child to the parent and then back to the parent. So I wrote a generic translator to copy all the data from one child class of BankInstruction to another.

/**
 * Convert a BankInstruction Child class to another bank instruction child class
 *
 * @param incoming
 *            The incoming child class with data
 * @param clazz
 *            The class we want to convert to and populate
 * @return
 *         The class we requested with all the populated data
 */
public static <I extends BankInstruction, O extends BankInstruction> O convertBankInstructionModel(final I incoming,
                                                                                                   final Class<O> clazz) {

    // Create return data object
    O outgoing = null;

    // Attempt to instantiate the object request
    try {
        outgoing = clazz.newInstance();

        // Catch and log any exception thrown
    } catch (Exception exceptThrown) {
        exceptThrown.printStackTrace();
        return null;
    }

    // Loop through all of the methods in the class
    for (Method method : BankInstruction.class.getMethods()) {

        // Check if we have a set method
        if (method.getName().substring(0, 3).equalsIgnoreCase("set")) {

            // Create a corresponding get method
            String getMethodName = method.getName().replace("set", "get");

            // Check if we have a get method for the set method variable
            if (Arrays.toString(BankInstruction.class.getMethods()).contains(getMethodName)) {

                // Get the method from the method name
                Method getMethod = getMethodFromName(BankInstruction.class, getMethodName);

                try {

                    // If we have a method proceed
                    if (getMethod != null) {

                        // Attempt to invoke the method and get the response
                        Object getReturn = getMethod.invoke(incoming);

                        // If we have a response proceed
                        if (getReturn != null) {

                            // Attempt to invoke the set method passing it the object we just got from the get
                            method.invoke(outgoing, getReturn);

                        }

                    }

                } catch (Exception except) {
                    except.printStackTrace();
                }

            }

        }

    }

    // Return the found object
    return outgoing;

}

Probably not the best solution but it is working for me.

Patrick Aquilone
  • 584
  • 2
  • 11
  • 28