Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: 1.7.10, 1.8.0
-
Fix Version/s: 1.8.2, 1.9-beta-3, 1.7.11
-
Component/s: None
-
Labels:None
-
Environment:WinXP
-
Testcase included:yes
-
Number of attachments :
Description
Original problem:
I have an abstract groovy class, and two (or more) concrete java subclasses extend it. The superclass has an abstract method, which each concrete subclass overrides (of course).
When I use just one subclass, everything works fine: I call a superclass method that calls the abstract method, and I get the behavior I expect. But when the other subclass has already been loaded, things are different. Then, I get an IllegalArgumentException: object is not an instance of declaring class.
This problem corresponds to testGenericSubclassWithBafflingSymptom() in the attached junit tests. See that test for additional details.
Simpler case that illustrates the likely underlying problem (and does not involve generics):
I have an abstract groovy class, and two concrete java subclasses extend it. If I have an instance of just one of the subclasses, then instance.metaClass.theClass returns exactly what I expect. But if I've already loaded the other subclass, then the metaClass on an instance of either subclass is for the class that was used first!
// snippet of the groovy version of testSubclass(), also attached OtherConcreteJavaSubclass unrelatedInstance = new OtherConcreteJavaSubclass(); ConcreteJavaSubclass instance = new ConcreteJavaSubclass(); assertEquals("this one works", OtherConcreteJavaSubclass, unrelatedInstance.metaClass.theClass) assertEquals("but this one is wrong", ConcreteJavaSubclass, instance.metaClass.theClass)
This mixture of groovy and java may sound a little odd, but we actually ran into it when converting an existing class from java to groovy, and it stumped us for quite a while.
This bit us as well--as it manifests subtly, because unit tests pass when run in isolation but once both classes are loaded the same code will throw the exception mentioned above:
Suggest high priority as this takes a long time to track down and mixing Java and Groovy will be common in a large team.
The simple workaround we use is to put the following in the groovy superclass constructor (getting the metaclass of the java subclass, curiously, seems to work):