Java 运行AspectJ会导致NoSuchMethodError:Aspect.aspectOf

Java 运行AspectJ会导致NoSuchMethodError:Aspect.aspectOf,java,android,gradle,aspectj,android-gradle-plugin,Java,Android,Gradle,Aspectj,Android Gradle Plugin,我有一个非常简单的AspectJ方面(使用@AspectJ),它只打印一条日志消息。我的目标是在我的android应用程序中为代码提供建议。现在,只要我的应用程序源代码中有aspect类本身,这个aspect就可以很好地工作一旦我将方面移动到另一个模块(java->.jar或android lib->.aar)中,在我的应用程序中运行建议的代码时,我会遇到以下运行时异常: java.lang.NoSuchMethodError: com.xxx.xxx.TraceAspect.aspectOf

我有一个非常简单的AspectJ方面(使用@AspectJ),它只打印一条日志消息。我的目标是在我的android应用程序中为代码提供建议。现在,只要我的应用程序源代码中有aspect类本身,这个aspect就可以很好地工作一旦我将方面移动到另一个模块(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)
javac MyAspect.java
jar -cvMf code.jar MyAspect.class
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
从ajc编译器中,我可以看到ajc编译器选择了我的类并正确地通知它们,所以我真的不知道为什么只要我的源代码中有@AspectJ类,它就可以工作,但一旦我将它移动到jar存档中,它就会停止工作

我用的是gradle。我的应用程序的构建脚本非常简单。我按照指示去做

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

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

我还检查了
javaCompile.classPath
,它正确地包含了
库类.jar
和我的
应用类.jar
。将
-log file
添加到
ajc
任务中也会显示文件已正确编织

有什么想法吗

重现此问题的最小示例


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

Root
 + app (com.android.application)
   - MainActivity (with annotation to be adviced)
 + library (android-library)
   - TraceAspect (aspect definition)
javac MyAspect.java
jar -cvMf code.jar MyAspect.class
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
然后,您需要编织罐子,以“完成”这些方面:

ajc -inpath code.jar -outjar myfinishedcode.jar
或者您可以在初始步骤中使用
ajc
而不是
javac

ajc MyAspect.java
或者,您也可以在将方面应用于其他代码时执行此操作:

ajc <myAppSourceFiles> -inpath myaspects.jar 
在这里,方面路径上的方面应用于您的代码,但它们只是从那里加载的,它们没有完成,因此您无法在编译的应用程序源文件中获得完成的版本。

我使用了一个,并将其应用于注释子项目,如下所示:

Root
 + app (com.android.application)
   - MainActivity (with annotation to be adviced)
 + library (android-library)
   - TraceAspect (aspect definition)
javac MyAspect.java
jar -cvMf code.jar MyAspect.class
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
现在,该应用程序在模拟器中工作,来自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'
     }
 }

我遇到了同样的问题,但我用了Maven而不是Gradle

在将方面类应用于目标类之前,首先需要将其“编织”到方面中。 编织的方面类将添加两个静态方法(aspectOf和hasAspect)

在我的特殊情况下,我没有编织我的方面

可以通过将aspectj maven插件添加到构建部分来完成

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

org.codehaus.mojo
aspectj maven插件
编撰


希望有帮助

我相信我在gradle构建文件中正确地执行了
ajc
(通过
newmain().run(args,handler)
)。将
-日志文件
输出添加到
ajc
显示文件已正确编织。另外,我的代码没有经过编织,那么
@TraceDebug
注释将只是一个简单的方法注释,程序将在运行时忽略它。但在我的例子中,每当我试图执行带注释的方法时,程序就会崩溃。我想帮助AspectJ编译器部分,但从未使用过Gradle,只有Maven。通过在GitHub上发布一个最小的、完全自一致的项目版本(可能只有几个虚拟类),你能让问题重现吗?谢谢!我更新了问题,请检查。抱歉,我无法生成此问题。看起来我需要安装Android ADK incl SDK,我想我已经安装了,尽管这花了很长时间。但不知何故,它没有被找到,或者是错误的版本。通常,Maven构建会正确解析并下载所有依赖项,这在Gradle中有所不同吗?你能不能在没有Android的情况下为我创建一个可复制的构建,只关注普通的Java+AspectJ?好吧,通过大量的尝试和错误(
Android\u build\u TARGET\u SDK\u VERSION
对于我的安装是错误的),我能够编译这个项目。还有一个NPE,因为在应用程序子项目中,我必须将ajc参数更改为
“-log”、“weave.log”、
,因为我的机器上不存在您的本地路径。现在我是否在本地运行项目以重现问题?我现在可以重现问题,但我是一个Gradle noob和Android noob的组合。根据Andy的说法,我可以说,您使用普通Java编译器编译方面,也就是说,它还没有“完成”。然后,您的构建过程最终会将未完成的方面从annotation.jar获取到APK中。我建议您也使用Ajc构建注释子项目,这样就可以了。另一种方法是确保完成的方面类而不是未完成的方面类进入APK。为此,在inpath上获取annotation.jar。哇-我可以确认它是有效的,太棒了!非常感谢所有的调查,我真的很感谢你深入研究了这么多新技术,以便弄清真相。顺便问一下,你是否也知道,为什么我以前的脚本会失败,为什么它会与你的修改一起工作?我已经在不久前的最后一次评论中解释了你原来的问题,安迪的回答解释了你的问题