0

I have multiple classes generated from XSD files using XJC. These classes are automatically generated as part of the build process and therefore can't be modified. The classes share a common structure. I have client code that needs to use these classes. However, some of this client logic is the same for all the classes. Therefore, I don't want to duplicate the client code for every class to support. The popular solution that comes to mind in such case is to use interface/inheritance so that client code only deals with super class/interface instead of the specific classes. However, in this case, this solution is not possible since the classes can't be modified. Therefore, I guess the right direction is to use composition instead of inheritance. However, if composition is used, the composing class will need to deal with every specific classes so I will probably end up with many if (obj instanceof Type) to handle every case separately.

public class A {
    private int id;
    //Properties specific to type A
}

public class B {
    private int id;
    //Properties specific to type B
}

public class C {
    private int id;
    //Properties specific to type C
}

public class Client {
    public void myMethod(Object obj) {
        //obj may be an instance of A, B or C

        //I would like to access the id property (which is common to A, B and C)
        //using the most elegant way

        //Approach using instanceof
        if(obj instanceof A) {
            A objA = (A)obj;
            objA.getId();
        }
        if(obj instanceof B) {
            B objB = (B)obj;
            objB.getId();
        }
        if(obj instanceof C) {
            C objC = (C)obj;
            objC.getId();
        }
    }
}

I thought about using an approach where the instance is wrapped and the instanceof logic is inside the wrapper class instead of the client code.

public class Wrapper {
    private Object obj;

    public int getId() {
        if(obj instanceof A)
            return ((A)obj).getId();
        if(obj instanceof B)
            return ((B)obj).getId();
        if(obj instanceof C)
            return ((C)obj).getId();
    }
}

public class Client {
    public void myMethod(Wrapper wrapper) {
        //Only deals with wrappers, not with the objects themselves

        wrapper.getId();
    }
}

Is the use of instanceof necessary in this case? If yes, what is the recommended approach?


EDIT:

Reflection can also be used to avoid the multiple instanceof. Following the given example, if the getId() method is defined in every class (A, B and C), the following is possible:

public class Wrapper {
    private Object obj;

    public int getId() {
        return obj.getClass().getMethod("getId").invoke(obj);
    }
}

I forgot to mention that I don't have any control over the XSDs.

manash
  • 6,985
  • 12
  • 65
  • 125
  • You can use an xjb file to customize the generation of the classes, and make them implement an interface. See http://stackoverflow.com/questions/2916217/jaxb-generated-classes-implement-interface for example. – JB Nizet Mar 10 '16 at 22:25
  • @JBNizet In my experience, trying to tweak JAXB/XJC may be a nightmare. Also, implementing an interface requires that the methods are overriden in the generated classes, which may not be always the case. Similar structure doesn't necessarily mean same methods. There may be methods with different names but with logically equivalent returned information. – manash Mar 10 '16 at 22:30
  • do you have getId() method in every class? If Yes, you know the solution using reflection. – Ravindra babu Mar 10 '16 at 22:36
  • Well, if all the classes that are supposed to have a getId() method don't have an getId() method, then it's a sign that your schema has a problem, since you expect them to have one. And the compiler will warn you about the problem (which won't be the case with a reflection-basd method calling getId()). It's up to you to choose which classes implement which interface. XJB allows doing that. I'm not saying that ALL your classes implement that interface. Only the classes which should implement it, because they should all have a getId() method returning an int. – JB Nizet Mar 10 '16 at 22:42
  • @JBNizet Right, but in my case, I don't have any control over the schemas. – manash Mar 11 '16 at 09:21
  • If the schemas can change at any time, any reflection-based attempt at getting the ID from an object can fail at runtime, since there might not be any getId() method in the class, right? Using instanceof will instead fail at compile-time, because the code will try to call a getId() method that doesn't exist anymore. And adding an interface with a getId() method to some classes using XJB will also make the code fail at compile-time, because the generated call won't implement the interface. That will allow you to detect the change, fix the XJB file and your code. – JB Nizet Mar 11 '16 at 09:33
  • So it's clearly the best solution: failure at compile-time rather than runtime, and no ugly instanceof in the code. – JB Nizet Mar 11 '16 at 09:34

1 Answers1

0

You could use the impromptu-interface.

C# 4.0 (.net & silverlight) framework to allow you to wrap any object (static or dynamic) with a static interface even though it didn't inherit from it.

Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193