On 11/08/10 2:06 PM, Kenneth Kousen wrote:
Hi all,

I'm trying to use a Groovy class marked with @Immutable, from a Java class. As you might imagine, this is leading to some strange behavior, especially when using Eclipse and Gradle.

First, here's build.gradle:

apply plugin:'groovy'

repositories {
mavenCentral()
}

sourceSets {
main {
            java { srcDirs = [] }
            groovy { srcDir 'src' }
}
test {
            java { srcDirs = [] }
            groovy { srcDir 'tests' }
}
}

dependencies {
groovy group:'org.codehaus.groovy', name:'groovy-all', version:'1.7.2'
testCompile group:'org.spockframework', name:'spock-core', version:'0.4-groovy-1.7'
testCompile group:'junit', name:'junit', version:'4.8.1'
}

I find this custom mapping of the source sets to be very helpful when mixing Java and Groovy code. As you can see, I'm basically just using the Groovy compiler for both Groovy and Java files.

Here's my immutable class:

@Immutable
class ImmutablePoint {
    double x
    double y
}

From Groovy, I have the following Spock test, stored in the 'tests' tree:

import groovy.lang.ReadOnlyPropertyException;
import spock.lang.Specification;

class ImmutablePointSpockTest extends Specification {
def "map-based constructor"() {
when:
def p = new ImmutablePoint(x:3,y:4)
then:
p.x == 3
p.y == 4
}
def "regular constructor"() {
when:
def p = new ImmutablePoint(3,4)
then:
p.x == 3
p.y == 4
}
def "can not change x"() {
when:
def p = new ImmutablePoint(x:3,y:4)
p.x = 5
then:
thrown(ReadOnlyPropertyException)
}
def "can not change y"() {
when:
def p = new ImmutablePoint(x:3,y:4)
p.y = 5
then:
thrown(ReadOnlyPropertyException)
}

}

That's all good and expected, and works when using Gradle 0.9-rc1. Here's a similar test, this time in Java using JUnit 4, also in the test tree:

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class ImmutablePointJUnitTests {
private ImmutablePoint p;
@Test
public void testConstructor() {
p = new ImmutablePoint(3,4);
assertEquals(3.0, p.getX(), 0.0001);
assertEquals(4.0, p.getY(), 0.0001);
}

}

Believe it or not, that too works just fine. It confuses the heck out of the Groovy Eclipse plugin, which underlines the ImmutablePoint constructor as an error but doesn't flag the class as having an error in the Package Explorer, but I can live with that.

Everything is fine until I use the same constructor in actual Java code in the 'src' tree:

public class UsePoint {
public static void main(String[] args) {
// ImmutablePoint p = new ImmutablePoint(3,4);
// System.out.println(p);
}
}

If I remove the comments and run this as a regular Java application in Eclipse, I get:
    ast.ImmutablePoint(3.0, 4.0)
which is fine.  If I do the "gradle build", however, I get:

:compileJava UP-TO-DATE
:compileGroovy
org.codehaus.groovy.control.MultipleErrorsException: startup failed:
Compile error during compilation with javac.
c:\...\UsePoint.java:5: cannot find symbol
symbol : constructor ImmutablePoint(int,int)
location: class ast.ImmutablePoint

etc. In other words, I can use that constructor in a JUnit test in the tests tree, but as soon as I use it in the source tree in a Java class, the build fails.

I'm sure getting Groovy Eclipse and Gradle to deal with AST Transformations is quite a task (no pun intended), but still, this is pretty strange behavior. Any idea what's going on?

It looks like the Groovy compiler is not taking AST transformations into account when generating the Java stubs for joint compilation, and so does not include the generated constructor. You should raise this issue with the Groovy project.


--
Adam Murdoch
Gradle Developer
http://www.gradle.org
CTO, Gradle Inc. - Gradle Training, Support, Consulting
http://www.gradle.biz

Reply via email to