Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
1.5.6, 1.6-beta-1
-
None
-
None
-
Groovy 1.5.6 (standalone or inside Grails 1.0.3), Groovy 1.6-beta-1, Sun Java SE 1.6.0_07 on 64bit Linux (OpenSUSE 11)
Description
I am experiencing the following problem with Groovy 1.5.6 and 1.6-beta-1:
Groovy does not seem to accept subtypes of direct subtypes of SomeType in constructs like <T extends SomeType>.
The exact constellation for reproducing the error is as follows:
Directory structure
. +- groovy | +- foo | +- bar | +- BarMaping.groovy | +- MyTypeMapping.groovy | +- MySubTypeMapping.groovy +- java +- foo +- example | +- MyType.java (interface extending Bar) | +- MySubType.java (interface extending MyType) +- Bar.java +- Baz.java
Bar.java
package foo; public interface Bar { Baz getId(); void setId(Baz id); }
Baz.java is just a POJO
MyType.java
package foo.example; import foo.Bar; public interface MyType extends Bar { String getTitle(); void setTitle(String title); }
MySubType.java
package foo.example; public interface MySubType extends MyType { }
BarMapping.groovy
package foo.bar import foo.Bar import foo.Baz abstract class BarMapping<T extends Bar> { Baz id BarMapping(T bar) { mapFrom(bar) } def mapFrom(T bar) { id = bar?.id } def mapTo(T bar) { } }
MyTypeMapping.groovy
package foo.bar import foo.example.MyType class MyTypeMapping extends BarMapping<MyType> { String title MyTypeMapping(MyType x) { super(x) } def mapFrom(MyType x) { super.mapFrom(x) title = x?.title } def mapTo(MyType x) { x.title = title } }
MySubTypeMapping.groovy
package foo.bar import foo.example.MySubType class MySubTypeMapping extends BarMapping<MySubType> { String title MySubTypeMapping(MySubType x) { super(x) } def mapFrom(MySubType x) { super.mapFrom(x) title = x?.title } def mapTo(MySubType x) { x.title = title } }
Now, the following lines will produce the compiler error:
> export CLASSPATH={absolute_path_to_this_dir}/java:{absolute_path_to_this_dir}/groovy > cd java > javac foo/*.java foo/example/*.java > cd ../groovy > groovyc foo/bar/*.groovy org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, foo/bar/MySubTypeMapping.groovy: 20: The type MySubType is not a valid substitute for the bounded parameter <T extends foo.Bar> @ line 20, column 32. class MySubTypeMapping extends BarMapping<MySubType> { ^ 1 error
This means, MyTypeMapping.groovy compiles whereas MySubTypeMapping.groovy does not compile.
An equivalent Java hierarchy compiles without problems.
Inside a Grails application, the error message is:
> grails compile Welcome to Grails 1.0.3 - http://grails.org/ Licensed under Apache Standard License 2.0 Grails home is set to: /martin/dev/grails-1.0.3 Base Directory: /martin/dev/projects/generics Note: No plugin scripts found Running script /martin/dev/grails-1.0.3/scripts/Compile.groovy Environment set to development [mkdir] Created dir: /neofonie/home/gerlach/.grails/1.0.3/projects/generics/classes [groovyc] Compiling 13 source files to /neofonie/home/gerlach/.grails/1.0.3/projects/generics/classes [javac] Compiling 12 source files to /neofonie/home/gerlach/.grails/1.0.3/projects/generics/classes Compilation error: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, /martin/dev/projects/generics/src/groovy/foo/bar/MySubTypeMapping.groovy: 20: The type MySubType is not a valid substitute for the bounded parameter <T extends foo.Bar> @ line 20, column 32. class MySubTypeMapping extends BarMapping<MySubType> { ^ 1 error
This is the error message with groovy 1.6-beta-1
> groovyc foo/bar/*.groovy java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:108) at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130) Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, foo/bar/MySubTypeMapping.groovy: 20: The type MySubType is not a valid substitute for the bounded parameter <T extends foo.Bar> @ line 20, column 32. class MySubTypeMapping extends BarMapping<MySubType> { ^ 1 error at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:296) at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:785) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:435) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:414) at org.codehaus.groovy.tools.FileSystemCompiler.compile(FileSystemCompiler.java:63) at org.codehaus.groovy.tools.FileSystemCompiler.main(FileSystemCompiler.java:246) ... 6 more
Some more observations:
- If I use BarMapping<T> instead of BarMapping<T extends Bar>, the code compiles without any problem - we only loose the possibility to check the generic type at compile time.
- When using IntellijIDEA, everything seems fine even when using <T extends Bar>, I can even execute the unit tests included in the attached archive.