2015-06-05 9 views
5

Nehmen wir an, ich habe eine Java-Bibliothek namens Foo erstellt und ich habe eine Klasse in dieser Bibliothek namens Bar. Nehmen wir weiter an, dass ich in der Klasse Bar eine private Methode namens fooBar habe.Java verhindert den Aufruf von privaten oder geschützten Methoden außerhalb der Klasse

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

Man kann mit einem Code dieser Methode ohne Schwierigkeiten laufen in einer Klasse geschrieben, wie folgt aus:

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

Aber lassen Sie uns annehmen, dass wir diese Gewohnheit für fooBar entmutigen möchten. Wie können wir so etwas tun? Sollten wir die Stack-Spur von irgendwoher bekommen und überprüfen, wo sie heißt? Oder sollten wir etwas anderes machen?

+3

Sie haben bereits die Leute davon abgehalten, Ihre Methode aufzurufen, indem Sie sie privat machen. – aioobe

Antwort

6

Sie einen Sicherheitsmanager benötigen ...

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

Ein Sicherheitsmanager ist ein Objekt, das eine Sicherheitspolitik für die Anwendung definiert. Diese Richtlinie gibt Aktionen an, die nicht sicher sind, oder sensitive. Alle Aktionen, die von der Sicherheitsrichtlinie nicht zugelassen werden, verursachen das Auslösen einer SecurityException . Eine Anwendung kann auch den Sicherheitsmanager abfragen, um festzustellen, welche Aktionen zulässig sind.

Es unterstützt die Sperrung setAccessible(), um private und geschützte Methoden über Reflektion aufrufbar zu machen.

+0

Nice one, Phil :) –

3

Ich denke, wenn man extreme sein wollen, können Sie den Stack-Trace wie diese:

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 
    } 
    //... 
} 

ich ein einfaches Szenario zusammengestellt, in der überprüft, ob die second Instanz, die die Klasse ruft die gleiche ist Objekt oder etwas anderes.

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(); 
    } 
} 

Und

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); 
    } 
} 

Dann bekomme ich

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 

Also ich denke, es möglich ist, mit Stack-Trace Element Magie zu überprüfen, aber Sie sollten überprüfen, ob dies tatsächlich funktioniert, ist dies extrem grob und ich habe es gerade vor einer Sekunde zusammengefügt.

+0

Ich habe Ihre Antwort upvoted, wie es funktionieren sollte. Es war jedoch eindeutig die Lösung, an die ich auch dachte. Ich habe meine Frage in der Hoffnung gestellt, dass es etwas Besseres gibt. Phil Andersons Antwort ist dieser Idee jedoch deutlich überlegen. Ich habe das ebenfalls aufgewertet und akzeptiere es. –

+0

In der Tat, aber ich war neugierig, es in Aktion zu sehen, falls man nicht die Befugnis hat, den SecurityManager zu setzen, usw. – EpicPandaForce

+1

Keine Probleme, ich glaube deine Antwort ist eine gute, ich habe dasselbe in meinem vorgeschlagen Frage und es ist schön, eine Antwort zu schreiben, die eine Idee illustriert. Gewiss verdient das Up-Votum, aber wir müssen anerkennen, dass die andere Antwort überlegen ist und dieses ist ein Workaround, wenn die andere Lösung aus einem Grund nicht verfügbar ist. –