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

Java泛型与Jackson序列化问题:返回LinkedHashMap而非目标类型

问题描述

定义了泛型API响应类ApiResponse:

@Setter
@Getter
public final class ApiResponse<T> {
    private T data;
}

通过Jackson解析HTTP响应体生成ApiResponse的Converter类:

class Converter<T> {
  ApiResponse<T> create(){
     // 此步骤前有REST调用并生成httpResponse
     ApiResponse<T> apiResponse = new ApiResponse();
     T data = objectMapper
         .readValue(httpResponse.body(), new TypeReference<>() {});
     apiResponse.setData(data);
     return apiResponse;
  }
}

使用自定义对象MyObject调用时:

Converter<MyObject> converter = new Converter<>();
ApiResponse<MyObject> apiResponse = converter.create();

发现apiResponse.getData()返回的是LinkedHashMap而非MyObject类型。

MyObject类定义:

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public final class MyObject {
  @JsonProperty("childs")
  private ChildObject[] childs;
}

参考HTTP响应体:

{
  "childs": [
    {
      "freightLineId": "",
      "shipmentId": "",
      "shipmentVersionId": ""
    }
  ]
}
问题原因

Java的泛型类型擦除导致Jackson无法识别T的实际类型。在Converter的create方法中,new TypeReference<>() {}是匿名内部类,但编译后泛型T的具体类型信息会被擦除,Jackson无法知晓要将JSON反序列化为MyObject,只能默认解析成LinkedHashMap。

解决方案

方案1:传入TypeReference参数

修改Converter的create方法,由调用方提供带有实际类型信息的TypeReference:

class Converter<T> {
  ApiResponse<T> create(TypeReference<T> typeReference){
     ApiResponse<T> apiResponse = new ApiResponse();
     T data = objectMapper
         .readValue(httpResponse.body(), typeReference);
     apiResponse.setData(data);
     return apiResponse;
  }
}

调用时指定类型:

Converter<MyObject> converter = new Converter<>();
ApiResponse<MyObject> apiResponse = converter.create(new TypeReference<MyObject>() {});

方案2:传入Class参数

如果不需要处理嵌套泛型这类复杂场景,直接传入目标类的Class对象即可:

class Converter<T> {
  ApiResponse<T> create(Class<T> clazz){
     ApiResponse<T> apiResponse = new ApiResponse();
     T data = objectMapper
         .readValue(httpResponse.body(), clazz);
     apiResponse.setData(data);
     return apiResponse;
  }
}

调用时传入MyObject.class:

Converter<MyObject> converter = new Converter<>();
ApiResponse<MyObject> apiResponse = converter.create(MyObject.class);

方案3:在Converter初始化时传入类型信息

提前将类型信息注入Converter实例,避免每次调用都传参数:

class Converter<T> {
  private final TypeReference<T> typeReference;

  public Converter(TypeReference<T> typeReference) {
    this.typeReference = typeReference;
  }

  ApiResponse<T> create(){
     ApiResponse<T> apiResponse = new ApiResponse();
     T data = objectMapper
         .readValue(httpResponse.body(), typeReference);
     apiResponse.setData(data);
     return apiResponse;
  }
}

创建Converter时指定类型:

Converter<MyObject> converter = new Converter<>(new TypeReference<MyObject>() {});
ApiResponse<MyObject> apiResponse = converter.create();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 22:43:13