You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

泛型类获取实际类型对象及fromJson报ClassCastException原因

问题:LinkedHashMap无法转为QueryOrderInfo对象的原因分析

我遇到如下报错:
Caused by: java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.test.QueryOrderInfo

场景是需要将JSON字符串bizContent解析为QueryOrderInfo对象。

更新说明:新增fromJson2()方法后可以正常运行,但疑惑为什么fromJson()方法会抛出异常。


代码示例

主方法代码

public static void main(String[] args) {
    BaseResponse<QueryOrderInfo> queryOrderInfoBaseResponse = null;
    try {
        queryOrderInfoBaseResponse = new ObjectMapper().readValue("{\"returnCode\":\"SUCCESS\",\"biz_content\":\"{\\\"mchReserved\\\":\\\"1\\\",\\\"cmbOrderId\\\":\\\"900119022715203210134445\\\",\\\"dscAmt\\\":\\\"0\\\",\\\"payType\\\":\\\"ZF\\\",\\\"orderId\\\":\\\"9001004180329103417277\\\",\\\"txnTime\\\":\\\"20190227152032\\\",\\\"merId\\\":\\\"3089991701207X7\\\",\\\"currencyCode\\\":\\\"156\\\",\\\"txnAmt\\\":\\\"1\\\",\\\"tradeState\\\":\\\"S\\\"}\",\"sign\":\"kGE7mwX/ubRlPsPZGNydjY3uCjILgGuxD4j1e/inyC/DlHn5o7LkISpmrH0YQvoZT6lyOxtr9uIkKnqVcTMZNYeYIBU+Tz8NRaPZHuFr/qQb0+fUgEgq5j9ovaFczAF8wrnEfIRYBEqp0ERtK7NG+X6eZLIr9nNVy31eKcnFx1tToJ/zPYN91GOKOtTrJaJrKeDY4+r3ctzsDhnD+TO2MX5zfvW0WLoUjvX5geiYLVpt022BiyxSJyOsrDS858RBmZ5FbVlYP0v/WqwX+J8VY1kDSLxvPtSZuPnsluJPXw6ccnYNH8dir0VgrYfrWRvnupctIm2elCmL7ES6KzDTGg==\",\"encoding\":\"UTF-8\",\"version\":\"0.0.1\",\"signMethod\":\"01\",\"respCode\":\"SUCCESS\"}", new TypeReference<BaseResponse<QueryOrderInfo>>() {
        });
        QueryOrderInfo queryOrderInfo = queryOrderInfoBaseResponse.fromJson();
        QueryOrderInfo queryOrderInfo2 = queryOrderInfoBaseResponse.fromJson2(QueryOrderInfo.class);
    } catch (JsonProcessingException e) {
        throw new RuntimeException(e);
    }
}

BaseResponse类

@NoArgsConstructor
@Data
public class BaseResponse<T> {

    private String returnCode;
    @JsonProperty(value = "biz_content")
    private String bizContent;
    private String sign;
    private String encoding;
    private String version;
    private String signMethod;
    private String respCode;

    private String errCode;
    private String respMsg;

    public T fromJson() {
        try {
            return new ObjectMapper().readValue(this.bizContent, new TypeReference<T>() {
            });
        } catch (JsonProcessingException e) {
            return null;
        }
    }

    public T fromJson2(Class<T> clazz) {
        try {
            return new ObjectMapper().readValue(this.bizContent, clazz);
        } catch (JsonProcessingException e) {
            return null;
        }
    }
}

QueryOrderInfo类

@NoArgsConstructor
@Data
public class QueryOrderInfo {

    private String mchReserved;
    private String cmbOrderId;
    private String dscAmt;
    private String payType;
    private String orderId;
    private String txnTime;
    private String merId;
    private String currencyCode;
    private String txnAmt;
    private String tradeState;
}

原因分析

核心问题是Java泛型的类型擦除机制:

  • 编译时BaseResponse<T>中的泛型参数T会被保留,但运行时JVM会擦除泛型信息,T会被替换为Object。这意味着fromJson()方法里的new TypeReference<T>() {}无法在运行时获取到具体的QueryOrderInfo类型,Jackson没有明确的目标类型信息,只能将JSON字符串解析为默认的LinkedHashMap对象。当你尝试把这个LinkedHashMap强转为QueryOrderInfo时,就会触发ClassCastException。
  • 而fromJson2(Class<T> clazz)方法直接传入了具体的Class对象,Jackson可以通过这个对象明确知道要解析的目标类型,因此能正确生成QueryOrderInfo实例,不会出现类型转换异常。

额外优化建议

  • 避免在方法内重复创建ObjectMapper实例,ObjectMapper是线程安全的,可以全局复用一个实例,提升性能。
  • 如果想保留fromJson()的写法,可以在BaseResponse初始化时传入TypeReference或Class对象并保存,这样运行时就能获取到具体类型信息。

内容的提问来源于stack exchange,提问作者Holinc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 04:55:53