If we try to use the repository for saving the data we end with a similar error:
publicIterable<ModelObject>save(finalIterable<ModelObject> data) {// ERROR: Iterable<ModelObject> is not Iterable<ModelObjectEntity>returnrepository.create(data);}
The difference here is that the type is inside the Iterable, used as a generic. Now we have to worry not only about the type we use, but also about the type inside the argument.
Method Receiving a Child
Another version of the same problem is using as argument a collection of child classes. These will extend the interface we want, but won't match the expected generic template.
Collection<ModelObjectEntity> data;data =newArrayList<>();// ERROR: Iterable<ModelObjectEntity> is not Iterable<ModelObject>service.save(data);
Solving Nested Type Errors
Removing Types
The easiest way, which is not recommended, is removing the nested type:
publicIterablesave(finalIterable data) {// WARNING: type safety due to unchecked conversionreturnrepository.create(data);}
Collection<ModelObjectEntity> data;data =newArrayList<>();// There is not an error or warningservice.save(data);
In short, this is already done by Java (type erasure), as generics are checked only when compiling. But we lose the most important feature of generics, ensuring that we are working with the data we want.
Transforming Types
Again, we can keep the interfaces by transforming the type. But in this case we will have to transform all the objects we have received:
publicIterable<ModelObject>save(finalIterable<ModelObject> data) {finalIterable<ModelObjectEntity> entities;finalIterable<ModelObjectEntity> created; entities =StreamSupport.stream(data.spliterator(),false).map(this::toEntity).collect(Collectors.toList()); created =repository.save(entities);returnStreamSupport.stream(created.spliterator(),false).map(this::toObject).collect(Collectors.toList());}
Using Wildcard
Another option is making use of the tools offered by generics:
And matching it with the type the dependencies want:
finalModelObjecService<ModelObjectEntity> service =newModelObjecServiceImpl<>(repository);
publicIterablesave(finalIterable<ModelObjectEntity> data) {// ERROR: Iterable<? extends ModelObject> is not Iterable<ModelObjectEntity>returnrepository.create(data);}