Jackson 未能反序列化 Java 泛型基类中的对象。
我想将 JSON 反序列化为 Java 通用基类中的对象,但出现异常:
ClassCastException: class BaseResult cannot be cast to class MyResult (BaseResult and MyResult are in unnamed module of loader 'app')
例外情况如下:
public abstract class BaseAction<IT extends BaseInput, RT extends BaseResult> {
public RT execute(final IT inObj) throws Exception {
//...
TypeReference<RT> typeRef = new TypeReference<RT>() {};
return JacksonFunctions.jacksonObjectMapper.readValue(jsonString, typeRef); //ClassCastException!!
}
以下是类定义。
BaseInput.java
public abstract class BaseInput {
}
BaseResult.java
@Data
@NoArgsConstructor
public class BaseResult {
@JsonProperty("ErrorCode")
private int errorCode = 0;
@JsonProperty("ErrorMessage")
private String errorMessage = "";
}
BaseAction.java
public abstract class BaseAction<IT extends BaseInput, RT extends BaseResult> {
public RT execute(final IT inObj) throws Exception {
//...
TypeReference<RT> typeRef = new TypeReference<RT>() {};
return JacksonFunctions.jacksonObjectMapper.readValue(jsonString, typeRef); //ClassCastException!!
}
}
具体类是:
MyInput.java
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class MyInput extends BaseInput {
private String title;
}
MyResult.java
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class MyResult extends BaseResult {
@JsonProperty("Title")
private String title;
@JsonProperty("Description")
private String description;
}
MyAction.java
public class MyAction extends BaseAction<MyInput, MyResult> {
}
程序运行如下:
MyInput inObj = new MyInput();
inObj.setTitle("Galaxy");
MyAction act = new MyAction();
MyResult resObj = act.execute(inObj); //exception here!
我的问题是,MyResult(作为RT)被传递给通用基类MyAction,在BaseAction类(MyResult作为RT)中使用应该可以。但是为什么 Jackson 不能将 RT 作为 MyResult 来反序列化 JSON 字符串,而是作为 BaseResult (因此出现 ClassCastException)?!
如果我使用 MyResult 类创建 TypeReference,Jackson 工作正常,如下所示:
TypeReference<MyResult> typeRef = new TypeReference<MyResult>() {};
return JacksonFunctions.jacksonObjectMapper.readValue(jsonString, typeRef);
作为解决方法,我可以将上面的代码带到 MyAction,它会正常工作。
但是由于BaseAction已经有RT(如MyResult),我不知道为什么它不起作用。
我觉得这是由于编译时发生的类型擦除造成的。
BaseAction
类TypeReference<RT> typeRef = new TypeReference<RT>() {}
中的这一行将仅具有“BaseResult
的子类”的“记忆”,而不是which特定子类的“记忆”。由于每个子项可能具有不同的结构,因此您无法安全地将父项强制转换为它。
因此,您可以:
Deserializer
到 BaseResult
,它将处理不同的实现,或者BaseResult
中提供一个抽象方法来获取实现的类型。这可以传递给readValue(..)
而不是TypeReference<..>
,如下所示(未编译或测试,仅用于说明想法):public abstract class BaseAction<IT extends BaseInput, RT extends BaseResult> {
/* Method to the get the actual type */
protected Class<RT> getImplClass();
public RT execute(final IT inObj) throws Exception {
//...
return JacksonFunctions.jacksonObjectMapper.readValue(jsonString, getImplClass());
}
}
public class MyAction extends BaseAction<MyInput, MyResult> {
protected Class<MyResult> getImplClass(){
return MyResult.class;
}
}