2015-04-16 6 views
5

Mam trochę problemów z opracowaniem sposobu cięcia, który będzie działał na ziarnach, które mają określony parametr z adnotacjami. Moim ostatecznym celem jest zweryfikowanie wartości parametru przed jego przetworzeniem, ale na razie wystarczy utworzyć punkt cięcia.Jak napisać punkt cięcia Aspect na podstawie opisanego parametru

Rozważmy następującą adnotacją

@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.PARAMETER }) 
public @interface MyAnnotation {} 

bym wówczas jak zastosować to do wielu metod, takich jak:

public void method1(@MyAnnotation long i) {} 
public void method2(String someThing, @MyAnnotation long i) {} 
public void method3(String someThing, @MyAnnotation long i, byte value) {} 

Więc

  • Nie dbam o których klasa (lub pakiet) metody są w
  • Położenie adnotata Argument ed będzie się różnić.
  • wiem, że odnotowany wartość będą miały zastosowanie tylko do określonego typu

Moja realizacja punktu przekroju musi być coś wzdłuż linii:

@Before(value = "* *(..) && args(verifyMe)") 
public void verifyInvestigationId(long verifyMe) {} 

Dostaję nieco zdezorientowany o czym dokładnie musi być ta wartość i jak powiązać adnotację i jej typ. W tym momencie prawdopodobnie nie warto wymieniać rzeczy, które wypróbowałem!

Aktualizacja: Na podstawie opinii widziałem w http://stackoverflow.com/questions/3565718/pointcut-matching-methods-with-annotated-parameters/3567170#3567170 (i korygowania parę nieporozumienia i dodanie miejsca przeoczyłem) muszę punktu, w którym następujące utwory:

@Before("execution(public * *(.., @full.path.to.MyAnnotation (*), ..))") 
public void beforeMethod(JoinPoint joinPoint) { 
    System.out.println("At least one of the parameters are annotated with @MyAnnotation"); 
} 

To jest prawie to, czego potrzebuję - wszystko, co musisz zrobić, to przekazać wartość adnotacjami argumentu jako parametr metoda. Nie mogę dokładnie opracować składni, aby zmusić Spring do zrobienia tego (połączona odpowiedź tego nie pokazuje).

+0

możliwe duplikat [pointcut odpowiadających metodami dodając opisane parametry] (http://stackoverflow.com/questions/2766844/pointcut-matching-methods-with-annotated-parameters) – sheltem

+0

@sheltem, Dzięki za wskazanie mi, że to. Niestety była to jedna z rzeczy, które próbowałem, ale się nie udało. Logi zawierały błąd: Pointcut nie jest dobrze sformułowany: oczekuje "wzorca nazwy" przy pozycji znaku 56 wykonanie (public * * (.., @ aspects.VerifyMe (*), ..)) – Stormcloud

+0

BTW: są dwa gwiazdki oddzielone spacją po słowie "public" - stackoverflow zinterpretował je jako kursywa! – Stormcloud

Odpowiedz

5

Bardzo podobny do my answer here który sheltem już wskazał, rozwiązanie wygląda następująco (w składni adnotacja stylu tym razem, ponieważ w Spring AOP nie można użyć natywnej składni AspectJ):

Original autora adnotacji:

package annotations; 

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.PARAMETER }) 
public @interface MyAnnotation {} 

Sterownik Zastosowanie:

Używam aplikacji sterownika, aby przetestować moje rozwiązanie AspectJ. Na wiosnę klasa i aspekt muszą być fasolą Spring/komponentami, aby to zadziałało.

package de.scrum_master.app; 

import java.util.ArrayList; 
import java.util.HashSet; 
import java.util.List; 
import java.util.Set; 

import annotations.MyAnnotation; 

public class Application { 
    public void method1(@MyAnnotation int i) {} 
    public void method2(String id, @MyAnnotation float f) {} 
    public void method3(int i, @MyAnnotation List<String> strings, @MyAnnotation String s) {} 
    public void method4(int i, @MyAnnotation Set<Integer> numbers, float f, boolean b) {} 
    public void method5(boolean b, String s, @MyAnnotation String s2, float f, int i) {} 
    public void notIntercepted(boolean b, String s, String s2, float f, int i) {} 

    public static void main(String[] args) { 
     List<String> strings = new ArrayList<String>(); 
     strings.add("foo"); 
     strings.add("bar"); 
     Set<Integer> numbers = new HashSet<Integer>(); 
     numbers.add(11); 
     numbers.add(22); 
     numbers.add(33); 

     Application app = new Application(); 
     app.method1(1); 
     app.method2("foo", 1f); 
     app.method3(1, strings, "foo"); 
     app.method4(1, numbers, 1f, true); 
     app.method5(false, "foo", "bar", 1f, 1); 
     app.notIntercepted(false, "foo", "bar", 1f, 1); 
    } 
} 

proporcji:

package de.scrum_master.aspect; 

import java.lang.annotation.Annotation; 

import org.aspectj.lang.JoinPoint; 
import org.aspectj.lang.SoftException; 
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 
import org.aspectj.lang.reflect.MethodSignature; 

import annotations.MyAnnotation; 

@Aspect 
public class ArgCatcherAspect { 
    @Before("execution(public * *(.., @MyAnnotation (*), ..))") 
    public void interceptMethodsWithAnnotatedParameters(JoinPoint thisJoinPoint) { 
     System.out.println(thisJoinPoint); 
     MethodSignature signature = (MethodSignature) thisJoinPoint.getSignature(); 
     String methodName = signature.getMethod().getName(); 
     Class<?>[] parameterTypes = signature.getMethod().getParameterTypes(); 
     Annotation[][] annotations; 
     try { 
      annotations = thisJoinPoint.getTarget().getClass(). 
       getMethod(methodName, parameterTypes).getParameterAnnotations(); 
     } catch (Exception e) { 
      throw new SoftException(e); 
     } 
     int i = 0; 
     for (Object arg : thisJoinPoint.getArgs()) { 
      for (Annotation annotation : annotations[i]) { 
       if (annotation.annotationType() == MyAnnotation.class) 
        System.out.println(" " + annotation + " -> " + arg); 
        // Verify 'arg' here or do whatever 
      } 
      i++; 
     } 
    } 
} 

konsoli drewna:

execution(void de.scrum_master.app.Application.method1(int)) 
    @annotations.MyAnnotation() -> 1 
execution(void de.scrum_master.app.Application.method2(String, float)) 
    @annotations.MyAnnotation() -> 1.0 
execution(void de.scrum_master.app.Application.method3(int, List, String)) 
    @annotations.MyAnnotation() -> [foo, bar] 
    @annotations.MyAnnotation() -> foo 
execution(void de.scrum_master.app.Application.method4(int, Set, float, boolean)) 
    @annotations.MyAnnotation() -> [33, 22, 11] 
execution(void de.scrum_master.app.Application.method5(boolean, String, String, float, int)) 
    @annotations.MyAnnotation() -> bar 
+0

Bardzo dokładna, dobra odpowiedź. –

0

To, co skończyło się na po błahy temat z nim (import pominięta):

@Aspect 
public class VerifyAspect { 

    @Before("execution(* *(.., @annotations.MyAnnotation (*), ..)) && args(.., verifyMe)") 
    public void verifyInvestigationId(final Object verifyMe) { 
     System.out.println("Aspect verifying: " + verifyMe); 
    } 
} 

Nie potrzeba nic Wiosna specyficzne, jak AspectJ już oferuje parametry, jeśli jest to pożądane.

+0

Miło (i na pewno bliższy niż wszystko, co udało mi się uzyskać!), Ale to ma pewne ograniczenia, że ​​argument przekazany jako "verifyMe" jest zawsze faktycznym argumentem przekazanym do metody cut-point. Czy istnieje sposób, aby powiedzieć coś w stylu "wyślij mi argumenty z podaną adnotacją"? – Stormcloud

+0

Masz rację, to prawdopodobnie nie daje adnotacji parametru w każdym przypadku. Hmm ... wracam do deski kreślarskiej! – sheltem

+0

Chociaż jako rozwiązanie ad hoc, możesz pozwolić AspectJ dać JoinPoint i przejrzeć jego parametry poprzez odbicie, aby znaleźć te adnotacje z adnotacjami. Niezbyt elegancki, ale powinien zadziałać na początek. – sheltem

Powiązane problemy