Outils pour utilisateurs

Outils du site


lang:java:aspectj

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
lang:java:aspectj [2016/12/14 23:25] – Ajout de "Mélange avec annotation et sans annotation" rootlang:java:aspectj [2020/04/26 22:39] (Version actuelle) – Conversion de <note> vers <WRAP> root
Ligne 1: Ligne 1:
-[[http://www.eclipse.org/aspectj/doc/next/progguide/printable.html|Manuel complet]]{{ :lang:java:aspectj:the_aspectjtm_programming_guide.html.maff |Archive}}+[[http://www.eclipse.org/aspectj/doc/next/progguide/printable.html|The AspectJTM Programming Guide]] {{ :lang:java:aspectj:the_aspectjtm_programming_guide_2020-04-26_10_31_44_pm_.html |Archive du 2003 le 26/04/2020}}
  
-[[https://eclipse.org/aspectj/doc/released/adk15notebook/printable.html#annotations|Complément Java 5]]{{ :lang:java:aspectj:the_aspectjtm_5_development_kit_developer_s_notebook.html.maff |Archive}}+[[https://eclipse.org/aspectj/doc/released/adk15notebook/printable.html|The AspectJTM Development Kit Developer's Notebook]] {{ :lang:java:aspectj:the_aspectjtm_5_development_kit_developer_s_notebook_2020-04-26_10_31_51_pm_.html |Archive du 2005 le 26/04/2020}}
  
 =====Déclaration d'un aspect===== =====Déclaration d'un aspect=====
 +Sans annotation
 <code java> <code java>
 public aspect Log { public aspect Log {
 +}
 +</code>
 +
 +Avec annotation
 +<code java>
 +import org.aspectj.lang.annotation.Aspect;
 +
 +@Aspect
 +public class Log {
 } }
 </code> </code>
  
 =====Déclaration d'un point de coupe===== =====Déclaration d'un point de coupe=====
 +Sans annotation
 <code java> <code java>
 pointcut evaluation(EventHandler h): target(h) && pointcut evaluation(EventHandler h): target(h) &&
   call(public void *.handleEvent());   call(public void *.handleEvent());
 +</code>
 +
 +La dénomination exacte pour trouver le nom d'un méthode est : ''package''.''classe''.''classes internes''.''methode''.
 +
 +
 +Avec annotation
 +<code java>
 +@Pointcut("call(void C.incI(int)) && args(x) && target(c)")
 +private void CoupureIncI(int x, C c) {
 +}
 </code> </code>
  
Ligne 39: Ligne 60:
 La méthode ''call'' est résolue à la compilation alors que la méthode ''execution'' est résolue à l'exécution. Pour que la méthode ''call'' marche, il faut de la classe appelante soit surveillée alors qu'avec la méthode ''execution'', seule la classe appelée doit être surveillée. La méthode ''call'' est résolue à la compilation alors que la méthode ''execution'' est résolue à l'exécution. Pour que la méthode ''call'' marche, il faut de la classe appelante soit surveillée alors qu'avec la méthode ''execution'', seule la classe appelée doit être surveillée.
  
-[[http://perfspy.blogspot.fr/2013/09/differences-between-aspectj-call-and.html|Source]]{{ :lang:java:aspectj:perfspy_differences_between_aspectj_call_and_execute_.html.maff |Archive}}+[[http://perfspy.blogspot.fr/2013/09/differences-between-aspectj-call-and.html|PerfSpy_ Differences between AspectJ call() and execute()]] {{ :lang:java:aspectj:perfspy_differences_between_aspectj_call_and_execute_2020-04-26_10_34_17_pm_.html |Archive du 02/09/2013 le 26/04/2020}}
  
    * ''(public void *.handleEvent())'' : la méthode à surveiller.    * ''(public void *.handleEvent())'' : la méthode à surveiller.
  
 Pour le constructeur, il utiliser la dénomination ''new''. Par exemple : ''C.new()''. Pour le constructeur, il utiliser la dénomination ''new''. Par exemple : ''C.new()''.
 +
 =====Déclaration d'un advice===== =====Déclaration d'un advice=====
 Utilisation d'un point de coupe (advice) : Utilisation d'un point de coupe (advice) :
Ligne 54: Ligne 76:
  
 <code java> <code java>
-around() : call(Display.update()) { if (! Display.disabled()) proceed();}+// Si la fonction update ne renvoie rien. 
 +around() : call(Display.update()) { 
 +  if (! Display.disabled()) 
 +    proceed(); 
 +
 + 
 +// Si la fonction update renvoie quelque chose. 
 +Object around() : call(Display.update()) { 
 +  if (! Display.disabled()) 
 +    return proceed(); 
 +  return null; 
 +}
 </code> </code>
 Ici, le point de coupe est directement directement défini dans l'advice. C'est à ''around'' de bien appeler ''proceed();'' qui permet l'exécution de la méthode ''Display.update()''. Ici, le point de coupe est directement directement défini dans l'advice. C'est à ''around'' de bien appeler ''proceed();'' qui permet l'exécution de la méthode ''Display.update()''.
  
-Exemple sans annotation : 
 <code java> <code java>
 +@Around("setAge(i)")
 +// Mettre void à la place de Object si la méthode setAge ne renvoie rien
 +public Object twiceAsOld(ProceedingJoinPoint thisJoinPoint, int i) {
 +  // En cas de méthode static, pas besoin de joinPoint.getTarget().
 +  return thisJoinPoint.proceed(new Object[]{i*2, joinPoint.getTarget()}); //using Java 5 autoboxing
 +}
 +</code>
 +
 +Exemple sans annotation :
 +<file java Log.aj>
 public aspect Log { public aspect Log {
   pointcut evaluation(EventHandler h): target(h) &&   pointcut evaluation(EventHandler h): target(h) &&
     call(public void *.handleEvent());     call(public void *.handleEvent());
  
-  // Le pointcut et after ont la même signature. Je ne sais pas si c'est absolument +  // Le pointcut et after ont la même signature, sinon, ce n'est pas la peine 
-  // indispensable mais ça a toujours été le cas dans les exemples que j'ai trouvé.+  // de capturer des éléments dans le pointcut pour ne pas s'en servir.
   after(EventHandler h):evaluation(h) {   after(EventHandler h):evaluation(h) {
     System.out.println("Coucou");     System.out.println("Coucou");
   }   }
 } }
-</code>+</file>
  
-<code java>+<file java ProceedAspect.aj>
 public aspect ProceedAspect { public aspect ProceedAspect {
   pointcut setAge(int i): call(* setAge(..)) && args(i);   pointcut setAge(int i): call(* setAge(..)) && args(i);
  
   Object around(int i): setAge(i) {   Object around(int i): setAge(i) {
 +    // Les trois variables thisJoinPoint, thisJoinPointStaticPart et thisEnclosingJoinPointStaticPart
 +    // s'utilisent sans déclaration. Ce sont des mots clés.
     return proceed(i*2);     return proceed(i*2);
   }   }
 } }
-</code>+</file>
  
 Et en version annotation Java 5 : Et en version annotation Java 5 :
-<code java>+<file java Log.java>
 import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.After;
 import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
Ligne 89: Ligne 133:
 @Aspect @Aspect
 public class Log { public class Log {
-  @After("call(public void *.handleEvent()) && target(h)") +  @After("call(public void *.handleEvent())") 
-  public void LogHandleEvent(EventHandler h)+  // Chacun des champs est facultatif. 
 +  public void LogHandleEvent(JoinPoint thisJoinPoint, 
 +    JoinPoint.StaticPart thisJoinPointStaticPart, 
 +    JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart)
   {   {
     System.out.println("Coucou");     System.out.println("Coucou");
   }   }
 } }
-</code>+</file>
  
-<code java>+<file java ProceedAspect.aj>
 @Aspect @Aspect
 public class ProceedAspect { public class ProceedAspect {
Ligne 105: Ligne 152:
  
   @Around("setAge(i)")   @Around("setAge(i)")
 +  // Dans le cas d'un Around, JoinPoint est en fait un ProceedingJoinPoint.
   public Object twiceAsOld(ProceedingJoinPoint thisJoinPoint, int i) {   public Object twiceAsOld(ProceedingJoinPoint thisJoinPoint, int i) {
-    return thisJoinPoint.proceed(new Object[]{i*2}); //using Java 5 autoboxing+    return thisJoinPoint.proceed(new Object[]{i*2});
   }   }
 } }
-</code>+</file>
  
-Séparation du point de coupure et de l'advice, il faut passer par une méthode vide. Pas pratique.+Séparation du point de coupure et de l'advice, il faut passer par une méthode vide. Pas pratique je trouve.
  
 <code java> <code java>
Ligne 132: Ligne 180:
 </code> </code>
  
 +=====Mots clés disponibles dans un advice=====
 +   * ''thisJoinPoint'' : that contains reflective information about the current join point for the advice to use,
 +   * ''thisJoinPointStaticPart'' : identique à ''thisJoinPoint.getStaticPart()''. Si seulement cette information est nécessaire, il est préférable de l'utiliser plutôt que de passer par ''thisJoinPoint'' pour des raisons de performance,
 +   * ''thisEnclosingJoinPointStaticPart'' : This only holds the static part of a join point, but only the enclosing join point.
 +
 +Exemple avec ''ProceedingJoinPoint'' (en annotation donc) :
 +  getArgs - 50 // Ici, un seul argument : un entier.
 +  getKind - method-call
 +  getTarget - test.C@30f39991
 +  getThis - null
 +  getSignature - void test.C.incI(int)
 +  toString - call(void test.C.incI(int))
 +  toLongString - call(void test.C.incI(int))
 +  toShortString - call(C.incI(..))
 +  getSourceLocation - C.java:18
 +
 +Exemple avec ''JoinPoint.StaticPart'' :
 +  getId - 0
 +  getKind - method-call
 +  toLongString - call(void test.C.incI(int))
 +  toShortString - call(C.incI(..))
 +  getClass - class org.aspectj.runtime.reflect.JoinPointImpl$StaticPartImpl
 +  getSignature - void test.C.incI(int)
 +  getSourceLocation - C.java:18
 +
 +Exemple avec ''JoinPoint.EnclosingStaticPart'' :
 +  getId - 1
 +  getKind - method-execution
 +  toLongString - execution(public static void test.C.main(java.lang.String[]))
 +  toShortString - execution(C.main(..))
 +  toString - execution(void test.C.main(String[]))
 +  getSignature - void test.C.main(String[])
 +  getSourceLocation - C.java:16
 =====Accéder aux champs privés===== =====Accéder aux champs privés=====
 Mot clé : ''privileged''. Cela n'existe pas en annotation et ne s'utilise pas en combiné avec l'annotation ''@Aspect''. Mot clé : ''privileged''. Cela n'existe pas en annotation et ne s'utilise pas en combiné avec l'annotation ''@Aspect''.
Ligne 151: Ligne 232:
 C'est niet. C'est niet.
  
-<note warning>Il est interdit de mélanger l'écriture de code avec annotation et sans annotation (cf [[http://stackoverflow.com/questions/25042972/aspectj-and-java8-bad-type-on-operand-stack|Source]]{{ :lang:java:aspectj:java_8_-_aspectj_and_java8_-_bad_type_on_operand_stack_-_stack_overflow.htm.maff |Archive}}). Il n'est donc pas possible d'utiliser la moindre annotation dans une classe nécessitant d'avoir des droits privilégiés.</note>+<WRAP center round alert 60%> 
 +Il est interdit de mélanger l'écriture de code avec annotation et sans annotation. Il n'est donc pas possible d'utiliser la moindre annotation dans une classe nécessitant d'avoir des droits privilégiés. 
 + 
 +<cite>[[https://stackoverflow.com/questions/25042972/aspectj-and-java8-bad-type-on-operand-stack|java 8 - AspectJ and Java8 - bad type on operand stack - Stack Overflow]] {{ :lang:java:aspectj:java_8_-_aspectj_and_java8_-_bad_type_on_operand_stack_-_stack_overflow_2020-04-26_10_36_32_pm_.html |Archive du 30/07/2014 le 26/04/2020}}</cite> 
 +</WRAP>
  
 <file java C.java> <file java C.java>
Ligne 460: Ligne 545:
     if (((C) joinPoint.getTarget()).i + x > MAX)     if (((C) joinPoint.getTarget()).i + x > MAX)
       throw new RuntimeException();       throw new RuntimeException();
-    // En cas de méthode static, pas besion de joinPoint.getTarget().+    // En cas de méthode static, pas besoin de joinPoint.getTarget().
     joinPoint.proceed(new Object[] { x, joinPoint.getTarget() });     joinPoint.proceed(new Object[] { x, joinPoint.getTarget() });
   }   }
Ligne 723: Ligne 808:
 } }
 </file> </file>
-<note>Il n'y a finalement pas de différence entre la méthode avec annotation et sans annotation, hormis que l'ordre d'écriture des méthodes n'est pas la même (et bien sûr l'utilisation de ''ProceedingJoinPoint'' pour une annotation ''around'' et ''JoinPoint'' pour ''before'' et ''after'').</note>+ 
 +<WRAP center round info 60%> 
 +Il n'y a finalement pas de différence entre la méthode avec annotation et sans annotation, hormis que l'ordre d'écriture des méthodes n'est pas la même (et bien sûr l'utilisation de ''ProceedingJoinPoint'' pour une annotation ''around'' et ''JoinPoint'' pour ''before'' et ''after''). 
 +</WRAP> 
 =====Héritage et interface===== =====Héritage et interface=====
 <code java> <code java>
Ligne 756: Ligne 845:
 } }
 </code> </code>
 +
 +=====Aspect à l'exécution=====
 +Pour cela, il faut un JAR contenant l'aspect, un JAR contenant la classe et un programme fusionnant les 2.
 +====La classe ====
 +Créez un ''Java project''.
 +<file java C.java>
 +package classe;
 +
 +public class C {
 +  public int i = 0;
 +
 +  public void incI(int x) {
 +    i = i + x;
 +  }
 +
 +  static public void main(String[] arg) {
 +    for (String string : arg) {
 +      System.out.println(string);
 +    }
 +    C c = new C();
 +    c.incI(50);
 +    c.incI(1000);
 +  }
 +}
 +</file>
 +Puis en console allez dans le dossier ''bin'' et tapez :
 +<code bash>
 +jar cf C.jar classe
 +</code>
 +
 +====L'aspect====
 +Créez un ''AspectJ project''.
 +<file java A.aj>
 +package aspects;
 +
 +import org.aspectj.lang.ProceedingJoinPoint;
 +import org.aspectj.lang.annotation.Around;
 +import org.aspectj.lang.annotation.Aspect;
 +import org.aspectj.lang.annotation.Pointcut;
 +
 +import classe.C;
 +
 +// Les deux implémentations marchent.
 +
 +public aspect A {
 +  static final int MAX = 1000;
 +
 +  before(int x, C c): call(void C.incI(int)) && target(c) && args(x) {
 +    System.out.println("Before");
 +    if (c.i + x > MAX)
 +      throw new RuntimeException();
 +  }
 +}
 +
 +/*
 +@Aspect
 +public class A {
 +  private static final int MAX = 1000;
 +
 +  @Around("execution(void C.incI(int)) && args(x)")
 +  // AutourDeCoupureIncI renvoie le même type que C.incI.
 +  public void AutourDeCoupureIncI(ProceedingJoinPoint joinPoint, int x) throws Throwable {
 +    System.out.println("début");
 +    if (((C) joinPoint.getTarget()).i + x > MAX)
 +      throw new RuntimeException();
 +
 +    joinPoint.proceed(new Object[] { x });
 +    System.out.println("Fin");
 +  }
 +}
 +*/
 +</file>
 +La classe dépendant de C, il ne faut pas oublie d'ajouter le chemin vers le premier projet pour que la classe compile : Menu ''Project|Properties'', catégorie ''Java Build Path'', onglet ''Projects'' puis ''Add'' et cochez la case du projet Java ''classe''.
 +
 +Puis en console allez dans le dossier ''bin'' et tapez :
 +<code bash>
 +jar cf A.jar aspects
 +</code>
 +
 +====La classe exécutrice====
 +Créez un ''AspectJ project''.
 +<file java Main.java>
 +package main;
 +
 +import java.io.IOException;
 +import java.lang.reflect.InvocationTargetException;
 +import java.lang.reflect.Method;
 +import java.net.URL;
 +
 +import org.aspectj.weaver.loadtime.WeavingURLClassLoader;
 +
 +public class Main {
 +  static public void main(String[] arg) throws ClassNotFoundException, NoSuchMethodException,
 +      SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
 +    try (WeavingURLClassLoader weaving = new WeavingURLClassLoader(
 +        new URL[] { new URL("file:///tmp/java/classe/bin/C.jar"), new URL("file:///tmp/java/aspects/bin/A.jar") },
 +        new URL[] { new URL("file:///tmp/java/aspects/bin/A.jar") },
 +        Thread.currentThread().getContextClassLoader())) {
 +      Thread.currentThread().setContextClassLoader(weaving);
 +
 +      Class<?> classC = weaving.loadClass("classe.C");
 +
 +      Method mainMethod = classC.getMethod("main", new Class[] { String[].class });
 +
 +      mainMethod.invoke(null, (Object)new String[] { "Start" });
 +    }
 +  }
 +}
 +</file>
 +
 +Pensez à ajouter le jar ''org.aspectj.weaver'' dans le ''Build Path'', onglet ''Libraries''.
 +
 +====Exécution====
 +  Start
 +  Before
 +  Before
 +  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:498)
 +    at main.Main.main(Main.java:24)
 +  Caused by: java.lang.RuntimeException
 +    at aspects.A.ajc$before$aspects_A$1$ff7f72c0(A.aj:18)
 +    at classe.C.main(C.java:16)
 +    ... 5 more
 +
 +====Commentaires====
 +Il est impératif que le projet ''main'' ne possède pas le projet ''classe'' dans son ''Build Path'', onglet ''Projects''. Sinon la réflexion ne passera pas par l'aspect.
 +
 +[[https://raw.githubusercontent.com/kilim/kilim/master/src/kilim/tools/Kilim.java|Kilim.java]], {{ :lang:java:aspectj:kilim.zip |Archive kilim.zip}}
lang/java/aspectj.1481754329.txt.gz · Dernière modification : 2016/12/14 23:25 de root