How to compile mixed java groovy project with AST transformations?

1.1k Views Asked by At

When I try to compile my project using groovy-eclipse compiler with following classes:

 import groovy.transform.builder.Builder

// @author: m on 10.05.16 22:15.
@Builder
class F {

   int a

}

and

public class B {

   int a;

public static void main(String[] args) {
    F.FBuilder builder = F.builder();

    F build = builder.a(1).build();
  }
}

The following error occurs:

[INFO] Using Groovy-Eclipse compiler to compile both Java and Groovy files
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] /Users/m/git_repo/mix/src/main/java/B.java:[7,1] 1. ERROR in /Users/m/git_repo/mix/src/main/java/B.java (at line 7)
    F.FBuilder builder = F.builder();
    ^^^^^^^^^^
F.FBuilder cannot be resolved to a type

[ERROR] /Users/m/git_repo/mix/src/main/java/B.java:[7,24] 2. ERROR in /Users/m/git_repo/mix/src/main/java/B.java (at line 7)
    F.FBuilder builder = F.builder();
                           ^^^^^^^
The method builder() is undefined for the type F
[ERROR] Found 2 errors and 0 warnings.

How to fix it? Please help

4

There are 4 best solutions below

0
On

You may just want to use the def keyword in place of F.FBuilder. When using joint compilation (java and groovy mixed in the same source folder), the groovy files are mapped into the Java model of Eclipse/JDT. However this mapping happens before many AST transformations have been applied, so additional types and methods like @Builder adds are not seen by Java.

1
On

The Java files need to be under the groovy directory with the Groovy files if they need to be cross-compiled.

8
On

Try using the maven-antrun-plugin:

<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
        <execution>
            <id>compile</id>
            <phase>compile</phase>
            <configuration>
                <tasks>
                    <mkdir dir="${basedir}/src/main/groovy"/>
                    <taskdef name="groovyc"
                        classname="org.codehaus.groovy.ant.Groovyc">
                        <classpath refid="maven.compile.classpath"/>
                    </taskdef>
                    <mkdir dir="${project.build.outputDirectory}"/>
                    <groovyc destdir="${project.build.outputDirectory}"
                        srcdir="${basedir}/src/main/groovy/" listfiles="true">
                        <classpath refid="maven.compile.classpath"/>
                    </groovyc>
                </tasks>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
        <execution>
            <id>test-compile</id>
            <phase>test-compile</phase>
            <configuration>
                <tasks>
                    <mkdir dir="${basedir}/src/test/groovy"/>
                    <taskdef name="groovyc"
                        classname="org.codehaus.groovy.ant.Groovyc">
                        <classpath refid="maven.test.classpath"/>
                    </taskdef>
                    <mkdir dir="${project.build.testOutputDirectory}"/>
                    <groovyc destdir="${project.build.testOutputDirectory}"
                        srcdir="${basedir}/src/test/groovy/" listfiles="true">
                        <classpath refid="maven.test.classpath"/>
                    </groovyc>
                </tasks>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
    </executions>
</plugin>
0
On

If you do not mind splitting Java and Groovy classes into different Maven modules, I would strongly encourage you to do that.

The benefits are that you will never run into joint compilation issues, you will get a clear vision of what depends on what (to use a Groovy module from a Java module, you add a Maven dependency to it), Groovy AST will be visible from the Java classes, and you stay sane by not mixing languages within the same module.

I created a simple java-groovy-maven-test project on GitHub to show how you can do that.

Basically, you create two modules, one just containing your Java class (test-java in my project), the other containing the Groovy class (test-groovy).

Both are under the same parent Maven module.

This works much better than trying to compile both Groovy/Java within the same module.

Instruction on how to build and test the project are on the README page.