Lombok’s access to jdk.compiler’s internal packages incompatible with Java-16

Update:

Lombok v1.18.20 supports JDK 16 out of the box.

In the same thread, one of the maintainers also writes:

We have some less well known loopholes we can use to bridge a few gaps. We’ll start work on gradle and maven plugins in the mean time, which will be a long-term fix.


Original:

The exception you are seeing with the latest JDK-16 build is because of JEP 396: Strongly Encapsulate JDK Internals by Default. Lombok is accessing an internal JDK API with reflection, and where in previous Java versions this would result in a warning message, it now results in a hard error.

In general, it is possible to explicitly open internal JDK packages for reflection when running java by passing --add-opens=<module>/<package>=<accessing module> directives as VM arguments when running java. In this case these directives would need to be passed to the java process that runs when invoking javac. This can be done by prefixing the option passed to javac with -J, which will instead pass it to the underlying JVM.

Using Maven, I was able to make it work with the following compiler plugin config:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <source>16</source>
        <target>16</target>
        <!--                    <release>16</release>-->
        <fork>true</fork>
        <compilerArgs>
            <arg>--enable-preview</arg>
            <arg>-Xlint:all</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED</arg>
        </compilerArgs>
        <!--for unmappable characters in classes-->
        <encoding>UTF-8</encoding>
        <showDeprecation>true</showDeprecation>
        <showWarnings>true</showWarnings>
        <!--for lombok annotations to resolve-->
        <!--contradictory to maven, intelliJ fails with this-->
        <annotationProcessorPaths>
            <path>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.16</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

Where the needed options are passed using <compilerArgs> elements in the configuration.

Note that I added -J in front of the options in order to pass them to the JVM running javac, instead of javac options.

On top of the --add-opens directives listed in the question, an additional:

-J--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED

was also needed.

<fork>true</fork> was also needed since otherwise the -J options were being ignored (judging from the output of mvn clean install -X). Looking at the Maven docs, setting fork to true seems to be needed any time when using <compilerArgs>:

https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#compilerArgs

<compilerArgs> Sets the arguments to be passed to the compiler if fork is set to true.

Leave a Comment