views:

109

answers:

5

I have a method that looks like this

 public static <T extends MyClass, X extends AnotherClass> List<T> (Class<T> aParameter, X anotherParameter)

Now if AnotherClass is an abstract class that does NOT Have getId defined, but every single class that extends this interface does. (Don't ask me why it is designed this why, I did not design the abstract class, and I am not allowed to change it).

How can I do something like this

anotherParameter.getId();

I know I have to cast it to the class, but then i have to do an instanceof check for every possible class and then cast it.

So right know i have something like:

if (anotherParameter instanceof SomeClass)
    ((SomeClass)anotherParameter).getId();  //This looks bad.

Is it possible to cast this dynamically?, to whatever anotherParameter is at runtime?.

+1  A: 

I would say no, since due to type erasure, X is actually just Object at runtime. You could try doing something with reflection to test if anotherParameter has getId() and if so, call it.

takteek
+1  A: 

The concept of casting something at runtime doens't really make sense, as you have an instance, and it can tell you what class it is. You will need to use reflection, for example using the Introspector class.

private Integer getId(final X anotherParameter) {
    final BeanInfo beanInfo = Introspector.getBeanInfo(anotherParameter.getClass());
    for (MethodDescriptor methodDescriptor : beanInfo.getMethodDescriptors()) {
        final Method method = methodDescriptor.getMethod();
        if ("getId".equals(method.getName())
                && method.getParameterTypes().length == 0) {
            return (Integer) method.invoke(anotherParameter);
        }
    }
    return null;
}
Jon Freedman
+1  A: 

You could use reflection to invoke the method at runtime if it exists.

try {
    Method m = anotherParameter.getClass().getMethod("getId", null);
    Object result = m.invoke(anotherParameter, null);
}
catch (NoSuchMethodException e) {
   // ... and several other exceptions need to be caught
}
Stephen P
+3  A: 

Can you modify derived classes? If so, you could define an interface for this (syntax maybe wrong):

public interface WithId {
    void getId();
}
...
public class MyDerivedClass1 extends AnotherClass implements WithId {
...
}
...
public class MyDerivedClass2 extends AnotherClass implements WithId {
...
}

and then, inside your method do:

...
if (anotherParameter instanceof WithId) {
 WithId withId = (WithId) anotherParameter;
 withId.getId();
}
...

If you can change your method's signature, maybe you can specify an intersection type:

public static <T extends MyClass, X extends AnotherClass & WithId> List<T> myMethod(Class<T> aParameter, X anotherParameter)

and then you would have getId() available directly inside your method.

gpeche
Note than instead of implementing WithId, you could 1) code an abstract class `AnotherClassWithId` providing `abstract void getId()` 2) make your derived classes extend that, and 3) make your method parameter `anotherParameter` be of type `AnotherClassWithId`. This would be simpler and require less changes to your code, but the basic idea is the same.
gpeche
Thank you worked great.
OscarMk
+1  A: 

As others here have said, reflection is the only practical solution to this, but I would enhance this a little bit by caching the reflection metadata (perhaps a map keyed by the class+methodName), as that part of reflection isn't completely cheap. You can't help the "invoke()" part.

David M. Karr