Ejecutar AspectJ causa NoSuchMethodError: Aspect.aspectOf

Tengo un aspecto muy simple de AspectJ (usando @AspectJ) que apenas imprime hacia fuera un mensaje del registro. Mi objetivo es el código de consejos en mi aplicación Android. Ahora, este aspecto funciona perfectamente, siempre y cuando tenga la clase de aspecto en mis aplicaciones código fuente. Una vez que muevo el aspecto en un módulo diferente (ya sea java -> .jar o android lib -> .aar) Tengo la siguiente excepción de tiempo de ejecución al ejecutar el código adviced en mi aplicación:

java.lang.NoSuchMethodError: com.xxx.xxx.TraceAspect.aspectOf 

Básicamente mi estructura es así:

 Root + app (com.android.application) - MainActivity (with annotation to be adviced) + library (android-library) - TraceAspect (aspect definition) 

Desde el compilador ajc, puedo ver que el compilador ajc recoge mis clases y los advierte correctamente, así que realmente no sé por qué funciona, siempre y cuando tenga la clase @AspectJ en mi código fuente, pero deja de funcionar una vez que me muevo A un archivo jar.

Estoy usando gradle. Buildscript para mi aplicación es muy simple. Seguí las instrucciones en http://fernandocejas.com/2014/08/03/aspect-oriented-programming-in-android/

 import com.android.build.gradle.LibraryPlugin import org.aspectj.bridge.IMessage import org.aspectj.bridge.MessageHandler import org.aspectj.tools.ajc.Main buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.12.+' classpath 'org.aspectj:aspectjtools:1.8.1' } } apply plugin: 'com.android.application' repositories { mavenCentral() } dependencies { compile 'org.aspectj:aspectjrt:1.8.1' compile project (':library') } android.applicationVariants.all { variant -> AppPlugin plugin = project.plugins.getPlugin(AppPlugin) JavaCompile javaCompile = variant.javaCompile javaCompile.doLast { String[] args = ["-showWeaveInfo", "-1.5", "-XnoInline", "-inpath", javaCompile.destinationDir.toString(), "-aspectpath", javaCompile.classpath.asPath, "-d", javaCompile.destinationDir.toString(), "-classpath", javaCompile.classpath.asPath, "-bootclasspath", plugin.project.android.bootClasspath.join(File.pathSeparator)] MessageHandler handler = new MessageHandler(true); new Main().run(args, handler) def log = project.logger for (IMessage message : handler.getMessages(null, true)) { switch (message.getKind()) { case IMessage.ABORT: case IMessage.ERROR: case IMessage.FAIL: log.error message.message, message.thrown break; case IMessage.WARNING: log.warn message.message, message.thrown break; case IMessage.INFO: log.info message.message, message.thrown break; case IMessage.DEBUG: log.debug message.message, message.thrown break; } } } } 

No estoy seguro si es importante, pero por si acaso, el código de mi aspecto:

 @Aspect public class TraceAspect { private static final String POINTCUT_METHOD = "execution(@com.xxx.TraceAspect * *(..))"; @Pointcut(POINTCUT_METHOD) public void annotatedMethod() {} @Around("annotatedMethod()") public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Aspect works..."); return joinPoint.proceed(); } } 

Camino de clase

También he comprobado javaCompile.classPath y contiene correctamente tanto la library-classes.jar como mi app-classes.jar . La adición de -log file a las tareas de ajc también muestra que los archivos se tejen correctamente.

¿Algunas ideas?

Ejemplo mínimo para reproducir este problema

Https://github.com/fschoellhammer/test-aspectj

Jugué con un plugin Gradle AspectJ y lo apliqué al subproyecto de anotación como este:

 buildscript { repositories { maven { url "https://maven.eveoh.nl/content/repositories/releases" } } dependencies { classpath "nl.eveoh:gradle-aspectj:1.4" } } project.ext { aspectjVersion = '1.8.4' } apply plugin: 'aspectj' project.convention.plugins.java.sourceCompatibility = org.gradle.api.JavaVersion.VERSION_1_7 project.convention.plugins.java.targetCompatibility = org.gradle.api.JavaVersion.VERSION_1_7 

Ahora la aplicación funciona en el emulador y DDMS del SDK de Android muestra que la salida de asesoramiento está en la consola como se esperaba. :-)

Debug Monitor consola de registro

Tenga en cuenta que he actualizado el proyecto a AspectJ 1.8.4 y Java 7. También he cambiado esta configuración:

 Index: app/build.gradle =================================================================== --- app/build.gradle (revision 9d9c3ce4e0f903b5e7c650f231577c20585e6923) +++ app/build.gradle (revision ) @@ -2,8 +2,7 @@ dependencies { // aspectJ compiler - compile 'org.aspectj:aspectjrt:1.8.1' - + compile 'org.aspectj:aspectjrt:1.8.4' compile (project (':annotation')) } @@ -50,13 +49,13 @@ JavaCompile javaCompile = variant.javaCompile javaCompile.doLast { String[] args = ["-showWeaveInfo", - "-1.5", + "-1.7", "-XnoInline", "-inpath", javaCompile.destinationDir.toString(), "-aspectpath", javaCompile.classpath.asPath, "-d", javaCompile.destinationDir.toString(), "-classpath", javaCompile.classpath.asPath, - //"-log", "/home/flo/workspace/test-aspectj/weave.log", + "-log", "weave.log", "-bootclasspath", plugin.project.android.bootClasspath.join(File.pathSeparator)] MessageHandler handler = new MessageHandler(true); Index: build.gradle =================================================================== --- build.gradle (revision 9d9c3ce4e0f903b5e7c650f231577c20585e6923) +++ build.gradle (revision ) @@ -5,7 +5,7 @@ dependencies { classpath 'com.android.tools.build:gradle:0.12.+' // aspectj - http://fernandocejas.com/2014/08/03/aspect-oriented-programming-in-android/ - classpath 'org.aspectj:aspectjtools:1.8.1' + classpath 'org.aspectj:aspectjtools:1.8.4' } } 

El mensaje implica que el archivo de aspecto no ha pasado por el aspectj tejedor. El tejedor sería responsable de agregar el método aspectOf() . Aunque sus aspectos de estilo de anotación se compilarán bien con javac , deben ser "terminados" por aspectj en algún momento para introducir los métodos de infraestructura que soportan el tejido. Si usted fue el tiempo de carga de tejer esto se hace como los aspectos se cargan, pero si se compila tiempo o post-compilar el tiempo de tejer, entonces usted necesita para obtener a ajc alguna otra manera. Si tiene una biblioteca construida de esta manera:

 javac MyAspect.java jar -cvMf code.jar MyAspect.class 

Entonces usted necesitaría conseguir ese frasco tejido para "completar" los aspectos:

 ajc -inpath code.jar -outjar myfinishedcode.jar 

O simplemente puede usar ajc lugar de javac para el paso inicial

 ajc MyAspect.java 

O usted podría hacerlo en el punto que los aspectos se están aplicando a su otro código:

 ajc <myAppSourceFiles> -inpath myaspects.jar 

Al incluir myaspects.jar en la vía de inpath , cualquier clase de aspecto en la que se habrá "terminado" como parte de este paso de compilación y las versiones terminadas puestas junto a los archivos de origen de la aplicación compilada. Tenga en cuenta que esto es diferente si usó la ruta de aspecto:

 ajc <myAppSourceFiles> -aspectpath myaspects.jar 

Aquí los aspectos de la ruta de aspecto se aplican a su código, pero sólo se cargan desde allí, no se terminan y por lo que no obtendrá las versiones terminadas junto con los archivos de origen de la aplicación compilada.

Me encuentro con el mismo problema, pero he utilizado Maven en lugar de Gradle.

Antes de que se pueda aplicar una clase de aspecto a una clase de destino, primero hay que "tejerla" en un aspecto. Una clase de aspecto tejida tendrá dos métodos estáticos agregados (aspectOf y hasAspect).

En mi caso particular no tejí mis aspectos.

Se puede hacer agregando el aspectoj-maven-plugin a la sección de compilación.

 <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <executions> <execution> <goals> <goal>compile</goal> </goals> </execution> </executions> </plugin> </plugins> 

¡Espero eso ayude!

  • ¿Cómo puedo comprobar si ya existe un valor en una clase de datos Parse Android
  • Implementar Google Analytics para las pantallas de juegos Android LibGDX
  • ¿Cómo mostrar una imagen en el cuerpo del correo electrónico?
  • ¿Cómo descargar múltiples archivos simultáneamente usando intentservice en Android?
  • Eclipse: finalización de JVM. Código de salida = 2
  • Error: NullPointerAccess: La variable "" sólo puede ser null en esta ubicación
  • Extraño resultado de análisis de fecha y hora con SimpleDateFormat
  • ¿Cómo establecer el valor predeterminado en 0 en edittext cuando no se ingresa nada?
  • Formato de fecha recuperado de un servicio
  • Vida útil de las variables estáticas (clase)
  • Redes Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.