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

Java ObjectMapper.readValue泛型反序列化返回LinkedHashMap的解决方法

问题原因

该类型转换问题由Java泛型擦除 + Jackson反序列化类型信息丢失共同导致:

  • 代码中new TypeReference<>(){}使用了钻石运算符,运行时泛型参数T会被擦除,Jackson无法获取要反序列化的目标类型,默认会将JSON对象反序列化为LinkedHashMap类型
  • 传入的泛型实例t本身未携带运行时类型信息,无法帮助Jackson确定目标反序列化类型

修复方案

方案1:传入Class类型参数(最适配当前场景)

直接把目标类的Class对象作为参数传入,Jackson可以直接通过Class获取完整类型信息,修改后的代码如下:

@Service
public class PokemonManager implements PokemonService {

    // 建议将ObjectMapper提为类单例成员,避免每次方法调用重复创建,提升性能
    private final ObjectMapper objectMapper = new ObjectMapper();

    private HttpResponse<String> getStringHttpResponseByUrl(final String url) {
        HttpClient httpClient = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .GET().header("accept", "application/json")
                .uri(URI.create(url)).build();
        HttpResponse<String> httpResponse = null;
        try {
            httpResponse = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        return httpResponse;
    }

    // 修改方法签名,传入Class<T>替代原实例参数
    private <T> T getObjectResponse(Class<T> clazz, String url) {
        try {
            HttpResponse<String> response = getStringHttpResponseByUrl(url);
            // 补充空值判断避免空指针
            if (response == null || response.body() == null) {
                return null;
            }
            return objectMapper.readValue(response.body(), clazz);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }

    private List<Pokemon> getAllPokemonsAsList() {
        final String POSTS_API_URL = "https://pokeapi.co/api/v2/pokemon?limit=10000";
        // 调用时传入目标类的Class对象即可
        PokeApiResponse pokeApiResponse = getObjectResponse(PokeApiResponse.class, POSTS_API_URL);
        System.out.println(pokeApiResponse);
        return pokeApiResponse.results;
    }

    @Override
    public List<Pokemon> getAll() {
        return getAllPokemonsAsList();
    }
}

方案2:传入TypeReference参数(适配嵌套泛型场景)

如果后续需要反序列化带泛型的复杂类型(比如直接反序列化为List<Pokemon>),可以直接把TypeReference作为参数传入:

// 方法定义
private <T> T getObjectResponse(TypeReference<T> typeReference, String url) {
    try {
        HttpResponse<String> response = getStringHttpResponseByUrl(url);
        if (response == null || response.body() == null) {
            return null;
        }
        return objectMapper.readValue(response.body(), typeReference);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
        return null;
    }
}

// 调用处显式指定TypeReference的泛型参数
private List<Pokemon> getAllPokemonsAsList() {
    final String POSTS_API_URL = "https://pokeapi.co/api/v2/pokemon?limit=10000";
    PokeApiResponse pokeApiResponse = getObjectResponse(new TypeReference<PokeApiResponse>() {}, POSTS_API_URL);
    System.out.println(pokeApiResponse);
    return pokeApiResponse.results;
}

额外优化建议:getStringHttpResponseByUrl方法遇到异常时会返回null,建议补充更完善的异常抛出逻辑,避免上层调用出现无感知的空指针问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 04:36:02