views:

101

answers:

2

Generics bring in a lot of goodness to java but they also mean trouble because of the introduction of bridge methods which mean its not easy to locate a method given a name and target because erasure and bridge methods mean clients actually use the bridge rather than the target.

Return types from methods have been omitted because they are not important for this quetion...

class Super{
}

class Sub extends Super{
}

interface Interface<T extends Super>{
   method( T t ); // erased -> method( Super super );
}

interface Interface2 extends Interface<T extends Sub>{
   method2( T t ); // erased -> method2( Sub sub );
}

class Concrete implements Interface2{
   method( Sub sub );     // erased to method( Super super);
   method2( Sub sub );
}

how can i programmatically determine that Concrete.method(Super) ends up calling Concrete.method(Sub) ? I would like to avoid calculations based on parameterised types and what not as this gets complicated fast...

I have looked at Springs BridgeMethodResolver but its quite complex and does a lot of stuff, surely theres an easier way.. perhaps theres not..

A: 

What came to my mind is:

  • find all possible variants of method arguments, (using .getSuperclass()) with the final one being (Object, Object, ...)
  • loop through all these and find the one that isnt Method.isBridge();

But this is again too much work, and it might not work :). I'd propose doing just:

Method target = new BridgeMethodResolver().findBridgedMethod(bridgedMethod);

No matter what the complexity is there, it's hidden from you.

If you don't want dependecy on spring, just copy-paste the code of that class.

Bozho
Using getSuperClass and then testing for isBridge() isnt really accurate, one should really be using paramterized types etc but thats complex to figure out. BMR seems to do a lot of guessing and what not it seems crazy that one knows a method is a bridge but cant easily ask what its bridging too ...
mP
One cant copy/pastethe Spring BMR because it has a complex spring dependency graph. I would have to also verify if it can handle interface with type variables walking. Your reflection walking stuff would not work one actually needs to grab type varaibles and therir value and then walk up the graph and keep track of these variables and match them up.
mP
@mP - no, that class doesn't have a complex dependency graph. It depends only on two utility classes, which in turn don't depend on anything other than JavaSE
Bozho
A: 

I faced a related problem - I needed to retrieve annotations of the "original" method, and found it very hard to find out the method because of the bridges (which don't have the annotations). I ended up submitting an enhancement request which is accepted. In your case I don't know what you need the method for, so unfortunately, the request (as it is now formulated) may not help you.

Yardena
I am writing an intercepter with ASM, and one of my selectors is by type, so i can ONLY find methods with a return type of X. As per my example above, the super class will never have a X in its signature even though in source it looks like it does because of the type variable. It therefore would be wrong to skip/ignore that method when by looking at the source it appears they should match.
mP
Your example had generic method parameters, not return types, so I am a little confused. If it's return types - they are covariant in Java: a sub-class can override a method that returns a super-type of X to return X. So hypothetically, your selector can accepts all methods that return super-types of X and then you won't have the bridge problem either.
Yardena