使用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
相关产品推荐
相关产品推荐

