Impossible typing when the argument accepts Collection <X <? >>
This problem comes from the javax.validation.ConstraintViolationException constructor javax.validation.ConstraintViolationException . It takes Set<ConstraintViolation<?>> as an argument.
While it is very easy to get the ConstraintViolation <X> set, where X is a particular type, it seems impossible to get the "ConstraintViolation <?>" Set from any well-typed API. And it is impossible to convert the first to the last without using some minimized throws. (Drop to Set<? extends ConstraintViolation<?>> , and then Set<ConstraintViolation<?>> .)
And you guys think the API is wrong or am I wrong (and why)?
The API is invalid. If implementations do not need to add a new set of ConstraintViolation<?> the set, it should accept all Set<? extends ConstraintViolation<?>> Set<? extends ConstraintViolation<?>> .
Here is an example demonstrating why this is more flexible (provided by Paul Bellora, thanks):
public class Main { interface Foo<T> { } interface SubFoo<T> extends Foo<T> { } static class Bar { } public static void main(String[] args) { Set<Foo<?>> arg1 = null; Set<SubFoo<?>> arg2 = null; Set<Foo<Bar>> arg3 = null; Set<SubFoo<Bar>> arg4 = null; Set<Foo<?>> inflexibleParam; inflexibleParam = arg1; //success inflexibleParam = arg2; //incompatible types inflexibleParam = arg3; //incompatible types inflexibleParam = arg4; //incompatible types Set<? extends Foo<?>> flexibleParam; flexibleParam = arg1; //success flexibleParam = arg2; //success flexibleParam = arg3; //success flexibleParam = arg4; //success } } ( ideone )
The API is invalid.
Ideally, wherever we want to adopt a covariant generic type should we use ? extends ? extends
Some generic declarations are inherently covariant, which means they should always be used with a wildcard, for example. Iterator If Iterator used without wildcards, this is almost certainly wrong.
The problem is that wildcard syntax is so verbose that people are turned off and often forget to use it. This is widespread even in major libraries, for example. Iterable<T>.iterator() returns Iterator<T> , whereas it should return Iterator<? extends T> Iterator<? extends T> .
Ironically, Erasure can save this problem. We know that Iterator<Apple> can be safely used as Iterator<Fruit> statically, and we know that we can drop the Iterator<Apple> to Iterator<Fruit> dynamically, thanks to erasure. So just go ahead and make cattle.