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