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 file到ajc任务还表明文件已正确编织.
有任何想法吗?
重现此问题的最小示例
小智 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)
这里方面路径上的方面应用于您的代码,但它们仅从那里加载,它们没有完成,因此您不会在编译的应用程序源文件旁边获得完成的版本。
我遇到了同样的问题,但我使用了 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)
希望能帮助到你!
我使用了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)