Jackson泛型方法数据解析异常:java.util.LinkedHashMap无法转换为自定义类问题求助
你遇到的ClassCastException核心原因是Java的泛型类型擦除机制。当你在doNestedListGet方法中使用new TypeReference<PageWrapper<List<T>>>()时,编译后泛型参数T的实际类型会被擦除,Jackson在运行时无法知道T具体是WBEmployee,只能默认将JSON数组反序列化为LinkedHashMap的列表,这就导致后续你尝试把这些LinkedHashMap强转为WBEmployee时抛出异常。
而本地测试能正常运行,是因为你直接创建了具体的TypeReference<PageWrapper<List<WBEmployee>>>()——匿名内部类会保留泛型类型的元数据,Jackson可以正确识别出要反序列化为WBEmployee列表。
方案1:让调用方传入具体的TypeReference
修改doNestedListGet方法,让调用方明确传入包含具体泛型类型的TypeReference,这样Jackson就能获取到准确的类型信息:
@Override public <T> PageWrapper<List<T>> doNestedListGet(TypeReference<PageWrapper<List<T>>> typeRef, HttpUrl url) throws IOException { var req = this.reqBuilder.url(url).build(); try (var res = this.webClient.newCall(req).execute()) { if (!res.isSuccessful()) { throw new IOException(String.format("API call failed: %s", res)); } var jString = res.body().string(); return this.mapper.readValue(jString, typeRef); } }
然后在getList方法中调用时传入具体的TypeReference:
public List<WBEmployee> getList(int page, WBEmploymentStatus employmentStatus) throws IOException { var url = this.baseEndpoint.newBuilder() .addQueryParameter("page", String.valueOf(page)) .addQueryParameter("status", employmentStatus.getDescr()).build(); return this.wbClient.doNestedListGet( new TypeReference<PageWrapper<List<WBEmployee>>>() {}, url ).getPgData(); }
方案2:利用Jackson的TypeFactory构造具体类型
如果你不想修改调用方的代码,可以在doNestedListGet内部,通过传入的Class<T>结合Jackson的TypeFactory来构造准确的JavaType,避免类型擦除的影响:
@Override public <T> PageWrapper<List<T>> doNestedListGet(Class<T> type, HttpUrl url) throws IOException { var req = this.reqBuilder.url(url).build(); try (var res = this.webClient.newCall(req).execute()) { if (!res.isSuccessful()) { throw new IOException(String.format("API call failed: %s", res)); } var jString = res.body().string(); // 先构造List<T>的类型 JavaType listType = mapper.getTypeFactory().constructCollectionType(List.class, type); // 再构造PageWrapper<List<T>>的类型 JavaType wrapperType = mapper.getTypeFactory().constructParametricType(PageWrapper.class, listType); return this.mapper.readValue(jString, wrapperType); } }
这种方式下,原来的getList方法不需要任何修改,因为我们内部已经通过Class<T>构建了正确的泛型类型。
你的PageWrapper类中的@JsonAlias注解是正确的配置,它能处理不同API返回的不同key(比如documents/employees/some_key),这个不是导致问题的原因,无需修改。
内容的提问来源于stack exchange,提问作者KellyM

