Reputation: 393
I am trying to make a generic handling of different service implementations and I constantly receive the "Unchecked call due to raw type" error.
I have tried several implementations, but could not quite understand what is the issue here.
I have the following model:
public abstract class Fruit {
public List<String> vitamins;
public String originCountry;
// getters and setters omitted
}
The concrete implementation are the following:
public class Kiwi extends Fruit {
}
public class Pineapple extends Fruit {
}
I have the following interface:
public interface FruitCheckService<T extends Fruit> {
List<String> compareVitaminsFromDifferentCountries(T firstFruit, T secondFruit);
Class<T> getImplementation();
}
With implementations for the 2 models given above:
@Service
public class KiwiCheckServiceImpl implements FruitCheckService<Kiwi> {
@Override
public List<String> compareVitaminsFromDifferentCountries(Kiwi firstFruit, Kiwi secondFruit) {
// some implementation
return new ArrayList<>();
}
@Override
public Class<Kiwi> getImplementation() {
return Kiwi.class;
}
}
And pineapple:
@Service
public class PineappleCheckServiceImpl implements FruitCheckService<Pineapple> {
@Override
public List<String> compareVitaminsFromDifferentCountries(Pineapple firstFruit, Pineapple secondFruit) {
// some implementation
return new ArrayList<>();
}
@Override
public Class<Pineapple> getImplementation() {
return Pineapple.class;
}
}
I have the following class which is manupulating with the different beans:
@Service
public class FruitServices {
private Map<Class, FruitCheckService> beansMap;
@Autowired
public FruitServices(List<FruitCheckService> fruitCheckServices) {
beansMap = new HashMap<>();
fruitCheckServices
.forEach(
fruitCheckService -> {
Class implementation = fruitCheckService.getImplementation();
beansMap.put(implementation, fruitCheckService);
}
);
}
public FruitCheckService getFruitCheckService(Class clazz) {
return beansMap.get(clazz);
}
}
At the end, this is the service where I am calling this:
@Component
public class BusinessService {
@Autowired
private FruitServices fruitServices;
public void compareVitamins(Fruit one, Fruit two) {
Class<? extends Fruit> aClass = one.getClass();
FruitCheckService fruitCheckService = fruitServices.getFruitCheckService(aClass);
List<String> result = fruitCheckService.compareVitaminsFromDifferentCountries(one, two);
}
}
How to use correctly the fruitCheckService without receiving "Unchecked call to 'compareVitaminsFromDifferentCountries(T, T)' as a member of raw type 'exercise2.service.FruitCheckService'"?
Upvotes: 1
Views: 101
Reputation:
The problem is that you are using the raw type Class
in your service definition. To get around this problem, you can use the bounded wildcard type ?
, as such:
class FruitServices {
private Map<Class<? extends Fruit>, FruitCheckService<? extends Fruit>> beansMap;
public FruitServices(List<FruitCheckService<? extends Fruit>> fruitCheckServices) {
beansMap = new HashMap<>();
fruitCheckServices
.forEach(
fruitCheckService -> {
Class<? extends Fruit> implementation = fruitCheckService.getImplementation();
beansMap.put(implementation, fruitCheckService);
}
);
}
public FruitCheckService<? extends Fruit> getFruitCheckService(Class<? extends Fruit> clazz) {
return beansMap.get(clazz);
}
}
For class BusinessService
things are going to be trickier. First, it is necessary to make compareVitamins
a generic method to ensure both fruits are of the same type. But even then, I don't believe you can avoid an unchecked cast from the result of getFruitCheckService
because, as FruitServices
has to deal with services for different types of fruit, you can't have a precise type parameter for the return value of getFruitCheckService
.
class BusinessService {
private FruitServices fruitServices;
public <T extends Fruit> void compareVitamins(T one, T two) {
@SuppressWarnings("unchecked")
FruitCheckService<T> fruitCheckService =
(FruitCheckService<T>) fruitServices.getFruitCheckService(one.getClass());
List<String> result = fruitCheckService.compareVitaminsFromDifferentCountries(one, two);
}
}
Upvotes: 1