Java如何解析无根元素名称的REST请求JSON响应
问题描述
收到的REST请求响应格式如下:
[ { "data":{ "channel":{ "id":"708087644", "__typename":"User" } }, "extensions":{ "durationMilliseconds":112, "operationName":"ViewerCardModLogsMessagesBySender", "requestID":"01GWVKPD13BQGBZS64TY4824B9" } } ]
我尝试创建RestResponse类并通过以下代码解析:
ResponseEntity<RestResponse> result = restTemplate.postForEntity(uri, entity, RestResponse.class);
但抛出异常:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `org.tomass.twitch.RestResponse` from Array value (token `JsonToken.START_ARRAY`) at [Source: (PushbackInputStream); line: 1, column: 1]
RestResponse类定义如下:
public class RestResponse implements Serializable { private static final long serialVersionUID = 1L; private List<Root> root = new ArrayList<>(); public List<Root> getRoot() { return root; } public void setRoot(List<Root> root) { this.root = root; } public static class Root { private Data data; // getters & setters public class Data { private Channel channel; // getters & setters } } }
手动给响应添加根元素"root"后能正常解析,但我想知道无需修改响应内容的解析方法。
解决方法
方法1:直接解析为List<Root>类型
响应本身就是JSON数组,对应Java的List类型,直接把解析目标改成泛型列表即可:
ResponseEntity<List<Root>> result = restTemplate.postForEntity(uri, entity, new ParameterizedTypeReference<List<Root>>() {}); List<Root> rootList = result.getBody();
这里必须用ParameterizedTypeReference来指定泛型类型,避免Java类型擦除导致Jackson无法识别列表元素类型。
方法2:调整RestResponse类适配JSON数组
如果一定要用RestResponse类包裹数据,可通过Jackson注解让数组直接映射到root字段:
import com.fasterxml.jackson.annotation.JsonFormat; public class RestResponse implements Serializable { private static final long serialVersionUID = 1L; @JsonFormat(shape = JsonFormat.Shape.ARRAY) private List<Root> root = new ArrayList<>(); // 原有getter、setter不变 public static class Root { private Data data; private Extensions extensions; // 补上原响应中未定义的extensions字段 // getters & setters public static class Data { // 内部类改为static,否则Jackson无法实例化 private Channel channel; // getters & setters } public static class Extensions { private int durationMilliseconds; private String operationName; private String requestID; // getters & setters } } public static class Channel { private String id; private String __typename; // getters & setters } }
修改后即可用原解析代码正常解析,注意几个细节:
- 所有内部类需改为
static,非静态内部类依赖外部实例,Jackson无法直接初始化 - 补上原响应中的
extensions字段,避免数据丢失
方法3:自定义Jackson反序列化器
如果以上方法不满足需求,可自定义反序列化器手动处理数组映射:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class RestResponseDeserializer extends JsonDeserializer<RestResponse> { @Override public RestResponse deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode rootNode = p.getCodec().readTree(p); RestResponse response = new RestResponse(); List<RestResponse.Root> rootList = new ArrayList<>(); Iterator<JsonNode> elements = rootNode.elements(); while (elements.hasNext()) { JsonNode element = elements.next(); RestResponse.Root root = p.getCodec().treeToValue(element, RestResponse.Root.class); rootList.add(root); } response.setRoot(rootList); return response; } }
在RestResponse类上添加注解指定反序列化器:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @JsonDeserialize(using = RestResponseDeserializer.class) public class RestResponse implements Serializable { // 原有代码不变 }
内容的提问来源于stack exchange,提问作者hudi
相关产品推荐
相关产品推荐

