web-dev-qa-db-ja.com

Aspectjはkotlinでは機能しません

kotlinでaspectjaopを使用したいのですが、コードは次のとおりです。

annotation.lazy_listの私の注釈:

Kotlin:

 package anotation

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class lazy_list

私のアスペクト指向クラス:

@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>
    }

all()関数を呼び出すと、エラーは発生しませんが、「123」が出力されないのはなぜですか?

11
junk

Kotlinでの注釈プロセスでは、 [〜#〜] kapt [〜#〜] を有効にして使用する必要があります。これがGradleまたはMavenプラグインを介して追加されない限り、Kotlinコードでの注釈処理には何も機能しません。

Kotlinプラグインは、DaggerやDBFlowなどの注釈プロセッサをサポートしています。それらがKotlinクラスで動作するようにするには、kotlin-kaptプラグインを適用します。

参照:

5
Jayson Minard

spring + kotlin + AOPの動作いいですね。 http://start.spring.io/ にアクセスして、AOPをサポートするプロジェクトを生成すると、ビルドの一部が表示されます。 gradle ここ...

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 は、すべてのクラスをopenにしてAOPを許可します

次に、次のようにアスペクトを宣言します

@Aspect
@Component
class MyAspect {
...

重要:アスペクトクラスに @ Aspect および @ Component アノテーションを付けます

ケーキ! :)

3
SaveTheCode

その価値のために、AndroidプロジェクトでaspectJウィービングが必要でしたが、本当にkotlinに移行したかったので、この問題を解決する必要がありました。したがって、springまたはmavenを使用したこのスレッドのソリューションは解決しませんでした。これはAndroid gradleプロジェクトの解決策ですが、これによりインクリメンタルコンパイルが中断されるため、ビルド時間が遅くなったり、最終的に何かが中断したりします。 -私たちのアーキテクチャを考えて、aspectJを段階的に廃止するか、(うまくいけば)Androidがサポートを開始します。

Kaptがこれを解決するOPへの回答とコメントのいくつかには混乱がありますが、kaptを使用すると、ウィービングではなく、コンパイル時の注釈処理を実行できます。つまり、注釈プロセッサを使用すると、注釈に基づいてコードを生成できますが、既存のコードにロジックを挿入することはできません。

これは、AndroidへのaspectJの追加に関するこのブログの上に構築されています: https://fernandocejas.com/2014/08/03/aspect-directiond-programming-in-Android

Kotlinクラスは、別のディレクトリにあるバイトコードにコンパイルされます。したがって、このソリューションは同じプロセスを使用してJavaクラスを織りますが、kotlinクラスファイルで再度実行します

App/build.gradleの上部に追加:

buildscript {
    ext.aspectjVersion = '1.9.1'
    dependencies {
        classpath "org.aspectj:aspectjtools:$aspectjVersion"
    }
}

App /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
            }
        }
    }
}
2
bsautner

@RobbyCornelissenの答えを確認してください ここ 。私はそれがうまくいくことを発見しました、そして彼に感謝します。

1
Jacob Wu