Jackson 一直使用基类来反序列化 Java 泛型基类中的对象

问题描述 投票:0回答:1

标题

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),我不知道为什么它不起作用。

java generics jackson
1个回答
0
投票

我觉得这是由于编译时发生的类型擦除造成的。

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;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.