Бинарное плетение AspectJ с плагином Jcabi Maven не работает для кода Kotlin - PullRequest
0 голосов
/ 04 июля 2019

Я пытаюсь запустить небольшую аннотацию над функцией, которая будет регистрировать до и после выполнения метода.

Что я сделал: (все классы находятся под src/main/kotlin)

Класс аннотации

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

Класс аспекта

import org.aspectj.lang.JoinPoint
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect


@Aspect
abstract class Aspect {

    @Around("@annotation(LogMe) && execution(* *(..))")
    fun logMe(joinPoint: ProceedingJoinPoint): Any {
        beforeExecution(joinPoint)
        afterExecution(joinPoint)

        return joinPoint.proceed()
    }

    private fun beforeExecution(joinPoint: JoinPoint) {
        println("[${joinPoint.signature.name} has started its execution]")
    }

    private fun afterExecution(joinPoint: JoinPoint) {
        println("[${joinPoint.signature.name} has ended its execution]")
    }
}

Класс Foo с аннотированным методом

class Foo {

    @LogMe
    fun yourMethodAround() {
        println("Executing foo.yourMethodAround()")
    }
}

основной файл

fun main(args: Array<String>) {
    val foo = Foo()
    foo.yourMethodAround()
}

my POM.xml (урезанная версия)

...
    <dependencies>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib-jdk8</artifactId>
            <version>1.3.40</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-reflect</artifactId>
            <version>1.3.40</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.4</version>
        </dependency>

        <!-- TEST -->
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test</artifactId>
            <version>1.3.40</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test-junit</artifactId>
            <version>1.3.40</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>src/main/kotlin</sourceDirectory>
        <testSourceDirectory>src/test/kotlin</testSourceDirectory>
        <plugins>
            <plugin>
                <artifactId>kotlin-maven-plugin</artifactId>
                <configuration>
                    <jvmTarget>1.8</jvmTarget>
                </configuration>
                <groupId>org.jetbrains.kotlin</groupId>
                <version>1.3.40</version>
                <executions>
                    <execution>
                        <id>kapt</id>
                        <goals>
                            <goal>kapt</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>compile</id>
                        <phase>compile</phase>
                        <goals> <goal>compile</goal> </goals>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <phase>test-compile</phase>
                        <goals> <goal>test-compile</goal> </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>com.jcabi</groupId>
                <artifactId>jcabi-maven-plugin</artifactId>
                <version>0.14.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>ajc</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>MainKt</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
...

Когда я в основном запускаю этот main, я получаю println, что он входит в мой метод класса Foo:

Executing foo.yourMethodAround()

Но я не получаю до и после выполнения то, что ожидал от класса Aspect.

Кто-нибудь из вас когда-либо сталкивался с этой проблемой раньше?Это беспокоит меня, потому что я не могу понять, что здесь происходит.

1 Ответ

1 голос
/ 05 июля 2019

Отказ от ответственности:

  • Я никогда раньше не использовал плагин Jcabi, обычно я всегда использую плагин AspectJ Maven, также для бинарного плетения.
  • Я никогда раньше не использовал язык Kotlin, обычно я использую Java или Groovy.

Теперь некоторые вещи не в порядке в вашем аспекте:

  • Это не должно быть abstract, в противном случае ни один экземпляр не может быть создан.
  • Для void методов он должен иметь возможность возвращать null, поэтому тип возвращаемого значения Kotlin должен быть Any?
  • Вы должны proceed() между сообщениями журнала до и после, в противном случае вывод журнала будет неправильным.
  • Предполагая, что ваши классы, особенно класс аннотаций, не находятся в пакете по умолчанию, но имеют фактическое имя пакета, вам необходимо использовать полное имя класса в вашем pointcut, например, @annotation(de.scrum_master.app.LogMe)
  • Использование имени класса аспекта Aspect, то есть то же имя, что и у аннотации @Aspect, только в другом пакете, выглядит некрасиво. Вы должны переименовать его.

Для меня это прекрасно работает:

package de.scrum_master.aspect

import org.aspectj.lang.JoinPoint
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect

@Aspect
class LogAspect {
  @Around("@annotation(de.scrum_master.app.LogMe) && execution(* *(..))")
  fun logMe(joinPoint: ProceedingJoinPoint): Any? {
    beforeExecution(joinPoint)
    val result = joinPoint.proceed()
    afterExecution(joinPoint)
    return result
  }

  private fun beforeExecution(joinPoint: JoinPoint) {
    println("[${joinPoint.signature.name} has started its execution]")
  }

  private fun afterExecution(joinPoint: JoinPoint) {
    println("[${joinPoint.signature.name} has ended its execution]")
  }
}

Кроме того, возможно, вам также следует настроить плагин Jcabi на уровень языка Java 8. Он работает здесь без него, но, возможно, лучше в зависимости от того, какие языковые функции вы используете:

<configuration>
  <source>1.8</source>
  <target>1.8</target>
</configuration>

Моя консоль после mvn clean verify выглядит так:

$ java -jar target/so-aj-kotlin-56890630-1.0-SNAPSHOT.jar
[yourMethodAround has started its execution]
Executing foo.yourMethodAround()
[yourMethodAround has ended its execution]

Моя IDE IntelliJ IDEA не совсем подходит для бинарного плетения, потому что не знает Jcabi, только AspectJ Maven. Поэтому я просто настроил проект для делегирования компиляции в Maven:

Delegate IDEA build to Maven

Тогда вывод журнала такой же, когда приложение запускается напрямую из IDEA.

...