2015-06-05 13 views
5

Załóżmy, że utworzyłem bibliotekę Java o nazwie Foo i mam klasę wewnątrz tej biblioteki o nazwie Bar. Załóżmy dalej, że w klasie Bar mam prywatną metodę o nazwie fooBar.Java zapobiega wywoływaniu prywatnych lub chronionych metod poza klasą

public class Bar { 
    //... 
    private Object fooBar() { 
     //Do something 
    } 
    //... 
} 

Można uruchomić tę metodę bez żadnych trudności z kodu napisanego w klasie, podobnie jak to:

public static Object runMethod(Object object, String methodName) { 
    Method method = object.getClass().getDeclaredMethod(methodName); 
    method.setAccessible(true); 
    return method.invoke(object); 
} 

Jednak załóżmy, że chcemy, aby zniechęcić ten zwyczaj za fooBar. Jak możemy zrobić coś takiego? Czy powinniśmy pobrać gdzieś ślad stosu i sprawdzić, gdzie został wywołany? Czy powinniśmy zrobić coś innego?

+3

Już zniechęciłeś ludzi do wywołania swojej metody, czyniąc ją prywatną. – aioobe

Odpowiedz

6

Musisz menedżera zabezpieczeń ...

https://docs.oracle.com/javase/tutorial/essential/environment/security.html

Menedżer zabezpieczeń jest obiektem, który definiuje politykę bezpieczeństwa dla aplikacji . Ta polityka określa działania, które są niebezpieczne lub wrażliwe. Wszelkie działania niedozwolone przez zasady zabezpieczeń powodują wyrzucenie wyjątku SecurityException. Aplikacja może również wysłać zapytanie do swojego menedżera bezpieczeństwa , aby dowiedzieć się, jakie działania są dozwolone.

Umożliwia odrzucenie setAccessible(), aby prywatne i chronione metody były wywoływane poprzez odbicie.

+0

Fajna, Phil :) –

3

Myślę, że jeśli chcesz być skrajne, można uzyskać ślad stosu tak:

public class Bar { 
    //... 
    private Object fooBar() { 
     try { 
      throw new CheckIfCalledFromMethodException(); 
     } catch(CheckIfCalledFromMethodException e) { 
      //here you have access to stack trace in your exception 
     } 

     //Do something 
    } 
    //... 
} 

ułożyła prosty scenariusz, w którym sprawdza, czy instancja second które wywołuje klasy jest taka sama obiekt lub coś innego.

public class StackTraceTest { 
    private void execute() { 
     try { 
      throw new Exception(); 
     } catch (Exception e) { 
      /*for(int i = 0; i < e.getStackTrace().length; i++) { 
       StackTraceElement stackTraceElement = e.getStackTrace()[i]; 
       System.out.println(stackTraceElement.getFileName()); 
      } 
      System.out.println(""); 
      e.printStackTrace();*/ 
      if(!e.getStackTrace()[1].getFileName().equals(StackTraceTest.class.getSimpleName() + ".java")) { 
       throw new IllegalAccessError("Illegal Access."); 
      } 
     } 
    } 

    public void executeExternal() { 
     this.execute(); 
    } 
} 

I

public class AccsessorTest { 
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { 
     StackTraceTest stackTraceTest = new StackTraceTest(); 
     stackTraceTest.executeExternal(); 
     System.out.println("Accessed from within other method in class."); 
     System.out.println(""); 
     Class<?> clazz = StackTraceTest.class; 
     Method method = clazz.getDeclaredMethod("execute"); 
     method.setAccessible(true); 
     System.out.println("Accessing through reflection..."); 
     method.invoke(stackTraceTest); 
    } 
} 

Potem dostać

Accessed from within other method in class. 

Reflection test start. 
Accessing through reflection... 
Exception in thread "main" java.lang.reflect.InvocationTargetException 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:483) 
    at stacktracetest.another.AccsessorTest.main(AccsessorTest.java:22) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:483) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 
Caused by: java.lang.IllegalAccessError: Illegal Access. 
    at stacktracetest.StackTraceTest.execute(StackTraceTest.java:18) 
    ... 10 more 

Więc myślę, że to jest możliwe, aby skontaktować się z ślad stosu elementów magii, ale należy sprawdzić, czy to faktycznie działa, to jest bardzo szorstki i właśnie złożyłem to razem przed sekundą.

+0

Przesunąłem twoją odpowiedź, tak jak powinno działać. Jednak było to wyraźnie rozwiązanie, o którym myślałem również. Zadałem moje pytanie w nadziei, że jest coś lepszego. Odpowiedź Phila Andersona jest jednak zdecydowanie lepsza od tego pomysłu. Ja również przegłosowałem tę i akceptuję ją. –

+0

Rzeczywiście, ale byłem ciekawy, aby zobaczyć go w akcji, na wypadek gdyby ktoś nie miał uprawnień do ustawienia menedżera zabezpieczeń itp. – EpicPandaForce

+1

Żadnych problemów, uważam, że twoja odpowiedź jest dobra, sugeruję to samo w moim pytanie i miło jest napisać odpowiedź ilustrującą pomysł. Z pewnością zasługuje na głosowanie w górę, jednak musimy przyznać, że druga odpowiedź jest lepsza, a ta jest rozwiązaniem, gdy inne rozwiązanie nie jest dostępne z jakiegoś powodu. –