cppcoder
cppcoder

Reputation: 23105

Generic Interface implementation with subclass type

Processor interface:

public interface Processor<T> {

    public void process(T request);

    public Class<T> getRequestType();
}

Processor implementation:

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;
}

}

Request class:

public class Request {
    private long id;

    ...
}

TextRequest

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

Main class:

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);
}

I am getting compilation error in the process call.

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

How can I resolve this issue?

Upvotes: 1

Views: 155

Answers (3)

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147154

So you've got

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

but process is declared as

public void process(T request);

Request cannot be guaranteed to be a subtype of T, therefore it will not compile.

You need to change Request to the correct type.

First of all you need need to return the right type of class.

public Class<?> getRequestType();

becomes

public Class<T> getRequestType();

(Edit: This has now been modified in the original question.)

Then we need to read an request object of the correct type. For any particular object ? here will refer to a particular type. And we can capture that by introducing a new method.

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);
}

Upvotes: 1

The processor you get in Processor<?> processor = processors.get("proc name"); is parameterized of unknown type which has nothing common with the type in processor.getRequestType(). It is unclear to me what benefit generics bring to you in this case. It seem you don't have to know what is concrete Request subtype in main function so everything could be rewritten without generics. The root cause of problem is the processors map where all processors are in one bunch.

I can imagine benefits of generics for example when the processor map would be implemented as heterogenous map with some correlation between key type and value type. The Processor.getRequestType would then have to be parametrized by type T too, then you could use:

public static void main(String[] args) {
    Processor<TextRequest> processor = processors.get(TextRequest.class);
    TextRequest request = objectMapper.readValue(json, processor.getRequestType());
    processor.process(request);
}

Upvotes: 0

Witek
Witek

Reputation: 135

JAVA generics are checked at compile time.

So when you write Processor<?> processor = processors.get("proc name"); we don't know how to validate request against ?.

If you can accept this - try with non-generic version of processor:

Processor processor = new TextProcessor();

Otherwise maybe add some constraints for Processor interface (void process(Request request);)?

Upvotes: 0

Related Questions