2017-08-16 1 views
3

suche ich AspectJ und seine zahlreichen Verwendungen und mixins entdeckt haben.Wie greife ich mit AspectJ auf private Felder zu?

Ich kann viele Beispiele finden unter Verwendung reiner AspectJ.aj Aspekte, aber ich brauche nur @AspectJ Annotationen zu verwenden.

Was ich versuche zu erreichen, ist die folgende: -

Ich habe eine Klasse, die ich nicht ändern kann, es verfügt über eine private Klassenvariable, die ich brauche, um abzufragen, nach einer bestimmten Klasse Methode Ausführung abgeschlossen hat. Diese Klasse verfügt nicht über Getter- oder Setter-Methoden, die dieser privaten Klassenvariablen zugeordnet sind.

public final class CannotAmend { 

    private Uri privateUri; 

    public final void methodOne(){} 

    public final void methodTwo(){} 

    public final void methodThree(){ 

     privateUri = "something"; 

    } 
} 

Ich benötige einen Aspekt/mixin die @AftermethodThree() und erlauben erfassen kann mich den Wert in privateUri gesetzt zu sehen.

Ist das möglich?

Mit @AspectJ Anmerkungen?

Wo kann ich entdecken Dokumentation/tutorial/Beispiele dafür, wie dies zu erreichen?

+0

Es ist schade, dass man nicht '.aj' Syntax verwenden kann, als dies mit einem privilegierten Aspekte ziemlich einfach sein würde. –

Antwort

2

In einem Aspekt können Sie den privaten Bereich Zugriff auf die Reflection-API verwenden.

In dem Aspekt müssen Sie zwei Dinge:

  • A pointcut Methoden zu definieren, auf dem der Aspekt entspricht.
  • Und eine Methode, die mit @After annotiert ist, die Logik enthält, die ausgeführt wird, nachdem eine Methode, die von der Pointcut übereinstimmt, zurückgegeben wird.

@Aspect 
public class MyAspect { 

    @Pointcut("execution(* CannotAmend.methodThree(..))") 
    public void methodThreePointcut(){ 
    } 

    @After("methodThreePointcut()") 
    public void afterMethod(JoinPoint joinPoint) throws NoSuchFieldException, IllegalAccessException { 
     Object instance = joinPoint.getThis(); 

     Field privateUriField = instance.getClass().getDeclaredField("privateUri"); 
     privateUriField.setAccessible(true); 

     String privateUri = (String) privateUriField.get(instance); 
     System.out.println(privateUri); // prints "something" 
    } 
} 

Auf einer Seite zur Kenntnis, String-Konstanten mit einem privaten Feld zuzugreifen, ist keine saubere Lösung. Wenn sich in der Zukunft der Name der Variablen ändert oder wenn sie entfernt wird, wird der Aspekt unterbrochen.

+0

Vielen Dank, das mir erlaubt den privaten Bereich für den Zugriff (scheint „privateUriField.setAccessible (true);“ ist die Trick). Ich stimme zu, dass dies eine "spröde" Lösung ist, aber wenn dies der "einzige Weg" ist, kann ich nicht sehen, wie ich es zukunftssicher machen kann. Welche Alternativen habe ich? (Wenn überhaupt??) – Hector

1

Nicht mit Mixins, aber Sie können @Around Beratung verwenden, um JoinPoint zu erhalten und Feld durch Reflexion zu erhalten. Zum Beispiel:

@Around("execution(* *.methodThree())") 
public Object getValue(ProceedingJoinPoint pjp) throws Throwable { 
    try { 
     return pjp.proceed(); 
    } finally { 
     System.out.println(pjp.getThis().getClass().getDeclaredField("privateUri").get(pjp.getThis())); 
    } 
} 
+0

Ihre Lösung ist sehr nah, aber es erlaubt mir nicht Zugang zu einem privaten Bereich. Ich brauchte die privateUriField.setAccessible (true); um das zu machen – Hector

+0

@Hector In meinem Test funktionierte es ohne 'privateUriField.setAccessible (true)', aber ich denke, es hängt davon ab, welche Art von Byte-Code von 'ajc' erzeugt wird. Als eine andere Lösung, die Sie einige Instrumentierung Frameworks verwenden können (ByteBuddy zum Beispiel) und ursprüngliche Klasse umwandeln, bevor das Laden von Klassen in Runtime –

Verwandte Themen