【问题标题】:What is the easiest way to find and run private annotated method?查找和运行私有注释方法的最简单方法是什么?
【发布时间】:2016-10-13 13:09:23
【问题描述】:

以下示例仅在公开时运行MyClass#myMethod()。如果它是私有的,它不会运行它。

私下怎么跑?

import org.apache.commons.lang3.reflect.MethodUtils;

import javax.annotation.PostConstruct;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * Created by dims on 13.10.2016.
 */
public class CallPrivateMethodTest {

   @Retention(RUNTIME)
   @Target(METHOD)
   public @interface MyAnnotation {
   }

   public static class MyClass {

      @MyAnnotation
      private void myMethod() {
         System.out.println("myMethod() ran");
      }
   }

   public static void main(String[] args) {

      MyClass myObject = new MyClass();

      List<Method> methods = MethodUtils.getMethodsListWithAnnotation(myObject.getClass(), MyAnnotation.class);


      for(int i=0; i<methods.size(); ++i) {
         try {
            methods.get(i).invoke(myObject);
         } catch (IllegalAccessException e) {
            e.printStackTrace();
         } catch (InvocationTargetException e) {
            e.printStackTrace();
         }
      }
   }
}

【问题讨论】:

    标签: java reflection annotations private-members


    【解决方案1】:

    你必须在你的方法上调用setAccessible(true)

    参见the Javadoc of AccessibleObject,它又是 Method 的超类型。

    在你的例子中:

    methods.get(i).setAccessible(true);
    methods.get(i).invoke(myObject);
    

    编辑: 正如 GhostCat 在他的回答中指出的那样,并非所有反射调用也都返回私有方法。 It seems that MethodUtils#getMethodsListWithAnnotation 实际上并没有返回它们。

    要解决这个问题,您必须自己获取这些方法:

    MyClass myObject = new MyClass ();
    
    Method[] allMethods = myObject.getClass ().getDeclaredMethods ();
    List<Method> annotatedMethods = Arrays.stream (allMethods)
                                          .filter (m -> m.getAnnotation (MyAnnotation.class) != null)
                                          .collect (Collectors.toList ());
    
    for (Method method: annotatedMethods) {
      try {
        method.setAccessible (true);
        method.invoke (myObject);
      } catch (IllegalAccessException e) {
        e.printStackTrace ();
      } catch (InvocationTargetException e) {
        e.printStackTrace ();
      }
    }
    

    【讨论】:

      【解决方案2】:

      基本上,您需要从类本身运行私有方法。也许你应该重新考虑你的代码?否则,亚历克斯的回答会成功。

      访问级别的更多信息:https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

      如果你想使用反射,你可以在这里找到更多关于行为的信息:Java reflection - impact of setAccessible(true)

      【讨论】:

      • 使用反射时,可以访问类的私有字段和方法。但你是对的,在大多数情况下,应该考虑是否有必要以这种方式调用私有方法。
      • 是的,感谢您的评论,我今天学习了新东西!我还添加了一个关于 setAccessible 行为的问题的链接
      【解决方案3】:

      实际上,您的代码不起作用可能有两个原因:

      1. 该私有方法显示在该列表中;但在调用它之前,您必须使其可访问(您已经得到了答案)
      2. 根据您使用的 Util 类的实现,getMethodsListWithAnnotation 可能会返回一个根本不包含任何 私有 方法的列表? (你看,Java 反射中获取 private 方法的机制与 public 方法不同。因此,如果该 util 类是相同的,我不会感到惊讶区别)。

      在任何情况下:private 方法是 private 是有原因的。它们代表内部实现细节。它们可能会随时更改

      从这个意义上说:您真正的问题是您认为使用反射调用私有方法是有正当理由的。你应该首先工作。如果你真的认为该方法应该注解;并通过反射被调用;然后至少让它公开

      【讨论】:

        猜你喜欢
        • 2011-05-09
        • 1970-01-01
        • 1970-01-01
        • 2017-04-17
        • 1970-01-01
        • 1970-01-01
        • 2022-07-07
        • 1970-01-01
        • 2018-04-24
        相关资源
        最近更新 更多