我正在构建一个客户端/服务器应用程序,并将请求和响应消息封装在如下所示的通用Java类中:
@SuperBuilder
@Jacksonized
@Getter
@Setter
public class AppResponse<T extends AppResponse.Results> {
public static final String SUCCESS_ATTRIBUTE = "success";
public static final String MESSAGE_ATTRIBUTE = "message";
public static final String REQUEST_ID_ATTRIBUTE = AppRequest.REQUEST_ID_ATTRIBUTE;
public static final String RESULTS_ATTRIBUTE = "results";
@JsonProperty(SUCCESS_ATTRIBUTE)
boolean success;
@JsonProperty(MESSAGE_ATTRIBUTE)
String message;
@JsonProperty(REQUEST_ID_ATTRIBUTE)
String requestID;
@JsonProperty(RESULTS_ATTRIBUTE)
T results;
@SuperBuilder
@Jacksonized
@Getter
@Setter
public static class Results {
}
}
然后我有一个扩展AppResponse的类。每个命令响应包的结果可以通过网络发送。例如:
@SuperBuilder
@Getter
@Setter
@Jacksonized
public class AppCreateForumPostResults extends AppResponse.Results {
@JsonProperty("id")
UUID id;
}
因此,当服务器使用Jackson将其编码为JSON时,我会得到一个如下所示的JSON文档:
{
"success" : true,
"requestID" : "eL55P4Sz",
"results" : {
"id" : "0b48d389-2407-43c4-ad1b-ab52599c2d7f"
}
}
当客户端应用程序收到此消息时,它首先将其解码为ObjectNode:
objectNode = (ObjectNode) AppObjectMapper.OBJECT_MAPPER.readTree(message);
然后将其解码为泛型对象,因为它还不知道泛型的具体类型是什么:
JavaType genericType = AppObjectMapper.OBJECT_MAPPER.getTypeFactory().constructParametricType(
AppResponse.class,
AppResponse.Results.class
);
AppResponse<AppResponse.Results> genericResponse = AppObjectMapper.OBJECT_MAPPER.treeToValue(
objectNode,
genericType
);
然后,它查询已发送的requestID的HashMap,以找出它应该期望的结果类类型。
private final Map<String, CallbackEntry<? extends AppResponse.Results>> callbacks = new HashMap<>();
而CallbackEntry定义为:
@Builder
@Value
public static class CallbackEntry<T extends AppResponse.Results> {
Callback<T> method;
Class<T> resultsClass;
}
最后,Callback定义为:
public interface Callback<T extends AppResponse.Results> {
void handleResponse(AppResponse<T> results);
}
因此,一旦我们在HashMap中找到了requestID,我们就知道结果包含什么具体类,并且可以对其进行解码:
CallbackEntry<? extends AppResponse.Results> callbackEntry = callbacks.get(genericResponse.getRequestID());
callbacks.remove(genericResponse.getRequestID());
JavaType concreteType = AppObjectMapper.OBJECT_MAPPER.getTypeFactory().constructParametricType(
AppResponse.class,
callbackEntry.resultsClass
);
AppResponse<? extends AppResponse.Results> concreteResponse = AppObjectMapper.OBJECT_MAPPER.treeToValue(
objectNode,
concreteType
);
到目前为止,一切都很好。这一切都和预期的一样。如果我打印出concreteResponse对象,它里面的数据完全正确。但是,当我去实际调用回调方法时,我得到了一个错误。调用如下所示:
callbackEntry.method.handleResponse(concreteResponse);
我在这行代码中得到的错误是:
[127,49] incompatible types: com.whatever.app.common.AppResponse<capture#1 of ? extends com.whatever.app.common.AppResponse.Results> cannot be converted to com.whatever.app.common.AppResponse<capture#2 of ? extends com.whatever.app.common.AppResponse.Results>
我对这个错误信息感到有点困惑。我猜它一定与处理泛型的方式有关,但我就是想不出正确的咒语是什么。我在谷歌上搜索了很多次,到处都发现了类似的错误,但它们通常是由于有人使用了?而不是T,(我认为)这里不是这样。
那么,我错过了什么?
任何帮助都将不胜感激!
1条答案
按热度按时间cunj1qz11#
我可以通过如下转换函数参数来实现:
这会显示未检查工作分派的警告,但它可以运作。