2

Let's assume that we have two classes class1 and class2 which are generated classes. These classes are very similar to each other that even some methods are the same, thus I would like to use the same code for them during verification. So, because they are both generated I cannot make an abstract class for them. This is how I do it for now, but I cannot say that I like it.

if (myObject instanceof Class1) {
  if (((Class1) myObject).getId().length() > MAX_LENGTH) {
     throw new Exception();
  }
} else if (myObject instanceof Class2) {
  if (((Class2) myObject).getId().length() > MAX_LENGTH) {
     throw new Exception();
  }
}

Is there a better way?

6
  • 12
    have you considered using interface? Put the shared method getId in the interface Commented May 20, 2016 at 8:17
  • When you say they are generated, how or what is generating them? Unless you can use either an abstract or interface, you can't assume they will have the same methods Commented May 20, 2016 at 8:23
  • If you can't use an interface either, you could hack something with introspection. It should really be a last resort though Commented May 20, 2016 at 8:23
  • Is Scala an option? Then you could use structural typing or implicit conversions and type classes. Commented May 20, 2016 at 8:28
  • 1
    If you can't modify the class implementations maybe invoking the method's by reflection is an option. Commented May 20, 2016 at 8:38

6 Answers 6

2

A slightly better version in my opinion:

String id = null;
if (myObject instanceof Class1) {
  id = ((Class1) myObject).getId();
} else if (myObject instanceof Class2) {
  id = ((Class2) myObject).getId();
}
if (id == null || id.length() > MAX_LENGTH) {
  throw new Exception();
}

But that's just my take on your concrete example, not a solution for your general problem. You could always use reflection if you know that the method will be there.

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

2 Comments

Yes, I can agree that this is a bit better, but not really a solution.
You could use reflection even if you don't know whether the method will be there; just test whether the method is there.
2

I think that the adapter pattern could be an idea (might not be really this pattern but the idea came from him).

This might be a lot of work just for you example but for more complex work, this is a good approch (personnal opinion of course).

Create an interface an two class that will adapt these function like this :

The originals classes

Class A

public class A {

private int id;

    public A(int id){
        this.id = id;
    }

    public int getId() {
        return id;
    }
}

And the class B

public class B {

    private int id;

    public B(int id){
        this.id = id;
    }

    public int getId() {
        return id;
    }
}

Create an interface like :

public interface Adapter {

    public int getId();
}

And create both adapters :

Adapter A :

public class AdapterA implements Adapter{

    private A a;

    public AdapterA(A a){
        this.a = a;
    }

    public int getId() {
        return a.getId();
    }
}

and Adapter B

public class AdapterB implements Adapter{

    private B b;

    public AdapterB(B b){
        this.b = b;
    }

    public int getId() {
        return b.getId();
    }
}

Now if you need to work with this class, just create an adapter and call the getId of these adapter.

Using your example (Class1 = A and Class2 = B)

  Adapter adapter = new AdapterA(a); //This mean that you need to create the Adapter when you create (receive the class A or B)
  //Adapter adapter = new AdapterB(b);

  if (adapter.getId().length() > MAX_LENGTH) {
     throw new Exception();
  }

If one method have a different name, you just need to update the getter in the specific adapter, the logic behind won't change. So if in B the getId become getIdentity, the only update would be in the adapterB.

Comments

1

Supposing you can't modify at all the generated classes (which seems strange), here is how I would do it with introspection :

Class clazz = myObject.getClass();
Method getId = clazz.getMethod("getId");
Object result = m.invoke(myObject);
if (((String)result).length() > MAX_LENGTH) {
    throw new Exception();
}

Note that this suppose your class has an unique getId() method with no argument. If that's not the case, you'd have to push it a little further and check the methods signature.

Also, I don't think it is a better way than your current sample code. I would maybe use it if the real code had 5+ different classes, or if you needed to do 5+ similar operations on them.

2 Comments

You should probably use myObject.getClass().getMethod("getId") instead of iterating all methods. It will get the method without any parameters.
Yeah, that looks easier indeed. I hadn't used that in a while and followed the reflection Trail, but unless you have to check signatures that looks overkill. I'm editing my answer.
1

As I commented, one way to do this would be to have shared method getId in the interface

public interface ClassInterface
{
    public String getId ();
}

public class Class1 implements ClassInterface{
    public String getId (){
        //class 1 implementation
    }
}

public class Class2 implements ClassInterface{
    public String getId (){
        //class 2 implementation
    }
}

3 Comments

I'm not sure if the questioner can use this aproach, since it seem's he does not have any control over the class definiton?
I don't feel that there is any difference between this and abstract class. As I mentioned Class1 and Class2 are generated and I am not able to add there anything except fields with getters and setters.
@VladimirTikhomirov interface is better in this case because you can have more than one interface. Just saying ;)
1

You can also try to use reflection to get common methods by their signature if you claim them to be the same. It would go something like this:

if (o instanceof Class1 || o instanceof Class2) {
    Class classDescr = o.getClass();
    Method m = classDescr.getMethod("method");
    m.invoke(o);
}

If both classes have the method method with no arguments it would work just fine. Without taking some reflection overhead into account of course.

1 Comment

You need to also check that the method is public, takes no arguments, and returns String.
0

Depending on the abilities of the code generation tool, you could use a common interface. Maybe you could even let the tool create common classes that are used inside the other classes (delegation).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.