Запуск AspectJ вызывает NoSuchMethodError: Aspect.aspectOf

У меня очень простой аспект AspectJ (с использованием @AspectJ), который просто распечатывает сообщение журнала. Моя цель – указать код в приложении для Android. Теперь эти аспекты работают отлично, если у меня есть класс аспект в исходном коде приложений. Как только я переместил этот аспект в другой модуль (либо java -> .jar, либо android lib -> .aar), я получаю следующее исключение во время выполнения при запуске кода в моем приложении:

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

В основном моя структура выглядит так:

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

Из компилятора ajc я вижу, что компилятор ajc подбирает мои классы и правильно их излагает, поэтому я действительно не знаю, почему он работает, пока у меня есть класс @AspectJ в исходном коде, но перестает работать, как только я перемещаюсь Это в архив банку.

Я использую град. Buildscript для моего приложения очень прост. Я выполнил инструкции в 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; } } } } 

Не уверен, что важно, но на всякий случай, код моего аспекта:

 @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(); } } 

Classpath

Я также проверил javaCompile.classPath и он правильно содержит как library-classes.jar и мой app-classes.jar . Добавление -log file ajc задачи ajc также показывает, что файлы правильно сотканы.

Есть идеи?

Минимальный пример для воспроизведения этой проблемы

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

Solutions Collecting From Web of "Запуск AspectJ вызывает NoSuchMethodError: Aspect.aspectOf"

Я играл с плагином Gradle AspectJ и применял его к подпроекту аннотации следующим образом:

 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 

Теперь приложение работает в эмуляторе, а DDMS из Android SDK показывает, что вывод рекомендаций находится на консоли, как ожидалось. :-)

Отладка журнала консоли мониторинга

Обратите внимание, что я обновил проект до AspectJ 1.8.4 и Java 7. Я также изменил эти настройки:

 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' } } 

Сообщение подразумевает, что аспектный файл не прошел через aspectj . Ткач будет отвечать за добавление aspectOf() . Хотя ваши аспекты стиля аннотации будут компилироваться с помощью javac , они должны быть «завершены» по aspectj в какой-то момент, чтобы представить методы инфраструктуры, которые поддерживают ткачество. Если вы занимались загрузкой во времени, это делается по мере того, как эти аспекты загружаются, но если вы используете время компиляции или время компиляции, тогда вам нужно сделать их ajc другим способом. Если у вас есть библиотека, построенная следующим образом:

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

То вам нужно будет собрать эту банку, чтобы «заполнить» аспекты:

 ajc -inpath code.jar -outjar myfinishedcode.jar 

Или вы можете просто использовать ajc вместо javac для начального шага

 ajc MyAspect.java 

Или вы можете сделать это в тот момент, когда аспекты применяются к вашему другому коду:

 ajc <myAppSourceFiles> -inpath myaspects.jar 

Включив myaspects.jar в inpath , любые классы аспектов там будут «завершены» как часть этого этапа компиляции, а готовые версии будут размещены рядом с вашими скомпилированными исходными файлами приложений. Обратите внимание, что это отличается от того, если вы использовали путь аспект:

 ajc <myAppSourceFiles> -aspectpath myaspects.jar 

Здесь аспекты на пути к аспекту применяются к вашему коду, но они только загружаются оттуда, они не завершены, и поэтому вы не получите готовые версии вместе с вашими исходными файлами скомпилированных приложений.

Я столкнулся с той же проблемой, но использовал Maven вместо Gradle.

Прежде чем класс аспект может быть применен к целевому классу, сначала его нужно «сплести» в один аспект. Сжатый аспектный класс будет содержать два статических метода (aspectOf и hasAspect).

В моем конкретном случае я не сплел свои аспекты.

Это можно сделать, добавив aspectj-maven-plugin в раздел сборки.

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

Надеюсь, поможет!