У меня есть следующий сценарий:
public interface BaseConfig {
}
public abstract class BaseWidget<C extends BaseConfig> {
public abstract C getConfig();
public abstract void setConfig(C config);
public abstract Class<C> getConfigClass();
}
public class ConcreteConfig implements BaseConfig {
public String foo = "bar";
}
public class ConcreteWidget extends BaseWidget<ConcreteConfig> {
private ConcreteConfig config;
public ConcreteWidget(ConcreteConfig config) {
this.config = config;
}
@Override
public ConcreteConfig getConfig() {
return config;
}
@Override
public void setConfig(ConcreteConfig config) {
this.config = config;
}
@Override
public Class<ConcreteConfig> getConfigClass() {
return ConcreteConfig.class;
}
}
Я хочу иметь возможность обобщенно сериализовать и десериализовать экземпляры BaseConfig
в правильный тип, заданный реализациями BaseWidget
. Следующие работы:
final BaseWidget<ConcreteConfig> instance = new ConcreteWidget(new ConcreteConfig());
final BaseConfig config = instance.getConfig();
final String configJson = om.writeValueAsString(config);
instance.setConfig(om.readValue(configJson, instance.getConfigClass()));
Теперь, если я попытаюсь сделать приведенный выше код универсальным (исключить вхождение ConcreteConfig
, поэтому первая строка имеет тип BaseWidget<? extends BaseConfig>
), я получу следующую ошибку компиляции в последней строке:
Ошибка: (18, 40) Java: несовместимые типы: BaseConfig не может быть преобразован в захват # 1 из? расширяет BaseConfig
или в IntelliJ:
setConfig (capture <? Extends BaseConfig>) в BaseWidget не может быть применен к (capture <? Extends BaseConfig>)
Я понимаю, что ошибка говорит мне, что два захвата несовместимы, но почему это так? Насколько я понимаю, типы instance.setConfig(C)
и instance.getConfigClass() -> Class<C>
должны приводить к одним и тем же C
, поскольку они происходят из одного и того же экземпляра.
Я мог бы обойти эту проблему, задав BaseWidget
другой метод вместо setConfig
, как этот.
public abstract void readConfig(ObjectMapper mapper, String rawConfig) throws IOException;
и реализовать это следующим образом: ConcreteWidget
:
@Override
public void readConfig(ObjectMapper mapper, String rawConfig) throws IOException {
this.config = mapper.readValue(rawConfig, ConcreteConfig.class);
}
но я бы предпочел, чтобы виджет не зависел от логики сериализации.
Вот мой тестовый проект maven: https://drive.google.com/open?id=16zt2FC8Gs5Cke-kbYBDRhmytE5utVn8E