views:

321

answers:

3

I'm looking for a way to extract the essence of a signature in Java. The reason is that I want to use the signature as a unique key in a Map for my java.lang.reflect.Proxies.

With this code:

public interface MyInterface {
  public int compute(String s);
}

...
public static void main (String... args) throws Exception {
  InvocationHandler handler = ...;
  MyInterface i = (MyInterface) Proxy.newProxyInstance(
      Beans.class.getClassLoader(),
      new Class<?>[] { MyInterface.class },
      handler);

  Method m1 = MyInterface.class.getMethod("compute", String.class);
  Method m2 = i.getClass().getMethod("compute", String.class);
  System.out.printf("%b%f", m1.equals(m2));
}

The result is obviously false.

This code is not the code I'll use, because I need it inside the InvocationHandler, but I'm wondering if regarding the Proxy implementations and the interface, getting method.getName() and method.getParameterTypes() is enough or I should use method.getTypeParameters() and method.getParameterAnnotations() as well?

In short: how to get a method signature that is the same for an interface and its java.lang.reflect.Proxy implementations?

+1  A: 

What about using the result of Method.toGenericString as the key? The string it returns includes all details of the signature, as far as I can tell.

Another thing that might be useful is: Method m2 = i.getClass().getMethod("compute", String.class).getDeclaringClass().getMethod("compute", String.class);. That might result in m1.equals(m2) returning true.

Lachlan
`toGenericString()` (or `toString()`) : no because the method returned in MyInterface.class.getMethod("compute") gives a fully different result as of i.getClass().getMethod("compute")The second solution is not valid as well since the "declaring class" returns the proxy class, not the interface.
Frór
+3  A: 

I think you want the Method passed in the InvocationHandler.

package playtest;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
import static junit.framework.Assert.*;

interface MyInterface {
    void run();
    void about();
    void run(String j);
}


public class TestProxyClass {
    @Test
    public void testDeclaringClass() throws Exception {
     final Map<Method, Runnable> actions = new HashMap<Method, Runnable>();

     actions.put(MyInterface.class.getMethod("run"), new Runnable() {

      @Override
      public void run() {
       System.out.println("run");
      }

     } );
     actions.put(MyInterface.class.getMethod("run", String.class), new Runnable() {

      @Override
      public void run() {
       System.out.println("run string");
      }

     } );
     actions.put(MyInterface.class.getMethod("about"), new Runnable() {

      @Override
      public void run() {
       System.out.println("about");
      }

     } );

     MyInterface face = (MyInterface) Proxy.newProxyInstance(getClass().getClassLoader(), 
       new Class<?>[] { MyInterface.class }, new InvocationHandler() {

        @Override
        public Object invoke(Object proxy, Method method,
          Object[] args) throws Throwable {
         actions.get(method).run();
         return null;
        }

       } );

     face.run();
     face.about();
     face.run("Hello");
    }
}
mlk
It works!But I'm perplex. With your code the method passed to invoke is the one of the MyInterface; with mine, the method passed to invoke is the one of the Proxied class, which is different from the one of MyInterface. Anyway, I have my answer, thanks!
Frór
A: 

Hello,

I just had a bug with code doing this, I took name, genericReturnType and genericParameterTypes, and I had problems when working with proxies because I lost the generic information.

I switched to use name, returnType and parameterTypes and it works fine...

I also considered using declaringClass but I removed it and don't remember exactly how I did this...

pgras
Sorry, this is not helping: I already used this, and it proved not to work properly.
Frór