views:

216

answers:

4

I have something like this going on in my Java program:

void f(Object o) {
    g(o);
}

<T extends MySuperClass & MyInterface> void g(T x) {
    ...;
}

How can I cast o so that this works? There seems to be no way to specify both a base class and an interface in variable declarations without using generics. I don't think generics will work here, because o is being created dynamically using reflection, so its actual class is not known at compile time.

(Yeah, I know this is a weird thing to want to do. But I actually do need functionality from both the superclass and the interface. I guess I could do all of the type checking at runtime with instanceof, but that just seems so Java 1.4...)

A: 

Could it be something like

<T extends MySuperClass implements MyInterface>

I'm just guessing here...

masher
The "<T extends MySuperClass
ljp
ah. I haven't need to really worry about complex generics and reflection before...
masher
+2  A: 

You can create a new inner class within the class containing f() calling g()

static abstract class MyCastingClass extends MySuperClass implements MyInterface {}

Then you can cast:

 g((MyCastingClass)o);

EDIT:

This doesn't appear to work though.

It allows your code to compile, and has no warnings, but at runtime, you'll get a ClassCastException unless your object is actually an instance of MyCastingClass

Stephen Denne
It's a shame that doesn't work. Nice try, though. The more I think about it, the more I think it just isn't possible. Casting and variable declarations are mechanisms that specify dynamic type, and dynamic types aren't as flexible as generic types that are erased at compile time. It does seem like a glaring hole in the implementation of generics that there's no apparent way to fudge this.
ljp
+3  A: 

It seems to be there is no way to invoke a "raw" generic method. But you can create an object of raw type (the following conversion is, obviously, unsafe):

void f(Object o) {
    Caster<?> c = new Caster(); 
    g(c.cast(o)); 
}

class Caster<T extends MySuperClass & MyInterface> {
    public T cast(Object o) {
        return (T) o;
    }
}
axtavt
Great! That works, thanks.
ljp
+1  A: 

You can use reflection to invoke g, similar to the below, but with more checks on picking the correct merhod, and handling exceptions:

Object dest_obj_containing_g = this; // Replace with your object.
Method[] methods = dest_obj_containing_g.getClass().getDeclaredMethods();
for (Method m : methods) {
  if (m.getName().equals("g")) {
    m.invoke(dest_obj_containing_g,o);
    break;
  }
}
Stephen Denne
Absolutely hideous! But it will work. Thanks =)
ljp
Yes, but you've said you're already using reflection. Less hideous is: `dest_obj_containing_g.getClass().getDeclaredMethod("g",MySuperClass.class).invoke(dest_obj_containing_g,o);`
Stephen Denne