Lombok 与 JDK 10

Update at 2018-06-21:
Lombok 的 v1.16.22 版本已经解决了这个问题。
以下内容仅做记录。

Lombok 这个工具很好用,从去年了解之后我编码的时候已经几乎离不开它了。今天在写 Log4j2 的 Demo 的时候,也顺手就加上了@Log4j2,但是意想不到的情况出现了:找不到符号。

因为我已使用 Lombok 多时,看到这个报错还是挺意外的,更意外的是这个错误的根源竟然是因为 Lombok 跟 JDK 10 的兼容问题(下一个 release 版本应该就解决了)。

本文就简单记录一下这个问题的解决过程。

先说下前提条件,我使用的 IntelliJ IDEA 版本是 2018.1.2 (Ultimate Edition),并且已经安装了 Lombok Plugin,且已在 Preferences | Build, Execution, Deployment | Compiler | Annotation Processors 打开了 annotation processing。

Annotation Processors

在网上搜相关的“lombok 找不到符号”相关的问题,给出的解决办法无非也就是上边我说的装插件和调设置了。有的还说让重启 IDEA,我试了但是然并卵。

这时我回到代码本身,在 Lombok 自动生成的 log 对象上点进去看,能看到这个 log 对象的声明确确实实是有的,跟自己手写的是一毛一样。嗯,这里应该没有问题。

code

直接在 IDEA 里 build 不行,那试试用 Maven 构建一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building log4j2-demo 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ log4j2-demo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ log4j2-demo ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 5 source files to /Users/yibo/IdeaProjects/xianlai/log4j2demo/target/classes
Processing annotations
Annotations processed
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by lombok.javac.apt.LombokProcessor to field com.sun.tools.javac.processing.JavacProcessingEnvironment.discoveredProcs
WARNING: Please consider reporting this to the maintainers of lombok.javac.apt.LombokProcessor
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.148 s
[INFO] Finished at: 2018-05-06T09:52:10+08:00
[INFO] Final Memory: 12M/50M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project log4j2-demo: Fatal error compiling: java.lang.ExceptionInInitializerError: com.sun.tools.javac.code.TypeTags -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

这里的报错就比在 IDEA 里的直接 build 来的清晰明了了

1
java.lang.ExceptionInInitializerError: com.sun.tools.javac.code.TypeTags

这是一个初始化的异常,我试着去找com.sun.tools.javac.code.TypeTags发现没有这个类。(这实际是个枚举类型,你可以把末尾的 s 去掉试试看)

当我再次回过神看着这个错误,突然有种“是不是在哪见过?”的感觉。对,上次因为某个工程使用了 JDK 10,出现了不同但类似的错误。我一查这个工程的 JDK 版本,不出所料果然是 10。

我将 JDK 版本回退到 8,再次运行,发现一切顺利。看来问题就出 Lombok 和 JDK 10 的兼容问题上。

Project SDK

关于这个问题在 Lombok 的 GitHub 中有大量的 issue,比较有代表性的是这个 Lombok fails with JDK 10 · Issue #1572

关于这个问题的原因呢,解释如下
the javac version “10-ea” doesn’t match VERSION_PARSER in Javac.java
Similar, the “JDK10” enum name in Sources doesn’t match the SOURCE_PARSER pattern.
Meaning it falls back to version 6, so it ends up looking for TypeTags instead of TypeTag.

其中给出的解决方案是先用 edge release 版本

edge release

下载这个 edge release 版本,食用方法多种多样,这里介绍两种:

方法一:使用maven-install-plugin插件

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<packaging>jar</packaging>
<file>${project.basedir}/lib/lombok-edge.jar</file>
</configuration>
</execution>
</executions>
</plugin>

方法二:本地安装

1
mvn install:install-file -Dfile=lombok-edge.jar -DgroupId=org.lombokproject -DartifactId=lombok -Dversion=1.16.21 -Dpackaging=jar
1
2
3
4
5
6
<dependency>
<groupId>org.lombokproject</groupId>
<artifactId>lombok</artifactId>
<version>1.16.21</version>
<scope>provided</scope>
</dependency>

注意:这里我把groupId稍微变动了一下以区分盗版(本地仓库 org.lombokproject)和正版(中央仓库 org.projectlombok)。

最后,个人感觉 JDK 10 的变动有些大,以至于很多在 JDK8 时能好好运行的工程如果直接切到 10 都或多或少的有些问题。但并不是说 JDK 10 就不好了,现在随着 Oracle 加快了 Java 迭代速度,我们作为一名 Java 开发者总是要去接触和熟悉新的 JDK 的。好在现在很多开源项目已经支持了 JDK 10 或正在着手支持,如果在使用 JDK 10 的过程中遇到了问题,可以尝试将相关依赖升级为最新的版本。