How do I find the Java interface whose method is i

2019-07-22 00:19发布

I need quite the opposite of what most people want to juggle with: I have a StackTraceElement with className and methodName. As the method belongs to an interface given class implements, I need a way I can ask the method which interface it originates in.

I can invoke Class.forName(className) and can also invoke clazz.getMethod(methodName), however method.getDeclaringClass() returns with the mentioned class' name instead of its original interface'. I don't want to iterate through all the class' interfaces to find that particular method, that would practically nullify the performance.

--

Basically it is a legacy broadcast mechanism. A broadcaster class contains a hashmap, where the keys are interfaces, and the values are lists with the implementing classes. The broadcaster implements the same interface so that each method retrieves the implementing classes from the hashmap, iterates through them and invokes the same method on each implementing class.

--

Sorry for adding it here, but it's a bit too long to add it inside a comment:

My solution was similar to what Andreas is referring to:

StackTraceElement invocationContext = Thread.currentThread().getStackTrace()[2];
Class<T> ifaceClass = null;
Method methodToInvoke = null;
for (Class iface : Class.forName(invocationContext.getClassName()).getInterfaces()) {
  try {
    methodToInvoke = iface.getMethod(invocationContext.getMethodName(), paramTypes);
    ifaceClass = iface;
    continue;
  } catch (NoSuchMethodException e) {
    System.err.println("Something got messed up.");
  }
}

Using an invocationContext like structure enables to make an interceptor, so the transmitter can only contain annotated methods with empty implementation bodies.

3条回答
Emotional °昔
2楼-- · 2019-07-22 00:51

I have a StackTraceElement with className and methodName.
I need a way I can ask the method which interface it originates in
I don't want to iterate through all the class' interfaces to find that particular method, that would practically nullify the performance.

I would first check whether iterating through all the class interfaces is really performance critical in your usecase. Usually, when you have a stack trace element, you are already in an exceptional state where performance might not be that critical. You could then use Class.getInterfaces() to traverse the interfaces and query the declared methods for each interface, for example like this:

class MethodQuery {
   private Set<Class<?>> result = new HashSet<>();
   private String theMethodName;

   private void traverse(Class<?> cls) {
      for (Class<?> c : cls.getInterfaces()) {
         for (Method m : c.getDeclaredMethods()) {
            if (theMethodName.equals(m.getName())) {
               result.add(c);
            }
         }

         traverse(c);
      }
   }

   public Set<Class<?>> getInterfacesForMethod(Class<?> cls, String methodName) {
      result.clear();
      theMethodName = methodName;
      traverse(cls);
      return result;
   }
}

You can then query which interface a method declares like this:

MethodQuery methodQuery = new MethodQuery();
Set<Class<?>> result = 
    methodQuery.getInterfacesForMethod(java.util.Vector.class, "addAll");
System.out.println(result);

Result:

[interface java.util.Collection, interface java.util.List]
查看更多
相关推荐>>
3楼-- · 2019-07-22 00:56

I can't imagine why you would need this in a performance sensitive situation but you could cache the results of your search. Note: the same method might implement a method from many interfaces.

查看更多
趁早两清
4楼-- · 2019-07-22 00:58

I don't want to iterate through all the class' interfaces to find that particular method, that would practically nullify the performance.

I don't think there are any alternatives.

(But to echo what Peter Lawrey says, caching would help ... and reflection in general should be avoided if performance matters.)

Also note:

  • A given method might not be declared in any interface.
  • A given method night be declared in more than one interface, or in an interface that is inherited via multiple paths.

Your scheme has to take account of these things if it is to be truly general.


It is guaranteed that one method belongs only to one interface.

Even so ...

查看更多
登录 后发表回答