Reputation: 15021
public class ResourceAssembler<T extends BasedEntity> {
public Resource<T> toResource(T entity) {
ExtendsBasedEntity e = getExtendsBasedEntity();
toResource(e); //<----compile error
//some other code
}
}
public class ExtendsBasedEntity extends BasedEntity{}
But if you call it from the outside its fine
//some other class
new ResourceAssembler<ExtendsBasedEntity>().toResource(new ExtendsBasedEntity())
Why?
Error:(28, 25) java: incompatible types: spring.BasedEntity cannot be converted to T
Upvotes: 1
Views: 158
Reputation: 1361
Let's create two classes extending BasedEntity
and call them EBE1
and EBE2
.
Now you create a ResourceAssembly
object using EBE1
as the type parameter. But let's say that in the implementation of the toResource
method you do something like return toResource(new EBE2());
.
So the return type of toResource()
is becoming Resource<EBE2>
but that is wrong because according to the structure you should return Resource<EBE1>
. And that's why the compile time error. And type safety instincts of Java kicks in.
If you want to do return a generic for the toResource
method then you either have to pass in the entity
object down as it is or change it to the concrete type that you are initializing it within and not use generic (although I don't know why would anyone use the second option, but it's a "solution" to make it "compile").
Also, on the outside when you declare it. You are not specifying the type parameter for ResourceAssembly
and hence it's a raw one. Try to do it with a type param. You will have red squiggly lines there as well.
Here is an example:
static class Resource<T> {
}
static class BasedEntity {
}
static class ExtendsBasedEntity1 extends BasedEntity {
}
static class ExtendsBasedEntity2 extends BasedEntity {
}
static public class ResourceAssembler<T extends BasedEntity> {
public Resource<T> toResource(T entity) {
return toResource(new ExtendsBasedEntity1()); //<----compile error
}
}
public static void main(String[] args) {
new ResourceAssembler<ExtendsBasedEntity1>().toResource(new ExtendsBasedEntity1()); // <---- No errors or warnings. This is valid and legal
new ResourceAssembler<ExtendsBasedEntity2>().toResource(new ExtendsBasedEntity1()); // <----- red squiggly lines here
new ResourceAssembler().toResource(new ExtendsBasedEntity2()); // <--compiler warning about raw types but no error
}
If you anyhow need to make it work the way you want it to, then instead of returning Resource<T>
, return Resource<ExtendsBasedEntity>
because you are recursing inside a generic method and looks like you need an object of concrete type to go in as the parameter for the recursive call. So it would make sense to do so.
Or else, go with @Bohemian's approach and make sure that in the class declaration of the type that you are using, there is a no-args constructor or else you will be having InstantiationException
.
Upvotes: 0
Reputation: 424983
T
may not be ExtendsBasedEntity
, but some other subtype of BaseEntity
, hence the compile error.
One way to "fix" the problem, is to use a type token
public class ResourceAssembler<T extends BasedEntity> {
private final Class<T> type;
public ResourceAssembler(Class<T> type) {
this.type = type;
}
public Resource<T> toResource(T entity) {
toResource(type.newInstance());
//some other code
}
}
Assuming that works for you.
Upvotes: 2