Reputation: 71
class TestClass <T extends SuperClass>{
public List<T> doSmth(){
///....
List testObjects = []
testObjects.add(new T(arg))
return testObjects;
}
}
class SuperClass{
}
class A extends SuperClass{
A(Arg arg){
....
}
class B extends SuperClass{
B(Arg arg){
....
}
////////test
class Main{
List <A> a
List <B> b
Main(){
this.a = new TestClass<A>().doSmth()
this.b = new TestClass<B>().doSmth()
}
}
Exception found (groovy.lang.GroovyRuntimeException: Could not find matching constructor for SuperClass) on line
testObjects.add(new T(arg))
This is quite correct coz SuperClass have no constructor. But sub-classes have one and all of them have the same signature, arg with the same type.
can some one help me to find a solution to my problem?
Upvotes: 5
Views: 2136
Reputation: 2568
The reason why your code doesn't work is not matching constructors of A
and B
. The reason is missing constructor that accepts string in SuperClass
. new T()
doesn't work as you expect. In your code it becomes new SuperClass(arg)
. The following code demonstrates it
class TestClass <T extends SuperClass> {
public void doSmth(){
println new T().class.simpleName;
}
}
class SuperClass{}
class A extends SuperClass{}
class B extends SuperClass{}
new TestClass<A>().doSmth()
new TestClass<B>().doSmth()
new TestClass<String>().doSmth() //even this works
Output is
SuperClass
SuperClass
SuperClass
TestClass <T>
will print Object
. TestClass <T extends A>
will print A
and so on.
Groovy doesn't have generic type information in runtime. Groovy even doesn't do compile type checking (example with new TestClass<String>()
). But it keeps some info to make new T()
work.
Java's generics implementation incorporates a feature known as "type erasure" which "throws away" generic type information after completing static type checking. This allows Java to easily integrate with legacy "non-generics" libraries. Groovy currently does a little further and throws away generics information "at the source level". Generics information is kept within signatures where appropriate http://web.archive.org/web/20150102195947/http://groovy.codehaus.org/Generics
Upvotes: 4
Reputation: 5950
Unfortunately, it's not possible to create a new instance of the generic type with new T
. So you'll need to work around that problem.
One way to work around it is to include a closure parameter in doSmth()
that creates the instance for you.
public List<T> doSmth(Closure newT) {
List testObjects = []
testObjects.add(newT(arg))
return testObjects;
}
and provide the code to create new instance when calling the method:
Main() {
this.a = new TestClass<A>().doSmth { new A(it) }
this.b = new TestClass<B>().doSmth { new B(it) }
}
Upvotes: 3