First of all let's make a few things clear. Your first CONFIG_ELEMENTS.put...
is equivalent to (just making sure you understand this).
CONFIG_ELEMENTS.put(
BooleanValue.class,
element -> {
new BooleanElement((ConfigElement<Boolean, BooleanValue>) element);
return;
}
);
Now the CONFIG_ELEMENTS
map that you declare, knows that the value it holds is of type Element
, that is the above can be written as:
CONFIG_ELEMENTS.put(
BooleanValue.class,
(Element element) -> {
new BooleanElement((ConfigElement<Boolean, BooleanValue>) element);
return;
}
);
that is why the only way to make this work is to cast that element
; because it is of type Element
, but your BooleanElement
takes a ConfigElement
as input. That should be obvious.
The second CONFIG_ELEMENTS.put...
explanation has to start with this:
private static class EnumElement<T extends Enum<T>> extends ConfigElement<T, ConfigValue<T>> {
EnumElement(ConfigElement<T, ? extends ConfigValue<T>> value) {
}
}
Notice the ? extends ConfigValue<T>> value
part. You need that because generics are invariant, so in order to be able to pass something that extends ConfigValue
, you need to properly declare the parameter type.
The rest of the explanation is my pure educated guessing, because I don't truly understand what is going on here (I have some hints that this has something to do with using raw types and the fact that T
from EnumElement
and T
from EnumValue
are different type variables)...
The easiest way to make this work, IMO, is to change this:
private static class EnumValue<T extends Enum> extends ConfigValue<T> {}
to using a raw Enum
.
EDIT
Here is full example that was requested in comments:
public class DeleteMe {
private static final Map<Class<?>, Consumer<Element>> CONFIG_ELEMENTS = new HashMap<>();
static {
CONFIG_ELEMENTS.put(BooleanValue.class, element -> new BooleanElement((ConfigElement<Boolean, BooleanValue>) element));
CONFIG_ELEMENTS.put(EnumValue.class,
element -> new EnumElement<>((ConfigElement<Enum, EnumValue<Enum>>) element)); // doesn't compile
}
private static class BooleanValue extends ConfigValue<Boolean> {}
private static class BooleanElement extends ConfigElement<Boolean, BooleanValue> {
BooleanElement(ConfigElement<Boolean, BooleanValue> value) {}
}
private static class ConfigValue<T> {
}
private static class EnumValue<TT extends Enum> extends ConfigValue<TT> {}
private static class Element {}
private static class ConfigElement<S, T extends ConfigValue<S>> extends Element {}
static class EnumElement<T extends Enum<T>> extends ConfigElement<T, ConfigValue<T>> {
EnumElement(ConfigElement<T, ? extends ConfigValue<T>> value) {
}
private T e;
public void setE(T e) { this.e = e; }
public T getE() { return e; }
}
static public void main(String... args) {
EnumValue<Foo> ev = new EnumValue<>();
ConfigElement<Foo, EnumValue<Foo>> ce = new ConfigElement<>();
EnumElement<Foo> ee = new EnumElement<>(ce);
ee.setE(Foo.BAR);
Foo bar = ee.getE();
System.out.println(bar);
Consumer<Element> c = CONFIG_ELEMENTS.get(ev.getClass());
c.accept(ee);
}
enum Foo {
BAR
}
}