Kotlin Aspectj不';我不能和科特林一起工作
我想在kotlin中使用aspectj aop,以下是我的代码: annotation.lazy_列表中的我的批注: 科特林:Kotlin Aspectj不';我不能和科特林一起工作,kotlin,aop,aspectj,Kotlin,Aop,Aspectj,我想在kotlin中使用aspectj aop,以下是我的代码: annotation.lazy_列表中的我的批注: 科特林: package anotation @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.FUNCTION) annotation class lazy_list 我的aspectj aop类: @Aspect class ActiveListAop{ @Pointcut("ex
package anotation
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class lazy_list
我的aspectj aop类:
@Aspect
class ActiveListAop{
@Pointcut("execution(@annotation.lazy_list * *(..))")
fun profile() {
}
@Before("profile()")
fun testModeOnly(joinPoint: JoinPoint) {
println("123")
}
}
我的用法:
@lazy_list
fun all():List<T>{
return lazy_obj?.all() as List<T>
}
@lazy\u列表
fun all():列表{
将lazy_obj?.all()作为列表返回
}
调用all()函数时,没有错误,但不会打印“123”,为什么?对于Kotlin中的注释过程,必须启用并使用。如果不通过Gradle或Maven插件添加此功能,Kotlin代码中的注释处理将不会起任何作用 Kotlin插件支持Dagger或DBFlow等注释处理器。为了让他们使用Kotlin类,应用Kotlin-kapt插件 另见:
buildscript {
ext {
kotlinVersion = '1.2.30'
springBootVersion = '2.0.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
}
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'org.springframework.boot'
...
dependencies {
compile('org.springframework.boot:spring-boot-starter-aop')
...
}
插件kotlin spring使所有类都打开以允许AOP
然后,只需声明您的方面如下
@Aspect
@Component
class MyAspect {
...
重要:使用@aspect和@Component注释注释方面类
小菜一碟!:) 值得一提的是,我们在android项目中需要aspectJ编织,但我们真的想转移到kotlin,所以我们必须解决这个问题。因此,这个线程中使用spring或maven的解决方案对我们不起作用。这是android gradle项目的解决方案,但是,这将破坏增量编译,从而降低构建时间和/或最终破坏某些东西。在我重新思考我们的架构并逐步淘汰aspectJ或(希望)android开始支持它之前,这会一直持续下去 在OP的一些答案和注释中有一点混淆,即kapt解决了这个问题,但kapt允许您进行编译时注释处理,而不是编织。也就是说,注释处理器允许您基于注释生成代码,但不允许您将逻辑注入现有代码 这篇文章建立在将aspectJ添加到android的博客之上: 您的kotlin类被编译成字节码,只是被编译到另一个目录中。因此,这个解决方案使用相同的过程来编织java类,但在kotlin类文件上再次运行它 在
应用程序/build.gradle的顶部添加:
buildscript {
ext.aspectjVersion = '1.9.1'
dependencies {
classpath "org.aspectj:aspectjtools:$aspectjVersion"
}
}
在应用程序/build.gradle的底部添加:
android.applicationVariants.all { variant ->
// add the versionName & versionCode to the apk file name
variant.outputs.all { output ->
def newPath = outputFileName.replace(".apk", "-${variant.versionName}.${variant.versionCode}.apk")
outputFileName = new File(outputFileName, newPath)
def fullName = ""
output.name.tokenize('-').eachWithIndex { token, index ->
fullName = fullName + (index == 0 ? token : token.capitalize())
}
JavaCompile javaCompile = variant.javaCompiler
MessageHandler handler = new MessageHandler(true)
javaCompile.doLast {
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)]
String[] kotlinArgs = ["-showWeaveInfo",
"-1.8",
"-inpath", project.buildDir.path + "/tmp/kotlin-classes/" + fullName,
"-aspectpath", javaCompile.classpath.asPath,
"-d", project.buildDir.path + "/tmp/kotlin-classes/" + fullName,
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(
File.pathSeparator)]
new Main().run(javaArgs, handler)
new Main().run(kotlinArgs, 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:
case IMessage.INFO:
log.info message.message, message.thrown
break
case IMessage.DEBUG:
log.debug message.message, message.thrown
break
}
}
}
}
你可以用
所以我想我已经为Android找到了一个很好的(但冗长的)解决方案。在撰写本文时,我正在使用Gradle 6.7、Android插件4.1.0和AspectJ工具1.9.6
问题的要点是:
- Java是通过task
CompiledBugJavaWithJavaC
- Kotlin由任务编译
compiledBugKotlin
- Gradle可以运行其中一个任务,也可以同时运行两个任务,也可以不运行任何任务
compileDebugJavaWithJavac
取决于compileDebugKotlin
- 编织Kotlin通常需要Java类
如果仔细观察这些要点,就会发现不能将编织作为编译Kotlin的一部分,因为此时可能缺少Java类。如果您这样做,您将收到以下警告:
警告:不正确的类路径:C:\Users\user\StudioProjects\myapp\app\build\intermediates\javac\debug\classes
以及错误,例如
错误:无法确定缺少类型myapp.Foo.Bar的修饰符
因此,更好的方法是在编译Java类之前推迟编织。但由于修改文件不是作为编译任务的一部分,因此会丢失增量构建。。。此外,这种延迟的编织非常难以正确执行记住,没有一个编译任务可能实际计划运行
真正的解决方案是将编织包装在一个框架中,这将产生一个带有自己输入和输出的渐变任务。这意味着您将不会污染编译任务的文件,可以说,这些任务以及此任务都是最新的。这需要相当多的代码,但它相当合理
首先,将其放入项目build.gradle.kts
:
buildscript{
依赖关系{
类路径(“org.aspectj:aspectjtools:1.9.6”)
}
}
这是从构建脚本的“内部”运行编织所必需的。如果您想在单独的进程中运行编织,这在Windows上是一个好主意,那么您需要这个jar的路径,您可以通过将以下内容添加到您的应用程序build.gradle.kts
:
val编织:按配置配置。创建
依赖关系{
编织(“org.aspectj:aspectjtools:1.9.6”)
}
最后,将AspectJ运行时放在类路径上(appbuild.gradle.kts
,注意我只需要在调试构建中编织):
依赖项{
调试实现(“org.aspectj:aspectjrt:1.9.6”)
}
现在,这是我的设置。我有一个本地日志库,:cats
,它包含我想要编织的方面。日志语句仅在我的项目中,而不在其他任何地方。另外,我只想在调试版本中运行这些。下面是将猫“编织”到应用程序中的转换(应用程序的build.gradle.kts
):
class-TransformCats:Transform(){
重写fun getName():String=TransformCats::class.simpleName!!
重写fun getInputTypes()=集合(QualifiedContent.DefaultContentType.CLASSES)
//仅在应用程序类中查找注释
//转换将使用这些类并将编织类放入输出目录中
重写fun getScopes()=mutableSetOf(QualifiedContent.Scope.PROJECT)
//…但其他的都在我们班上
//这些将不会被转换所触及
重写fun getReferencedScopes()=可变集合(QualifiedContent.Scope.SUB_项目,
QualifiedContent.Scope.EXTERNAL_库)
override fun isIncremental()=false
//只在de上运行
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "io.freefair.gradle:aspectj-plugin:5.2.1"
}
}
apply plugin: "io.freefair.aspectj.post-compile-weaving"