Created
March 29, 2018 07:52
-
-
Save odrotbohm/a52c430f84d4f70fcda6cb494dc15981 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Sample { | |
public static void main(String[] args) { | |
Foo<? extends Bar<?>> foo = new Foo<>(); | |
// Compiles | |
Iterable<?> first = foo.someMethod(); | |
DedicatedWrapper<? extends Bar<?>> dedicatedWrapper = foo.someOtherMethod(); | |
// Does not compile: | |
// Type mismatch: cannot convert from Iterable<Sample.SomeWrapper<capture#2-of ? extends Sample.Bar<?>>> | |
// to Iterable<Sample.SomeWrapper<? extends Sample.Bar<?>>> | |
Iterable<SomeWrapper<? extends Bar<?>>> second = foo.someMethod(); | |
} | |
static class Foo<B extends Bar<B>> { | |
Iterable<SomeWrapper<B>> someMethod() { | |
return Collections.emptySet(); | |
} | |
DedicatedWrapper<B> someOtherMethod() { | |
return null; | |
} | |
} | |
interface Bar<B extends Bar<B>> {} | |
interface SomeWrapper<B extends Bar<B>> {} | |
interface DedicatedWrapper<B extends Bar<B>> extends Iterable<SomeWrapper<B>> {} | |
} |
Foo<B extends Bar<B>>
is kinda weird imo. What would even be a valid type for B
besides ?
?
If you could change declaration of Foo
to Foo<B extends Bar<?>>
then it compiles as expected.
It's needed to allow the following:
interface Foo<B extends Bar<B>> {
B someMethod();
}
class ConcreteB implements Bar<ConcreteB> { … }
Foo<ConcreteB> foo = …
ConcreteB b = foo.someMethod();
I.e. it allows defining methods that will return a dedicated suptype of the generic type declared. Intensively used in Spring Data, just simplified here.
Can't you capture the parameter like this?
public static void main(String[] args) {
Foo<? extends Bar<?>> foo = new Foo<>();
capture(foo);
}
public static <B extends Bar<B>> void capture(Foo<B> foo) {
Iterable<SomeWrapper<B>> second = foo.someMethod();
// do something with second
}
I think it boils down to the fact that the compiler doesn't know that the first and second ?
in this line refer to the same thing Foo<? extends Bar<?>> foo = new Foo<>();
In the past when I've had this kind of problem I've extracted the method and added a real generic:
public static void main(String[] args) {
typed();
}
private static <T extends Bar<T>> void typed() {
Foo<T> foo = new Foo<>();
// Compiles
Iterable<?> first = foo.someMethod();
DedicatedWrapper<T> dedicatedWrapper = foo.someOtherMethod();
// Compiles
Iterable<SomeWrapper<T>> second = foo.someMethod();
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Can't claim I understand what's going on and don't know if it helps, but my IDE suggests:
I also have a hunch that it might be related to https://stackoverflow.com/q/46050311/66686