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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 19:12:40