如何用Jackson反序列化器解析JAX-RS Response中的Spring Data Page
通用解决Spring Data Page Jackson反序列化问题
问题核心
自定义Jackson Page反序列化器时,createContextual方法中wrapperType.containedType(0)返回null,无法自动识别content的泛型类型,导致无法通用解析不同类型的content(如EtudeDto、EtudeOptique)。
解决方案
1. 修正泛型类型获取逻辑
调整反序列化器中获取泛型参数的方式,从BeanProperty或上下文JavaType中正确提取content的类型:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.deser.ContextualDeserializer; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import java.io.IOException; import java.util.List; public class PageDeserializer extends JsonDeserializer<Page<?>> implements ContextualDeserializer { private JavaType contentJavaType; @Override public Page<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); JsonNode contentNode = node.get("content"); // 用预获取的泛型类型解析content列表 List<?> content = ctxt.readValue(contentNode.traverse(p.getCodec()), contentJavaType); int pageNumber = node.get("number").asInt(); int pageSize = node.get("size").asInt(); long totalElements = node.get("totalElements").asLong(); return new PageImpl<>(content, PageRequest.of(pageNumber, pageSize), totalElements); } @Override public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException { PageDeserializer deserializer = new PageDeserializer(); // 优先从BeanProperty提取泛型 if (property != null) { JavaType wrapperType = property.getType(); deserializer.contentJavaType = wrapperType.containedType(0); } else { // 无BeanProperty时,从上下文获取当前解析的泛型类型 JavaType currentType = ctxt.getContextualType(); if (currentType != null && currentType.isContainerType()) { deserializer.contentJavaType = currentType.containedType(0); } } // 兜底校验,避免空指针 if (deserializer.contentJavaType == null) { throw new JsonMappingException(null, "无法识别Page的泛型类型,请确保反序列化时指定具体的Page<XXX>类型"); } return deserializer; } }
2. 注册反序列化器并明确泛型类型
解析时必须通过TypeReference指定具体的Page<XXX>类型,不能直接用Page.class:
ObjectMapper objectMapper = new ObjectMapper(); // 注册自定义反序列化器 SimpleModule module = new SimpleModule(); module.addDeserializer(Page.class, new PageDeserializer()); objectMapper.registerModule(module); // 解析为Page<EtudeDto> String json = "..."; // 你的JSON响应内容 Page<EtudeDto> etudePage = objectMapper.readValue(json, new TypeReference<Page<EtudeDto>>() {}); // 解析为Page<EtudeOptique> Page<EtudeOptique> optiquePage = objectMapper.readValue(json, new TypeReference<Page<EtudeOptique>>() {});
3. 适配标准Page JSON结构
确保Web服务返回的JSON符合Spring Data Page的标准格式,示例:
{ "content": [ {"id": 1, "name": "示例EtudeDto"}, {"id": 2, "name": "示例EtudeDto2"} ], "number": 0, "size": 2, "totalElements": 5, "totalPages": 3, "first": true, "last": false, "empty": false }
关键注意点
- 必须使用
TypeReference传递具体泛型,Jackson才能在createContextual中识别content类型。 - 如果JSON中content字段名不是
content,需在反序列化器中修改node.get("content")的字段名。 - 兜底异常用于快速定位未指定泛型的错误场景。
内容的提问来源于stack exchange,提问作者Robyn.D
相关产品推荐
相关产品推荐

