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

lyfkaqu1  于 12个月前  发布在  Java
关注(0)|答案(1)|浏览(243)

标题

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


concreate类是:

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)?!
Jackson工作正常,如下所示,如果我使用MyResult类创建TypeReference:

TypeReference<MyResult> typeRef = new TypeReference<MyResult>() {};
return JacksonFunctions.jacksonObjectMapper.readValue(jsonString, typeRef);


作为一种变通方法,我可以把上面的代码带到MyAction,它会工作得很好。
但是由于BaseAction已经有RT(作为MyResult),我不知道为什么它不工作。

8dtrkrch

8dtrkrch1#

我觉得这是由于在编译时发生的类型擦除。BaseActionTypeReference<RT> typeRef = new TypeReference<RT>() {}中的这一行将只有“BaseResult的子类”的“内存”,而不是哪个特定的子类。由于每个子类可能有不同的结构,因此您不能安全地将父类转换为它。
因此,您可以:

  • 提供一个DeserializerBaseResult,它将处理不同的实现,或者
  • 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());
    }
}

个字符

相关问题