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

Spring Boot Jackson反序列化String[]报START_OBJECT错误解决

异常原因

报错核心是反序列化类型不匹配:你在POJO里把payLoad声明为String[](字符串数组),但实际传入的JSON中payLoad存储的是结构化JSON对象数组。Jackson反序列化时,读到数组内的对象起始标识{(即异常中提到的JsonToken.START_OBJECT token),无法直接将嵌套的JSON对象转为普通字符串,因此抛出MismatchedInputException。
你之前添加的@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)注解,作用仅为兼容「接口传单个值而非数组时自动包装为数组」的场景,完全无法解决JSON对象转字符串的问题,在此处添加无效。


解决方案

以下两种方案都可以实现「保留原有JSON格式、将payLoad转为字符串集合/数组」的需求,可根据场景选择:

方案1:自定义反序列化器(推荐)

该方案解析完成后字段直接为目标类型,无需二次转换,反序列化器可全局复用。

  1. 编写自定义反序列化器,遍历数组时将每个JSON节点直接转为标准JSON字符串:
    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonToken;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.JsonDeserializer;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    public class JsonArrayToStringListDeserializer extends JsonDeserializer<List<String>> {
        @Override
        public List<String> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            List<String> result = new ArrayList<>();
            if (p.currentToken() != JsonToken.START_ARRAY) {
                ctxt.reportInputMismatch(List.class, "payLoad字段预期为数组类型");
                return result;
            }
            ObjectMapper mapper = (ObjectMapper) p.getCodec();
            while (p.nextToken() != JsonToken.END_ARRAY) {
                JsonNode node = mapper.readTree(p);
                // 直接将节点转为JSON字符串,完全保留原有结构和格式
                result.add(node.toString());
            }
            return result;
        }
    }
    
  2. 修改Response类,为payLoad字段指定自定义反序列化器,移除无效注解:
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
    import java.util.List;
    
    public class Response {
        @JsonProperty("count")
        private int totalCount;
    
        @JsonProperty("respCode")
        private int responseCode;
    
        @JsonProperty("payLoad")
        @JsonDeserialize(using = JsonArrayToStringListDeserializer.class)
        private List<String> transactionsList;
    
        // getter/setter
        public int getTotalCount() { return totalCount; }
        public void setTotalCount(int totalCount) { this.totalCount = totalCount; }
        public int getResponseCode() { return responseCode; }
        public void setResponseCode(int responseCode) { this.responseCode = responseCode; }
        public List<String> getTransactionsList() { return transactionsList; }
        public void setTransactionsList(List<String> transactionsList) { this.transactionsList = transactionsList; }
    }
    
    如果一定要用String[]类型,只需修改反序列化器返回值为String[],最后执行return result.toArray(new String[0]),同步修改Response类对应字段类型即可。

方案2:先接收JsonNode再手动转换(轻量场景适用)

该方案无需额外编写反序列化类,适合临时使用的简单场景:

  1. 修改Response类,将payLoad字段声明为Jackson内置的JsonNode类型,手动添加转换方法:
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.databind.JsonNode;
    import java.util.ArrayList;
    import java.util.List;
    
    public class Response {
        @JsonProperty("count")
        private int totalCount;
    
        @JsonProperty("respCode")
        private int responseCode;
    
        @JsonProperty("payLoad")
        private JsonNode payLoadNode;
    
        // 手动转换为字符串列表
        public List<String> getTransactionsList() {
            List<String> result = new ArrayList<>();
            if (payLoadNode != null && payLoadNode.isArray()) {
                for (JsonNode node : payLoadNode) {
                    result.add(node.toString());
                }
            }
            return result;
        }
    
        // 其他字段getter/setter省略
    }
    

注意:不要直接将payLoad声明为List<Map<String,Object>>类型接收,这种方式会把JSON对象转为Map结构,后续再序列化为JSON字符串时可能出现字段顺序变化、null值处理规则不一致的问题,无法保证和原有JSON格式完全一致。

两种方案解析完成后,transactionsList中的每个元素都是payLoad数组内单个对象的完整JSON字符串,比如第一个元素值为{"id":1,"userName":null,"arName":"A1","areas":[]},完全保留原有结构无丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 09:54:29