2015-06-11 14 views
6

Mam projekt Java6, który jest migrowany do Java8. Użyliśmy aspectj do logowania niektórych działań użytkowników, takich jak kliknięcie przycisku.Aspectj: Pointcut w wyrażeniu lambda

Są więc słuchacze jak ten:

button.addClickListener(new Button.ClickListener() { 
     @Override 
     public void buttonClick(Button.ClickEvent clickEvent) { 
      doSth(); 
     } 
    }); 

Oraz poincut:

@Pointcut("execution(public void Button.ClickListener.buttonClick(Button.ClickEvent))") 
public void buttonClick() {}; 

Ale ponieważ będziemy używać Java8, słuchacze będą tak:

button.addClickListener(clickEvent -> doSth()); 

Czy istnieje w jaki sposób napisać punktcut pointj, aby obsłużył nowych słuchaczy?

+0

Myślę, że twój 'pointcut' powinien nadal działać, ponieważ zmodyfikowałeś' addClickListener', aby używał 'Lambda', a twój' Button.ClickListener.buttonClick' nadal pozostaje taki sam. Czy to też zmieniłeś? –

+0

To zdecydowanie nie działa. Tylko zmodyfikowałem addClickListener, aby użyć lambda. Tak, nadal używa Button.ClickListener.buttonClick, ale funkcja, która powinna zostać wykonana przed pointcut (oznaczona jako: @Before ("buttonClick()") nigdy nie jest wywoływana. Jest wywoływana, gdy używana jest definicja non-lambda – Lete

+0

To implikuje że AspectJ nie jest w stanie łatać metod klasy słuchaczy generowanych przez 'LambdaMetaFactory' w środowisku wykonawczym, ale czy może zmodyfikować' domyślne' metody 'interfejsu', które mogłyby doprowadzić do możliwego rozwiązania ... – Holger

Odpowiedz

2

Domyślam się, że problem polega na tym, że lambdas nie implementuje/nie zastępuje żadnych metod interfejsu z odpowiadającą im nazwą, ale tworzy anonimową metodę. Spójrz na ten przykład:

Dummy klasa przycisk, replikowania części Vaadin musimy tutaj: aplikację

package de.scrum_master.app; 

public class Button { 
    private ClickListener listener; 

    public void addClickListener(ClickListener listener) { 
     this.listener = listener; 
    } 

    public void click() { 
     System.out.println("Clicking button"); 
     listener.buttonClick(new ClickEvent()); 
    } 

    public static class ClickEvent {} 

    public static interface ClickListener { 
     public void buttonClick(ClickEvent clickEvent); 
    } 
} 

Kierowca:

package de.scrum_master.app; 

public class Application { 
    protected static void doSomething() {} 

    public static void main(String[] args) { 
     Button button = new Button(); 
     button.addClickListener(new Button.ClickListener() { 
      @Override 
      public void buttonClick(Button.ClickEvent clickEvent) { 
       doSomething(); 
      } 
     }); 
     button.click(); 

     button = new Button(); 
     button.addClickListener(clickEvent -> doSomething()); 
     button.click(); 
    } 
} 

Jak widać, dwa przycisk tworzone są instancje, jedna z klasycznym anonimowym detektorem klasy, druga z detektorem lambda. Oba przyciski dostać kliknięciu, więc w konsekwencji dziennik konsola wygląda następująco:

Clicking button 
Clicking button 

Aspekt: ​​

package de.scrum_master.aspect; 

import org.aspectj.lang.JoinPoint; 
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 

@Aspect 
public class ButtonClickLogger { 
    @Before("execution(public void *..Button.ClickListener.buttonClick(*..Button.ClickEvent))") 
    public void logButtonClick(JoinPoint thisJoinPoint) { 
     System.out.println("Caught button click: " + thisJoinPoint); 
    } 

    @Before("within(*..Application)") 
    public void logAllInListener(JoinPoint thisJoinPoint) { 
     System.out.println(" " + thisJoinPoint); 
    } 

    @Before("execution(void *..lambda*(*..Button.ClickEvent))") 
    public void logButtonClickLambda(JoinPoint thisJoinPoint) { 
     System.out.println("Caught button click (lambda): " + thisJoinPoint); 
    } 
} 

Pierwsza rada wykorzystuje punkt przekroju podobny do Ciebie. Może przechwytywać jedynie deklaracje klasycznego słuchacza.

Druga rada służy do debugowania i rejestruje wszystkie punkty połączenia w aplikacji sterownika, aby pokazać, co się tutaj dzieje.

Ostatnia, ale nie mniej ważna trzecia rada pokazuje obejście dla przechwytywania słuchaczy bazujących na zasadzie lambda, polegające na znajomości nazewnictwa kompilatorów Java dla lambd uzyskanych z wyjścia debugowania. To niezbyt przyjemne, ale na razie działa. Należy pamiętać, że wersja lambda buttonClick(..) jest publiczna,, więc nie jest to , a nie public void *..lambda*.

wyjścia konsoli z AspectJ:

staticinitialization(de.scrum_master.app.Application.<clinit>) 
    execution(void de.scrum_master.app.Application.main(String[])) 
    call(de.scrum_master.app.Button()) 
    call(de.scrum_master.app.Application.1()) 
    staticinitialization(de.scrum_master.app.Application.1.<clinit>) 
    preinitialization(de.scrum_master.app.Application.1()) 
    initialization(de.scrum_master.app.Application.1()) 
    initialization(de.scrum_master.app.Button.ClickListener()) 
    execution(de.scrum_master.app.Application.1()) 
    call(void de.scrum_master.app.Button.addClickListener(Button.ClickListener)) 
    call(void de.scrum_master.app.Button.click()) 
Clicking button 
Caught button click: execution(void de.scrum_master.app.Application.1.buttonClick(Button.ClickEvent)) 
    execution(void de.scrum_master.app.Application.1.buttonClick(Button.ClickEvent)) 
    call(void de.scrum_master.app.Application.doSomething()) 
    execution(void de.scrum_master.app.Application.doSomething()) 
    call(de.scrum_master.app.Button()) 
    call(void de.scrum_master.app.Button.addClickListener(Button.ClickListener)) 
    call(void de.scrum_master.app.Button.click()) 
Clicking button 
    execution(void de.scrum_master.app.Application.lambda$0(Button.ClickEvent)) 
Caught button click (lambda): execution(void de.scrum_master.app.Application.lambda$0(Button.ClickEvent)) 
    call(void de.scrum_master.app.Application.doSomething()) 
    execution(void de.scrum_master.app.Application.doSomething()) 

Aktualizacja: Istnieje odpowiednia Bugzilla issue teraz AspectJ. Właśnie to stworzyłem. Wskazuje również na niedawną dyskusję na liście mailingowej.

+0

Proszę zwrócić uwagę na moją aktualizację z link Bugzilla – kriegaex

+0

Jeśli ktoś napotka podobny problem, niektóre lambdy również tworzą statyczne metody, których ta odpowiedź obecnie nie śledzi –

+0

Cóż, nie było tu mowy o statycznych metodach w lambdach. i dostarczając przykładowy kod? Możesz utworzyć nowe pytanie opisujące swój problem za pomocą przykładowego kodu i odnośnika do niego stąd. Chciałbym zwrócić się do Ciebie i pomóc, jeśli Mogę. – kriegaex

Powiązane problemy