Reputation: 551
I am doing some research in AOP and use gradle + aspectJ to weave my code. So I did as some demo says, add aspectJtools to top build.gradle.
dependencies {
...
classpath 'org.aspectj:aspectjtools:1.9.5'
}
And in app/build.gradle, add task to weave code:
variants.all { variant ->
JavaCompile javaCompile
if (variant.hasProperty('javaCompileProvider')) {
//android gradle 3.3.0 +
javaCompile = variant.javaCompileProvider.get()
} else {
javaCompile = variant.javaCompile
}
def buildType = variant.buildType.name
javaCompile.doLast {
MessageHandler handler = new MessageHandler(true)
String[] javaArgs = [
"-showWeaveInfo",
"-1.8",
"-inpath", javaCompile.destinationDir.toString(),
"-aspectpath", javaCompile.classpath.asPath,
"-d", javaCompile.destinationDir.toString(),
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)
]
new Main().run(javaArgs, handler)
String[] kotlinArgs = [
"-showWeaveInfo",
"-1.8",
"-inpath", project.buildDir.path + "/tmp/kotlin-classes/" + buildType,
"-aspectpath", javaCompile.classpath.asPath,
"-d", project.buildDir.path + "/tmp/kotlin-classes/" + buildType,
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)
]
new Main().run(kotlinArgs, handler)
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:
case IMessage.INFO:
log.info message.message, message.thrown
break
case IMessage.DEBUG:
log.debug message.message, message.thrown
break
}
}
}
}
Then I add my aspect like:
@Aspect
public class AspectInCommon extends BaseAspect {
@Pointcut("execution(* com.example.cheng.test.MainActivityKt.on**(..))")
public void kotlinMainOn() {
}
@After("kotlinMainOn()")
public void hookKotlinMain(JoinPoint joinPoint) throws Throwable {
log(joinPoint.getSignature().toLongString());
}
...
}
And my MainActivity looks like:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
...
}
}
In this way I indeed wove aspect into my code. And here is some output: It works fine at first time until I click debug bottom again, then all the output are never triggered anymore. Then after few time's testing, I found that it only weave after clean build if one of my file is in kotlin. So I try to change mainActivity and aspect file to java or kotlin. And here is the test results:
MainActivity language Aspect language Weave results
Java Java Weave every time
Java Kotlin Weave after clean build *
Kotlin Java Weave after clean build
Kotlin Kotlin Weave after clean build
*:I put aspect file in subModule, and it crashed in second build after clean build. The error message is:
java.lang.NoSuchMethodError: No static method aspectOf()
I wonder how to make aspect weave kotlin code every time rather than only once after clean build, because most code of my real project is base in kotlin. It's perfect not to simply use a plugin. Many thanks.
Upvotes: 0
Views: 806
Reputation: 67297
I neither use Gradle (rather Maven) nor Kotlin, but my experience with multiple JVM languages or multiple compilation steps is that is makes sense to do each compilation step in a separate module.
This makes the build simpler and more stable. Other advantages are that you have an original, unwoven application module and an aspect-enhanced one. Depending on the situation, you could use the former or the latter in your application, e.g. if you weave debugging or tracing aspects which should not always be used. Last but not least, a separate aspect module makes the aspect library potentially re-usable.
Upvotes: 1