2

I've a proyect that call various webservices using an external library. This library give me objects like this:

public static class ObjA {
    @XmlElement(name = "counter", required = true)
    protected BigInteger counter;
    @XmlElement(name = "data", required = true)
    protected String data;
    [...]
}

and this:

public static class ObjB {
    @XmlElement(name = "counter", required = true)
    protected BigInteger counter;
    @XmlElement(name = "data", required = true)
    protected String data;
    [...]
}

as you can see objA and objB have same properties so, if I have to use both, I've to duplicate code:

public class myClass {

    [...]
    private ObjA a;
    private ObjB b;
    [...]

    public void myClass() {
        [...]
        this.a = new ObjectFactory().createObjA();
        this.b = new ObjectFactory().createObjB();
        [...]
    }

    public void init() {
        this.initA();
        this.initB();
    }

    private void initA() {
        this.a.setCounter(BigInteger.ZERO);
        this.a.setData = "";
    }

    private void initB() {
        this.b.setCounter(BigInteger.ZERO);
        this.b.setData = "";
    }

    [...]
}

initA and initB are identical, I cannot access the library code so I can't create a common interface, in which way can I avoid duplicated code? I mean, it's possible to have something like this?

    private void initObj([ObjA|ObjB] obj) {
        obj.setCounter(BigInteger.ZERO);
        obj.setData = "";
    }

Thank you! Muchas Gracias!

addendum

Please note I have no access to the underlying library, so I can't add modify classes, interfaces, wsdl or xsd in any way. Also in my opinion is not important if I'm using a ws or not, jaxb or other library: you can imagine ObjA and ObjB without annotations, like this:

public static class ObjA {
    protected BigInteger counter;
    protected String data;
    [...]
}

public static class ObjB {
    protected BigInteger counter;
    protected String data;
    [...]
}

and the crux of the matter doesn't change.

4
  • If you cannot create a common interface (in this case abstract class), you'll have to write the code to initialize type ObjA and type ObjB no matter what you do. Commented Feb 11, 2015 at 16:44
  • You could use an dynamic approach (reflection or BeanUtil) to work on different types with the same method. However this has a number of own problems (static analysis does not know about it), so I would normally stay away from it. We don't know anything about the context, so there might be other solutions as well. And don't forget to talk to the API provider. Commented Feb 11, 2015 at 20:35
  • I would just make a super class, hand edit the generated ( guess its just one place per class) then make a read me and a video of what and why done. Commented Feb 12, 2015 at 7:35
  • @tgkprog I cannot "hand edit the generated", I have no access to the source code. Anyway I think forcing re-editing of the code if for some reason you have to regenerate it is really bad. Commented Feb 12, 2015 at 19:42

3 Answers 3

1

I assume that the classes are generated for you using some sort of tool, perhaps the maven cxf-codegen-plugin etc. If this is the case, you need to modify the WSDL and XSD's such that the DTO classes are generated to your satisfaction. If the WSDL was supplied to you, then you will just have to accept the service as is?

You could use reflection if you know that the common methods all have the same name?

so you'd do something like this with raw reflection :

import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

public class Test {    
    public static void initObject(Object o) throws Exception {
        if (!(o instanceof ObjA)&&!(o instanceof ObjB)) return;
        Method m = o.getClass().getMethod("setCounter",java.math.BigInteger.class);
        m.invoke(o,BigInteger.ZERO);
        m = o.getClass().getMethod("setData",java.lang.String.class);
        m.invoke(o,"");
    }

    public static void main(final String[] args) throws Exception {
        List<Object>objects = new ArrayList<Object>();
        //this is like your factory method
        Object o = Class.forName("ObjA").newInstance();
        initObject(o);
        objects.add(o);
        o = Class.forName("ObjB").newInstance();
        initObject(o);
        objects.add(o);
    }
}

If you wanted to use a library you could use something like JXPath and see docs here But I think for your purpose raw reflection is probably fine. There's no need for a massively complicated reflection library.

Sign up to request clarification or add additional context in comments.

5 Comments

I cannot modify the WSDL or XSDs. I'm considering reflection but as stated by @L.Butz it's a bad practice.
It is usually bad practice, simply because it's hard to do properly. But reflection is actually used in just about every major java library you choose, particularly Jackson etc. I can't think of any way around your problem that doesn't involve some sort of reflection based solution. You could try something like xpath to do the refelction for you commons.apache.org/proper/commons-jxpath
I think you're right. Would you post an answer with an example that solve the problem with ObjA and ObjB so I can eventually accept it?
I've added an example above
you can cache the methods, just do that part once, and later only invoke
1

I suppose that you are using JAXB. You can read a list of Objects. See this post: JAXB Unmarshalling: List of objects

4 Comments

How is this going to avoid the duplication of code as in OP's myClass? Please explain!
It's not a list of objects, they are two identical objects but defined with two names, it's like having <book><bookdata><title>my lillte book</title><cost>12</cost></bookdata></book><film><filmdata><title>my good film</title><cost>24</cost></filmdata></film>: bookdata and filmdata are identical but different objects
To provide a better help you should give more information abount the problem, like: are you using JAXB? You will call 1 webservice and with that reply you will build the object A and B? Or they will obtain information from different ws souces?
The point is I have no access to the library nor to WSDL, XSD, etc... Anyway, I think it's not important if the objects go through a ws or not, they are simply two identical objects, the underlying layer it's a sort of black box accepting them.
0

Since they don't have a common interface (or parent class?), I guess the way to go is with java reflection.

Create some reflection helper methods by yourself like "init(Class clazz)" and invoke the construtors.

Keep in mind that java reflection is bad practice in most cases, so make sure that there are no other/better methods to accomplish your goal.

1 Comment

Technically feasible, but as I try to imagine the signatures of the "helper methods" and the resulting code, I shudder, delicately. And compile time error checking will be delayed until runtime.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.