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

使用Jackson反序列化异构元素列表时遭遇反序列化异常

解决混合类型JSON数组的反序列化异常

你遇到的问题本质是Java强类型特性和JSON混合类型结构的冲突——你的locations数组里同时存在对象、字符串、嵌套数组三种元素,默认的Jackson序列化规则无法自动识别这些不同类型的节点该映射到什么Java类,因此抛出了反序列化异常。下面是一套可行的解决方案:

1. 定义核心模型类

先把JSON中的location对象对应成标准Java类:

public class Location {
    private String location_type;
    private String position;
    private String accuracy;

    // Jackson必须依赖无参构造函数实例化对象
    public Location() {}

    // Getter & Setter 方法
    public String getLocation_type() { return location_type; }
    public void setLocation_type(String location_type) { this.location_type = location_type; }
    public String getPosition() { return position; }
    public void setPosition(String position) { this.position = position; }
    public String getAccuracy() { return accuracy; }
    public void setAccuracy(String accuracy) { this.accuracy = accuracy; }
}

2. 统一表达式接口与子类实现

因为locations元素有三种类型,我们用一个接口来统一它们,再分别实现对应子类:

统一接口(指定自定义反序列化器)

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@JsonDeserialize(using = LocationExpressionDeserializer.class)
public interface LocationExpression {
}

单个Location实现类

直接让Location类实现上面的接口:

public class Location implements LocationExpression {
    // 内容和上面的Location类完全一致,省略重复代码
}

逻辑运算符类(处理"and"/"or"字符串)

public class LogicalOperator implements LocationExpression {
    private String operator;

    public LogicalOperator() {}
    public LogicalOperator(String operator) { this.operator = operator; }

    // Getter & Setter
    public String getOperator() { return operator; }
    public void setOperator(String operator) { this.operator = operator; }
}

嵌套组合数组类

import java.util.List;

public class LocationGroup implements LocationExpression {
    private List<LocationExpression> expressions;

    public LocationGroup() {}
    public LocationGroup(List<LocationExpression> expressions) { this.expressions = expressions; }

    // Getter & Setter
    public List<LocationExpression> getExpressions() { return expressions; }
    public void setExpressions(List<LocationExpression> expressions) { this.expressions = expressions; }
}

3. 编写自定义反序列化器

这个类的作用是根据JSON节点类型,自动匹配对应的Java类:

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 com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class LocationExpressionDeserializer extends JsonDeserializer<LocationExpression> {
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public LocationExpression deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode node = p.getCodec().readTree(p);

        // 字符串节点 → 逻辑运算符
        if (node.isTextual()) {
            return new LogicalOperator(node.asText());
        }
        // 对象节点 → 单个Location
        else if (node.isObject()) {
            return objectMapper.treeToValue(node, Location.class);
        }
        // 数组节点 → 嵌套组合组
        else if (node.isArray()) {
            List<LocationExpression> expressions = new ArrayList<>();
            for (JsonNode arrayNode : node) {
                expressions.add(objectMapper.treeToValue(arrayNode, LocationExpression.class));
            }
            return new LocationGroup(expressions);
        }

        throw new IOException("无法识别的位置表达式类型");
    }
}

4. 主类中使用接口类型列表

把包含locations字段的主类字段定义为List<LocationExpression>:

import java.util.List;

public class YourMainModel {
    private List<LocationExpression> locations;

    // Getter & Setter
    public List<LocationExpression> getLocations() { return locations; }
    public void setLocations(List<LocationExpression> locations) { this.locations = locations; }
}

5. 测试反序列化

现在可以用Jackson正常解析你的JSON了:

import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) throws IOException {
        String json = "你的目标JSON字符串";
        ObjectMapper mapper = new ObjectMapper();
        YourMainModel model = mapper.readValue(json, YourMainModel.class);
        // 此时model中的locations已完成正确反序列化
    }
}

额外注意事项

  • 所有POJO类必须提供无参构造函数,Jackson依赖它创建实例。
  • 如果你不想用接口子类的方式,也可以把locations定义为List<Object>后手动做类型判断,但这种方式类型不安全,容易出现ClassCastException,不推荐使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:10:14