Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kotlin Support #1169

Open
aikar opened this issue Aug 9, 2016 · 24 comments
Open

Kotlin Support #1169

aikar opened this issue Aug 9, 2016 · 24 comments

Comments

@aikar
Copy link

aikar commented Aug 9, 2016

Hello,
I'm wanting to use Kotlin in a project that uses Lombok with Java.

However, while the IDE shows code as valid, the Kotlin compiler can not see Lombok generated code.

This makes mixing Java+Lombok with Kotlin impossible.

Would it be possible to also apply the Lombok processing to the Kotlin compiler so we can have harmony?

@dodgex
Copy link
Contributor

dodgex commented Mar 18, 2017

For my Android App I'm currently playing with Kotlin and was able to let Kotlin see Lombok generated getters by adding the lombok processor to kapt.

provided "org.projectlombok:lombok:1.16.14"
annotationProcessor "org.projectlombok:lombok:1.16.14"
kapt "org.projectlombok:lombok:1.16.14"

This is from a gradle build but should be also possible with maven. :)

@vojkny
Copy link

vojkny commented May 23, 2017

How can this be done via Maven? Also how can I use kapt in IDE?

@vojkny
Copy link

vojkny commented May 24, 2017

I tried using kapt with lombok annotation processor as follows:

           <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <version>${kotlin.version}</version>
                <executions>
                    <execution>
                        <id>kapt</id>
                        <goals>
                            <goal>kapt</goal>
                        </goals>
                        <configuration>
                            <sourceDirs>
                                <sourceDir>${project.basedir}/src/main/java</sourceDir>
                            </sourceDirs>
                            <annotationProcessors>
                                <annotationProcessor>lombok.core.AnnotationProcessor</annotationProcessor>
                            </annotationProcessors>
                        </configuration>
                    </execution>
    ...

With no effect.

@ubaierbhat
Copy link

I have the same problem. We are using Lombok in our Android apps and it looks like we can't use it along side with kotlin. @dodgex suggestion did not work for me.

@taejungkim
Copy link

taejungkim commented Aug 17, 2017

@dodgex I added kapt plugin with kapt "org.projectlombok:lombok:1.16.14" .
But impossible access to getter ( generated by lombok )

Help me!

@faizanahemad
Copy link

Any solution found to this? I have the same issue. We use Intellij with Java and lombok. and build with maven.

@jtonic
Copy link

jtonic commented Oct 12, 2017

Hi,

The only solution I found quite satisfactory was to move the lombok annotated java file in a separate maven module. But in our case lombok annotations were only used for DTOs (model), so it did make sense to approach this way.

Kind regards

Tony

@rojiani
Copy link

rojiani commented Jan 23, 2018

For anyone looking for a solution, I've created a demo app illustrating the separate module idea mentioned by @jtonic (except using Gradle rather than Maven).

@mouyang
Copy link

mouyang commented Feb 18, 2018

@dodgex do you have a working solution or a minimal proof-of-concept that you are able to post? All of the comments here suggest that this does not work.

@dodgex
Copy link
Contributor

dodgex commented Feb 18, 2018

Sorry but currently I don't have a project using lombok & kotlin.

@mouyang
Copy link

mouyang commented Feb 23, 2018

Hmmm. I'm probably not understanding the issue but it seems like this is possible as of Kotlin 1.2.21. All I did was blindly follow the instructions on the Kotlin Web site ...
https://kotlinlang.org/docs/reference/using-maven.html#compiling-kotlin-and-java-sources
https://kotlinlang.org/docs/reference/using-gradle.html

and I was able to see Lombok-generated methods in Kotlin without creating any separate modules ...
https://github.com/mouyang/kotlin-lombok/tree/master/gradle
https://github.com/mouyang/kotlin-lombok/tree/master/maven

Again, I'm probably misunderstanding the issue completely so any clarification would be appreciated.

@jtonic
Copy link

jtonic commented Feb 24, 2018

Hi,

I am not a specialist but I am trying to shed a light on the problem.

  1. lombok is not a pure APT library, because it also uses javac to generate the bytecode. AFAIK APT generates java sources, but lombok generates bytecode.
  2. kotlin supports joint compilation in the sense that it can compile both java and kotlin files (with two-way dependencies between them) in the same module .
  3. kotlin also support the ATP through KAPT kotlin plugin. This allows the joint compiler to see also the ATP generated java files by the kotlin ones.

There are some popular ATP libraries to generate useful java sources (related to hibernate, spring boot properties, java bean mappers - MapStruct) and there is no problem with them in java/kotlin module, thanks to kapt. But on the other hand because lombok modifies the bytecode during the compilation kapt can do nothing about it.

This is the problem I came across and if, I remember well, there was a thread, I suppose on stackoverflow, where the kotlin language architect told about this issue, explaining things more in depth.

Kind regards.

@mouyang
Copy link

mouyang commented Feb 27, 2018

@jtonic, thank you. Your explanation makes a lot of sense.

@dodgex If you have time, can you take a look at a sample branch I have? It's an minimal unsuccessful attempt to use Lombok in Kotlin, and I was wondering what you did to make it work.
I did not use "annotationProcessor" since I'm not working on Android, but I don't know if that actually matters or not. https://github.com/mouyang/kotlin-lombok/tree/broken-gradle-kapt

@jtonic
Copy link

jtonic commented Feb 27, 2018

@mouyang
I looked a bit over your example (gradle based one) and I have some recommendations.

  1. I urge you not to use lombok on kotlin classes. Practically you have all the supports lombok have in the kotlin syntax/api.
  2. I would use lombok only for DTOs or model classes. I saw lombok-ized spring services only to include @slf4j. It could bring a lot of issues
  3. if you lombok-ize only the (java) model then it makes sense to extract it into a new gradle subproject and and all is fine. And latter on incrementally migrate from java lombok-ized model to kotlin one. Of course in this new gradle model sub-project you cannot have kotlin classes referencing java lombok-ized ones.

Note: I remember I read on some stack overflow thread another approach - smth like put some generated lomboked classes in a gen folder and then refer it in the kotlin compilation one. This could work but for me it was an additional burden on the build tool.

I really hope all these help you figured out how to approach the kotlin/java/lombok issue.

@ericytsang
Copy link

ericytsang commented Jun 18, 2018

I've been trying to look for a solution for this problem to try to get my ancient team to migrate to a new language. we're so ancient that the leads complain about using java8's lambdas. i ended up making a pom.xml that delomboks the code in src/main/java then compiles the delomboked code with the kotlin plugin:

<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ericytsang</groupId>
    <artifactId>playground</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>com.ericytsang playground</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <kotlin.version>1.2.50</kotlin.version>
        <junit.version>4.12</junit.version>
        <lombok.version>1.16.8</lombok.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test-junit</artifactId>
            <version>${kotlin.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok-maven-plugin</artifactId>
                <version>${lombok.version}.0</version>
                <executions>
                    <execution>
                        <id>delombok</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>delombok</goal>
                        </goals>
                        <configuration>
                            <sourceDirectory>src/main/java</sourceDirectory>
                            <outputDirectory>${project.build.directory}/delombok-main</outputDirectory>
                            <addOutputDirectory>false</addOutputDirectory>
                        </configuration>
                    </execution>
                    <execution>
                        <id>delombok-test</id>
                        <phase>generate-test-sources</phase>
                        <goals>
                            <goal>delombok</goal>
                        </goals>
                        <configuration>
                            <sourceDirectory>src/test/java</sourceDirectory>
                            <outputDirectory>${project.build.directory}/delombok-test</outputDirectory>
                            <addOutputDirectory>false</addOutputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <version>${kotlin.version}</version>
                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>process-sources</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <configuration>
                            <sourceDirs>${project.build.directory}/delombok-main</sourceDirs>
                        </configuration>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                        <configuration>
                            <sourceDirs>${project.build.directory}/delombok-test</sourceDirs>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

</project>

i usually use gradle..im not too familiar with maven. improvements are welcome. i don't think it supports incremental compilation...i also imagine that having to modify every plugin originally using src/main/java to now use ${project.build.directory}/delombok-main would be a pain. debugging also becomes odd since the compiled code is the delomboked code instead of the code in src/main/java.

https://stackoverflow.com/a/50914110/2898715

@DRSchlaubi
Copy link

Seems like Kotlin themselves is working on a Lombok integration: https://github.com/JetBrains/kotlin/tree/master/plugins/lombok/lombok-compiler-plugin

@Rawi01
Copy link
Collaborator

Rawi01 commented Apr 27, 2021

That's fascinating, I had a quick look at the code and it seems like it adds some kind of method stubs to make them visible for Kotlin. If I have not missed anything that requires a basic reimplementation of all lombok handlers, seems to be a bunch of work 😄

I also tried to understand the Kotlin compilation process and I think it still invokes javac to compile the Java files. If it would be possible to run an annotation processor at that moment lombok should work. IIRC I did something similar some time ago for an android project: #2412 (comment)

@zveznicht
Copy link

kotlin+java projects are compiled like this:

  1. First kotlinc compiles kotlin code. It parses all java sources to resolve all links to it. And generates class files for kotlin files.
  2. After javac compiles all java sources, compiled kotlin classes are passed in classpath.

So to support lombok you need to provide all symbols lombok generates to kotlin on (1). Thats what new plugin does. You may call it stubs, they are basically declarations of parts lombok will generate later.
During (2) you simply enable lombok as annotation processor and it generates everything as usual.

I also tried to understand the Kotlin compilation process and I think it still invokes javac to compile the Java files. If it would be possible to run an annotation processor at that moment lombok should work

it will work as long as you don't refer any lombok-generated symbols from kotlin code.

@Rawi01
Copy link
Collaborator

Rawi01 commented Jun 15, 2021

@zveznicht Thanks for the additional details. Does kotlinc uses its own parser or does it use javac to generate the symbols/stubs? If it is the former the plugin is the only solution but if it is the latter it might be possible to invoke lombok.

@zveznicht
Copy link

zveznicht commented Jun 15, 2021

Thanks for the additional details. Does kotlinc uses its own parser or does it use javac to generate the symbols/stubs

kotlinc uses its own parser

@CharlyLafon37
Copy link

Check https://kotlinlang.org/docs/lombok.html. Seems to work for me.

@rzwitserloot
Copy link
Collaborator

We're still seeing some issue traffic on this. Does the kotlin plugin for lombok as linked by @CharlyLafon37 above work as expected? To be clear, this is what I expect, and this is what we will (attempt to) fix:

  • When using kotlinc in mixed mode to compile both .java as well as .kt source files in one go using kotlinc, that any lombok annotations used in your java code works totally fine, and that your .kt code sees the effects (as in, if your java source files use @Getter, then [A] these compile fine, [B] those getters are indeed generated and in the class files that kotlinc spits out, and [C] your .kt code sees them. – and that this all works if the code is tightly bound (Foo.java needs Bar.kt and vice versa, so compiling them out separately does not work unless you make stubs).

What we won't fix is:

  • Using lombok annotations in your .kt files, such as putting @Slf4j on your kotlin class and expecting lombok to stick a LOGGER field in your kotlin file. We don't do that, and don't intend to. We won't accept PRs unless you bring your own support team, as we are not in a position to provide the maintenance of such a feature. I'm not sure it's a good idea in the first place. Sounds like that should be a separate project, run by different folks. We'd love to work together with such a project to try and use the same names and adopt the same general meanings of things as much as possible, but it would end there.

@rzwitserloot
Copy link
Collaborator

Assuming that plugin works, can somebody tell me what happens if that plugin isn't around? Does lombok just silently not run, or is it more like #2428 describes: That lombok does run as annotation processor, fails to detect environment, says so in an error log, and throws in the towel?

Assuming the kotlinlang plugin works, we need to update our docs to refer to it. If lombok does run but fails to detect environment, we should make it detect environment and adjust our error message to refer to the plugin.

@YASMINCOS
Copy link

alguma atualização? estou tendo esse problema

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests