Reputation: 43
I am getting a bound mismatch error when using a self-referring type in a generic method, but not in a generic class declaration; here is an example of the faulty code:
public class Container {
public static class User<X> {} // line 1
public static class Box<U extends User<Box<U>>> {} // line 2
public static class NiceBox<U extends User<Box<U>>> {} // line 3: OK
<U extends User<Box<U>>> void niceMethod(U user) {} // line 4: NOT OK
}
Compile error message on line 4: Bound mismatch: The type
U
is not a valid substitute for the bounded parameter< U extends Container.User<Container.Box<U>>>
of the typeContainer.Box<U>
I don't understand why, thanks in advance for any help, SC
PS: Note that differently from previously asked questions, the problem presented here exists only with generic methods, the compiler accepts the problematic type bound when used within a generic class declaration.
I am using the compiler for Java 11 coming with the latest Eclipse distribution.
Here are more details on what I am trying to achieve. I am building a Box that needs to execute some work on a target of type T within a context of type C, where this context C must satisfy a minimal interface. Then I need to define methods to process a Box (hence the need for a generic method with the self-referring type bound). Here is the code:
static class Box<T,C extends MinimalContext<Box<T,C>>> {
void doSomething(T target, C context) {
// do something
}
}
interface MinimalContext<B> {
boolean validate(B box);
void print(B box);
}
// FAILS:
<T,C extends MinimalContext<Box<T,C>>>
void processBox(Box<T,C> box) {}
// Instead use:
class BoxProcessor<T,C extends MinimalContext<Box<T,C>>>
{
BoxProcessor(Box<T,C> box) {
// use box as niceMethod would do
}
}
Note that since the limitation exists only for generic method and not for classes, I am using an inner class to do the work of the generic method...any other solutions?
Could someone from the eclipse developers say more about this limitation?
Upvotes: 2
Views: 284
Reputation: 3580
It seems this is either a limitation of, or higher level of strictness from the Eclipse compiler. javac
accepts that code fine.
In Eclipse you could write:
public static class User<T> {}
public static class Box<T extends User<Box<T>>> {}
<T extends User<Box<?>>> void niceMethod(T user) {}
You can then declare a class:
static class UserBox extends User<Box<?>> {}
And Eclipse will allow you to:
public static void main(String[] args)
{
Container c = new Container();
c.niceMethod(new UserBox());
}
But then it won't let you create a concrete Box
. E.g:
Box<UserBox> b = new Box<>();
Is not allowed by Eclipse, but is by javac
.
I suspect Eclipse might be doing the right thing, because you are saying:
"Box
takes a type parameter of a class that extends a User
with a type parameter of a Box which has a type parameter of the type we are extending." Which sounds impossible to me, but there could be something I'm missing.
EDIT (since the question was updated to show the interface):
Rather than define the interface as completely generic and try to restrict the context types in the definition of Box
could you instead define a more restrictive interface, such as:
interface BoxContext<B extends Box<?, ?>> {
boolean validate(B box);
void print(B box);
}
You can then remove the self-referential generics from your definition of Box
:
static class Box<T, C extends BoxContext<?>> {
void doSomething(T target, C context) {
// do something
}
}
Which then allows you to define your method:
<T, C extends BoxContext<?>> void processBox(Box<T, C> box) {}
Upvotes: 1