Generi c Реализация интерфейса с типом подкласса - PullRequest
0 голосов
/ 23 февраля 2020

Интерфейс процессора:

public interface Processor<T> {

    public void process(T request);

    public Class<T> getRequestType();
}

Реализация процессора:

public class TextProcessor extends BaseProcessor implements Processor<TextRequest> {

@Override
public void process(TextRequest request) {
    // TODO Auto-generated method stub

}

@Override
public Class<TextRequest> getRequestType() {
    // TODO Auto-generated method stub
    return TextRequest.class;
}

}

Класс запроса:

public class Request {
    private long id;

    ...
}

TextRequest

public class TextRequest extends Request {
    String text;
    ...
} 

Основной класс:

private Map<String, Processor<? extends Request>> processors;

public static void main(String[] args) {

    Processor<?> processor = processors.get("proc name");
    Request request = objectMapper.readValue(json, processor.getRequestType());

    processor.process(request);
}

Я получаю ошибку компиляции в вызове process.

The method process(capture#10-of ?) in the type Processor<capture#10-of ?> is not applicable
for the arguments (Request)

Как мне решить эту проблему?

Ответы [ 3 ]

1 голос
/ 23 февраля 2020

Итак, у вас есть

Processor<?> processor = ...;
Request request = ...;
processor.process(request);

, но process объявлен как

public void process(T request);

Request, и нельзя гарантировать, что он является подтипом T, поэтому он не будет компилироваться.

Вам нужно изменить Request на правильный тип.

Прежде всего вам нужно вернуть правильный тип класса.

public Class<?> getRequestType();

становится

public Class<T> getRequestType();

( Редактировать: Теперь это было изменено в исходном вопросе.)

Затем нам нужно прочитать объект запроса правильного типа. Для любого конкретного объекта ? здесь будет ссылаться на определенный тип. И мы можем уловить это, введя новый метод.

public static void main(String[] args) {
    doProcess(processors.get("proc name"));
}
private static <T> void doProcess(Processor<T> processor) {
    T request = objectMapper.readValue(json, processor.getRequestType());
    processor.process(request);
}
0 голосов
/ 23 февраля 2020

Процессор, который вы получаете в Processor<?> processor = processors.get("proc name");, параметризован неизвестного типа, который не имеет ничего общего с типом в processor.getRequestType(). Мне неясно, какую выгоду дженерики принесут вам в этом случае. Кажется, вам не нужно знать, что конкретно является подтипом Request в основной функции, чтобы все можно было переписать без обобщений. Причиной проблемы root является карта processors, в которой все процессоры находятся в одной связке.

Я могу представить преимущества обобщений, например, когда карта процессоров будет реализована в виде гетерогенной карты с некоторой корреляцией между ключами. тип и тип значения. Затем Processor.getRequestType должен быть параметризован типом T, тогда вы можете использовать:

public static void main(String[] args) {
    Processor<TextRequest> processor = processors.get(TextRequest.class);
    TextRequest request = objectMapper.readValue(json, processor.getRequestType());
    processor.process(request);
}
0 голосов
/ 23 февраля 2020

JAVA Обобщения проверяются во время компиляции.

Поэтому, когда вы пишете Processor<?> processor = processors.get("proc name");, мы не знаем, как проверить запрос по ?.

Если вы можете принять это - попробуйте использовать не-generi c версию процессора:

Processor processor = new TextProcessor();

В противном случае, возможно, добавьте некоторые ограничения для интерфейса Processor (void process(Request request);)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...