views:

86

answers:

2

Suppose you have a generic interface and an implementation:

public interface MyInterface<T> {

  void foo(T param);
}

public class MyImplementation<T> implements MyInterface<T> {

  void foo(T param) {

  }
}

These two types are framework types I provide. In the next step I want allow users to extend that interface as well as redeclare foo(T param) to maybe equip it with further annotations.

public interface MyExtendedInterface extends MyInterface<Bar> {

  @Override
  void foo(Bar param);

  // Further declared methods
}

I create an AOP proxy for the extended interface and intercept especially the calls to furtherly declared methods. As foo(…) is now redeclared in MyExtendedInterface I cannot execute it by simply invoking MethodInvocation.proceed() as the instance of MyImplementation only implements MyInterface.foo(…) and not MyExtendedInterface.foo(…).

So is there a way to get access to the method that declared a method initially? Regarding this example is there a way to find out that foo(Bar param) was declared in MyInterface originally and get access to the accoriding Method instance?

I already tried to scan base class methods to match by name and parameter types but that doesn't work out as generics pop in and MyImplementation.getMethod("foo", Bar.class) obviously throws a NoSuchMethodException. I already know that MyExtendedInterface types MyInterface to Bar. So If I could create some kind of "typed view" on MyImplementation my math algorithm could work out actually.

Additional info:

I create the proxy for the MyExtendedInterface as follows:

ProxyFactory factory = new ProxyFactory();
factory.setTarget(new MyImplementation());
factory.setInterfaces(new Class[] { MyExtendedInterface.class });
factory.addInterceptor(new MyInterceptor(MyExtendedInterface.class));

The interceptor pretty much scans the methods and executes JPA queries for all methods declared in MyExtendedInterface but routes all method invocations of methods declared in MyInterface to the proxy target. This works as long as methods from MyInterface are not redeclared as the target then doesn't implement it anymore.

public class MyInterceptor implements MethodInterceptor {

  public Object invoke(final MethodInvocation invocation)
            throws Throwable {

    // handling of query methods
    // else

    invocation.proceed();
    // ^^ works if not redeclared but not if
  }
}

So what I would like to do instead of invocation.proceed() is detect the method that originally declared the one being invoked and invoke that on the target manually.

A: 

The whole scenario seems strange. You can't apply AOP declared on MyExtendedInterface to MyImplementation, because it does not implement it.

Second, I don't understand why it matters which interface defines a method, since it is the implementation that the method is invoked on.

Apart from that, you can get all the methods declared by a certain class/interface by getDeclaredMethods(). Then you can iterate on them and find something that matches your criteria (name)

Bozho
I can. I create the proxy programmatically and add an simple interceptor that intercepts *every* method call. Within this interceptor I decide where to route the actual method call to.`getDeclaredMethods()` is an option but I have to make sure the redeclared method actually overrides one from `MyInterface. One could actually also declare a `foo(Foobar param)` which wouldn't override the actual method then. So it seems there's no way to find out whether a method overrides another method esp. with generics involved.
Oliver Gierke
could you provide the code of the interceptor. I can't quite understand your scenario.
Bozho
Added proxy creation code and interceptor to the original question.
Oliver Gierke
A: 

Okay, here's the solution I came up with: As I know the base class and it generics structure (what T means in this case) as well as MyExtendedInterface types MyInterface to Bar I can scan the base implementation for possible matches as follows (pseudocode):

for all methods {

   skip those with non matching name and parameters length;

   for all generic parametertypes {

     if typename = T then concrete type has to be Bar
     ...
   }
}

I don't need a generic solution in this case so that seems to work.

Oliver Gierke