我有一个非常简单的AspectJ方面(使用@AspectJ),它只打印出一条日志消息。我的目标是在我的Android应用程序中建议代码。现在,只要我在应用程序源代码中拥有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)
从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;
}
}
}
}
不确定是否重要,但以防万一,我方面的代码:
@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
,它正确包含library-classes.jar
和app-classes.jar
。将-log file
添加到ajc
任务中也会显示文件已正确编织。
有什么想法吗?
重现此问题的最小示例
答案 0 :(得分:4)
该消息暗示方面文件尚未通过aspectj
织布工。编织者将负责添加aspectOf()
方法。虽然您的注释样式方面可以使用javac
进行正常编译,但它们必须完成“#1;}由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
通过在inpath
上加入myaspects.jar,其中的任何方面类都将完成“#1”。作为此编译步骤的一部分,已完成的版本与已编译的应用程序源文件一起放置。请注意,这与使用宽高比路径不同:
ajc <myAppSourceFiles> -aspectpath myaspects.jar
此处方面路径的方面应用于您的代码,但它们仅从那里加载,它们不已完成,因此您不会在编译后获得完成的版本应用程序源文件。
答案 1 :(得分:4)
我遇到了同样的问题,但我使用的是Maven而不是Gradle。
在将方面类应用于目标类之前,首先需要对其进行编织&#39;在一个方面。 一个weaved方面类将添加两个静态方法(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>
希望它有所帮助!
答案 2 :(得分:3)
我使用了Gradle AspectJ plugin并将其应用于注释子项目,如下所示:
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'
}
}