Java 和 Groovy 混合编程
16 Mar 2022Groovy 有很好的动态语言特性,编译后可以直接在 Java 代码里使用,所以 Java 和 Groovy 非常适合搭配在一起使用。网上相关的文档很多 [1],如果你运气好,跟着操作就可以了,运气不好就会有一些坑要自己趟一遍。Java 和 Groovy 混合编程主要就是需要配置下编译器,因为 Java 和 Groovy 代码会相互引用,编译 Java 或 Groovy 的时候需要能识别到另一门语言编写的代码。目前主流的两种编译配置,一个是用 Groovy-Eclipse 插件,另一个是用 GMavenPlus 插件。前者是直接在一个编译器里解决了交叉引用的问题,后者是先根据 Groovy 生成对应 Java 代码的 stub,让 Java 代码先编译通过,然后再用 Groovy 编译器来编译 Groovy 代码。
先说 Groovy-Eclipse 插件,如果你只是需要编译成功,那么按照官网的 wiki 配置下就可以了 [2],但如果你需要和 lombok 配合使用虽然官方有指导 [3] ,但是坑还是比较多,有的坑还填不了。首先,为了支持 lombok 你要这么配置:
<build>
<plugins>
<!-- groovy 和 java 混合编程 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerId>groovy-eclipse-compiler</compilerId>
<compilerArguments>
<javaAgentClass>lombok.launch.Agent</javaAgentClass>
</compilerArguments>
<fork>true</fork>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-compiler</artifactId>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-batch</artifactId>
<version>${groovy.version}-01</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
其中的 javaAgentClass
和 fork
的配置是必须的,插件中依赖的 lombok
也是必须的。这么配置下来,如果你简单使用 lombok 的话,maven 就能编译通过了。如果你 IDE 是 IDEA,那么大概率 IDEA 编译不通过了,因为 IDEA 会错误识别 javaAgentClass
导致 groovy-eclipse-compiler
编译出错。你可以在 IDE 里使用 javac
的编译器( 虽然使用 javac ,但是 IDEA 是能正确编译 Groovy 的),另外就是记得将 IDEA 里 maven 的 Detect compiler automaticlly
选项关闭,否则一刷新 pom,IDEA 就又使用错误配置了。如果你 lombok 使用的时候还要自定义配置,也就是说你会创建自己的 lombok.config
文件,那么 Groovy-Eclipse 插件就没法支持了(我是没找到解决方案)。所以 Groovy-Eclipse 插件的坑还挺多的,一是多人协作的情况 IDEA 需要手动配置下,lombok 的自定义配置无法使用,基于这些原因,我们项目最终使用的是 GMavenPlus 插件。
GMavenPlus 就简单多了,按照官网 wiki 配置就好了 [4]。我一开始配置的时候编译始终报错,提示:
Execution default of goal org.codehaus.gmavenplus:gmavenplus-plugin:1.13.1:generateStubs failed: Unrecognized target bytecode: '8'.
原因是我们项目 maven.compiler.target
配置的值是 8
,换成 1.8
就好了。另外,GMavenPlus 支持 indy
功能 [5],也就是编译产生字节码时会使用 invokedynamic
指令,一些 Groovy 的动态特性执行起来效率会更高。
[1] Integrating Groovy into Java Applications
[2] How to use the compiler plugin - Setting up the POM
[3] Project Lombok
[4] Joint Compilation
[5] InvokeDynamic Compilation