Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way in Kotlin to weave in code before/after/around functions like there is with AspectJ in Java?

Tags:

kotlin

aspectj

I have tried to use AspectJ to weave in aspects around Kotlin functions, but with no success. Maybe I'm just configuring something incorrectly, or maybe AspectJ does not support this.

Does anyone know if this is possible using e.g maven and Eclipse (or IntelliJ)? Or care to explain why it is not possible?

like image 956
User0 Avatar asked Jul 02 '16 19:07

User0


2 Answers

In addition to the other comments/answers I think it is worth pointing out that you can "weave" code before/after/around function code by using inline functions. e.g.:

fun main(vararg args: String) = nanoTimeAppendedTo(System.out, name = "main") {
    /* do something, e.g.: */
    Thread.sleep(0)
}

inline fun nanoTimeAppendedTo(appendable: Appendable, name: String, block: () -> Unit) {
    val nanoTime = measureNanoTime(block)
    appendable.appendln("`$name` took $nanoTime ns")
}

You won't have access to all of the information that AspectJ gives you but for simple cases where you simply want to reuse executing some code before/after/around some other code this works just fine.

like image 126
mfulton26 Avatar answered Oct 15 '22 19:10

mfulton26


This is what I did to weave in the aspects the "binary" way, after that the Java and Kotlin code has been compiled.

I couldn't get the aspectj-maven-plugin to weave the aspect the "binary" way correctly, so I used the plugin jcabi-maven-plugin instead. See http://plugin.jcabi.com/example-ajc.html

The pom that worked for me:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>my.group.id</groupId>
<artifactId>my.artifact.id</artifactId>
<version>0.0.1-SNAPSHOT</version>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.6</maven.compiler.source>
    <maven.compiler.target>1.6</maven.compiler.target>
    <complianceLevel>1.6</complianceLevel>
</properties>

<dependencies>

    <dependency>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-stdlib</artifactId>
        <version>1.0.3</version>
    </dependency>

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

</dependencies>

<build>

    <plugins>

        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <groupId>org.apache.maven.plugins</groupId>
            <version>3.3</version>
            <configuration>
                <source>${maven.compiler.source}</source>
                <target>${maven.compiler.target}</target>
            </configuration>
        </plugin>

        <plugin>
            <artifactId>kotlin-maven-plugin</artifactId>
            <groupId>org.jetbrains.kotlin</groupId>
            <version>1.0.3</version>
            <configuration>
                <sourceDirs>
                    <sourceDir>src/main/kotlin</sourceDir>
                    <sourceDir>src/test/kotlin</sourceDir>
                </sourceDirs>
            </configuration>
            <executions>
                <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.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.5.0</version>
            <configuration>
                <mainClass>my.package.MyMainClassKt</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

So this works with the aspects and a few annotations defined in Java, and then using these annotations to annotate Kotlin methods and classes, to have the aspects successfully injected in the Kotlin code.

Note that if the Kotlin file has both a main method and a class defined in the same file, the Kotlin compiler produces two class files. One class with the name of the class and one class with "Kt" added to its name. Good to know if you try to use the exec-maven-plugin to run the Kotlin code.

However, this did not play very well with eclipse. Maybe IntelliJ will do a better job here.

like image 43
User0 Avatar answered Oct 15 '22 21:10

User0