YON Blog

Java 和 Groovy 混合编程

Groovy 有很好的动态语言特性,编译后可以直接在 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>

其中的 javaAgentClassfork 的配置是必须的,插件中依赖的 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