I have the following definition:
public interface MessageResponseHandler<T extends MessageBody> {
public void responsed(Message<T> msg);
}
public class DeviceClientHelper {
public MessageResponseHandler<? extends MessageBody> messageHandler;
setHandler(MessageResponseHandler<? extends MessageBody> h){
this.messageHandler = h;
}
public someMethod(Object message){
Message<? extends MessageBody> msg = (Message<? extends MessageBody>) message;
if (this.messageHandler != null) {
this.messageHandler.responsed(msg);
}
}
}
I couldn't figure out why in the someMethod() method, the invocation of
this.messageHandler.responsed(msg);
would give me a wired compiler error in eclipse. something like:
the method responsed(Message<capture#3-of ? extends MessageBody>) in
the type MessageResponseHandler<capture#3-of ? extends MessageBody> is
not applicable for the arguments (Message<capture#4-of ? extends
MessageBody>)
what is the "catpure" means in the error message anyway?
You're saying DeviceClientHelper has a messageHandler for some subclass of MessageBody. And someMethod has a message also for some subclass of MessageBody. However, there's nothing requiring them to be the same subclass of MessageBody, so the call to responsed is not valid.
To make them use the same subclass, make the DeviceClientHelper generic on a specific subclass of MessageBody like so:
interface MessageResponseHandler<T extends MessageBody> {
public void responsed(Message<T> msg);
}
public class DeviceClientHelper<T extends MessageBody> {
public MessageResponseHandler<T> messageHandler;
void setHandler(MessageResponseHandler<T> h){
this.messageHandler = h;
}
public void someMethod(Object message){
Message<T> msg = (Message<T>) message;
if (this.messageHandler != null) {
this.messageHandler.responsed(msg);
}
}
}
However, your MessageResponseHandler interface probably doesn't need to care about the MessageBody class. This depends on how it's actually used, but something like this might work better:
interface MessageResponseHandler {
public void responsed(Message<? extends MessageBody> msg);
}
And then you can remove the generic type from the messageHandler field and keep the original someMethod implementation.
This is a common pitfall when using generics; despite your messageHandler and msg objects looking to be the same, they really aren't (or rather, they do not necessarily have to be). Consider this:
class M1 extends MessageBody { ... }
class M2 extends MessageBody { ... }
MessageHandler<? extends MessageBody> handler = new MessageHandler<M1>();
/* So far so good */
Message<? extends MessageBody> message = new M2();
/* Still OK */
handler.responded(message);
/* Huh... you don't want to allow this, right? */
If your handler is only able to handle one specific kind of messages, then your DeviceClientHelper should only receive this specific kind of messages too, right? How about something like this?
public class DeviceClientHelper<T extends MessageBody> {
public MessageResponseHandler<T> messageHandler;
setHandler(MessageResponseHandler<T> h){
this.messageHandler = h;
}
public someMethod(Object message){
Message<T> msg = (Message<T>) message;
if (this.messageHandler != null) {
this.messageHandler.responsed(msg);
}
}
}
(this will most probably produce a warning about unchecked cast)
Or better yet:
public class DeviceClientHelper<T extends MessageBody> {
public MessageResponseHandler<T> messageHandler;
setHandler(MessageResponseHandler<T> h){
this.messageHandler = h;
}
public someMethod(T message){
if (this.messageHandler != null) {
this.messageHandler.responsed(message);
}
}
}
If your DeviceClientHelper is supposed to contain handlers handling different types of messages (for example, it initially contains a handler for M1, but then you assign a handler for M2), and still you want it to be validated by generics, I am afraid you are out of luck; this would require the generics to be checked at runtime instead of compile time, and Java does not support it due to generics' type erasure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With