Как проще всего найти и запустить частный аннотированный метод?

В следующем примере выполняется 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();
         }
      }
   }
}

person Dims    schedule 13.10.2016    source источник


Ответы (3)


Вы должны вызвать setAccessible(true) в своем методе.

См. Javadoc AccessibleObject, который, в свою очередь, является надтипом Method.

В вашем примере:

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

EDIT: Как указал GhostCat в своем ответе, не все вызовы отражения также возвращают частные методы. Похоже, что 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 ();
  }
}
person Alex    schedule 13.10.2016

По сути, вам нужно запустить частный метод из самого класса. Может быть, вам стоит переосмыслить свой код? В противном случае ответ Алекса поможет.

Дополнительная информация об уровнях доступа: https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

И если вы хотите использовать Reflection, вы можете найти еще больше информации о поведении здесь: Java Reflection - влияние setAccessible(true)

person Aks    schedule 13.10.2016
comment
При использовании отражения вы можете получить доступ к закрытым полям и методам классов. Но вы правы, в большинстве случаев стоит задуматься, нужно ли так вызывать приватные методы. - person Alex; 13.10.2016
comment
Да, спасибо за комментарий, сегодня я узнаю что-то новое! Я также добавил ссылку на вопрос о поведении setAccessible. - person Aks; 13.10.2016

На самом деле, может быть две причины, почему ваш код не работает:

  1. Этот частный метод отображается в этом списке; но прежде чем вызывать его, вы должны сделать его доступным (на это у вас уже есть ответ)
  2. В зависимости от реализации того класса Util, который вы используете, возможно, getMethodsListWithAnnotation возвращает список, который просто не включает какие-либо частные методы? (видите ли, механизм отражения java для получения методов private отличается от механизма для методов public. Поэтому меня не удивит, если этот класс util делает то же самое. различие).

И в любом случае: методы private являются private не просто так. Они представляют детали внутренней реализации. Они могут постоянно изменяться.

В этом смысле: ваша реальная проблема заключается в том, что вы думаете, что есть веская причина для вызова закрытого метода с использованием отражения. Вы должны поработать над этим сначала. Если вы действительно считаете, что этот метод должен быть аннотирован; и вызываться через отражение; тогда хотя бы сделайте его общедоступным.

person GhostCat    schedule 13.10.2016