运行AspectJ会导致NoSuchMethodError:Aspect.aspectOf

Flo*_*Flo 8 java android aspectj gradle android-gradle-plugin

我有一个非常简单的AspectJ方面(使用@AspectJ),它只打印出一条日志消息.我的目标是在我的Android应用程序中建议代码.现在,只要我在应用程序源代码中拥有aspect类本身,这个方面就可以完美地运行.一旦我将方面移动到另一个模块(java - > .jar或android lib - > .aar),我在应用程序中运行建议代码时会遇到以下运行时异常:

java.lang.NoSuchMethodError: com.xxx.xxx.TraceAspect.aspectOf
Run Code Online (Sandbox Code Playgroud)

基本上我的结构是这样的:

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

从ajc编译器,我可以看到ajc编译器选择了我的类并正确地建议它们,所以我真的不知道为什么它可以工作,只要我在源代码中有@AspectJ类,但是一旦我移动就停止工作它是一个jar存档.

我正在使用gradle.我的应用程序的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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

不确定是否重要,但为了以防万一,我方面的代码:

@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();
  }
}
Run Code Online (Sandbox Code Playgroud)

类路径

我也检查了javaCompile.classPath它,它正确包含library-classes.jar和我的app-classes.jar.添加-log fileajc任务还表明文件已正确编织.

有任何想法吗?

重现此问题的最小示例

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

小智 5

该消息暗示方面文件尚未通过aspectj编织器。编织者将负责添加aspectOf()方法。尽管您的注释样式方面可以很好地编译javac,但它们必须aspectj在某个时候“完成”以引入支持编织的基础结构方法。如果您是在加载时编织,这是在加载方面时完成的,但如果您是在编译时或编译后编织,那么您需要以ajc其他方式将它们放入。如果你有一个这样构建的库:

javac MyAspect.java
jar -cvMf code.jar MyAspect.class
Run Code Online (Sandbox Code Playgroud)

那么你需要编织那个罐子来“完成”这些方面:

ajc -inpath code.jar -outjar myfinishedcode.jar
Run Code Online (Sandbox Code Playgroud)

或者您可以只使用ajc而不是javac用于初始步骤

ajc MyAspect.java
Run Code Online (Sandbox Code Playgroud)

或者您可以在将方面应用于您的其他代码时执行此操作:

ajc <myAppSourceFiles> -inpath myaspects.jar 
Run Code Online (Sandbox Code Playgroud)

通过在 上包含 myaspects.jar,其中的inpath任何方面类都将作为此编译步骤的一部分“完成”,并将完成的版本与已编译的应用程序源文件放在一起。请注意,这与使用方面路径的情况不同:

ajc <myAppSourceFiles> -aspectpath myaspects.jar
Run Code Online (Sandbox Code Playgroud)

这里方面路径上的方面应用于您的代码,但它们仅从那里加载,它们没有完成,因此您不会在编译的应用程序源文件旁边获得完成的版本。


Eug*_*yuk 5

我遇到了同样的问题,但我使用了 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>
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你!


kri*_*aex 3

我使用了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
Run Code Online (Sandbox Code Playgroud)

现在,该应用程序可以在模拟器中运行,并且来自 Android SDK 的 DDMS 显示建议输出按预期显示在控制台上。:-)

调试监控控制台日志

请注意,我已将项目升级到 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'
     }
 }
Run Code Online (Sandbox Code Playgroud)