Java中使用Jackson处理JSON原始联合类型的序列化与反序列化
嘿,针对你遇到的JSON联合类型序列化/反序列化问题,我给你整理了几个实用的方案,帮你完美适配value可以是字符串、布尔值或数字的场景:
方案1:直接用Object类型接收(最简方案)
这是最省心的方式,把你原来POJO里的String value改成Object value,Jackson默认就能自动处理不同类型的JSON值,序列化时也会保留原始类型:
@RequiredArgsConstructor @Getter @EqualsAndHashCode public class Request { private final String key; private final Object value; // 替换为Object类型 } @RequiredArgsConstructor @Getter @EqualsAndHashCode public class Response { private final String key; @JsonInclude(JsonInclude.Include.NON_NULL) private final Object value; // 同样替换为Object类型 }
优点:零额外配置,快速实现需求;
缺点:类型不安全,使用value时需要手动判断类型并强制转换,可能抛出ClassCastException,适合简单场景。
方案2:自定义序列化/反序列化器(类型安全首选)
如果想要严格的类型安全,避免强制转换的风险,可以自定义Jackson的序列化/反序列化器,精准处理每种类型:
第一步:编写自定义反序列化器
public class UnionValueDeserializer extends JsonDeserializer<Object> { @Override public Object deserialize(JsonParser parser, DeserializationContext context) throws IOException { JsonNode node = parser.getCodec().readTree(parser); if (node.isBoolean()) { return node.asBoolean(); } else if (node.isNumber()) { // 用Number兼容整数、浮点数等所有数字类型,也可以按需指定Long/Double return node.numberValue(); } else if (node.isTextual()) { return node.asText(); } throw new IOException("不支持的value类型:" + node.getNodeType()); } }
第二步:在POJO字段上添加注解
@RequiredArgsConstructor @Getter @EqualsAndHashCode public class Request { private final String key; @JsonDeserialize(using = UnionValueDeserializer.class) private final Object value; } // Response类同理,如果序列化需要特殊处理,也可以添加@JsonSerialize注解自定义逻辑
进阶:用密封类实现强类型安全
如果想进一步提升类型安全,可以定义一个密封类来封装不同类型的value,避免使用Object:
// 密封类,限制只能有这三个子类 public sealed class UnionValue permits StringValue, BooleanValue, NumberValue {} // 分别封装每种类型的value public record StringValue(String value) extends UnionValue {} public record BooleanValue(Boolean value) extends UnionValue {} public record NumberValue(Number value) extends UnionValue {}
然后修改反序列化器,返回对应的UnionValue子类,使用时可以用switch-case模式匹配,完全避免类型转换错误:
// 修改后的反序列化器 public class UnionValueDeserializer extends JsonDeserializer<UnionValue> { @Override public UnionValue deserialize(JsonParser parser, DeserializationContext context) throws IOException { JsonNode node = parser.getCodec().readTree(parser); if (node.isBoolean()) { return new BooleanValue(node.asBoolean()); } else if (node.isNumber()) { return new NumberValue(node.numberValue()); } else if (node.isTextual()) { return new StringValue(node.asText()); } throw new IOException("不支持的value类型:" + node.getNodeType()); } }
这种方式是类型最安全的,适合复杂业务场景。
方案3:用JsonNode接收(灵活操作JSON)
如果需要频繁对value进行JSON节点级别的操作,可以把字段类型改成JsonNode:
@RequiredArgsConstructor @Getter @EqualsAndHashCode public class Request { private final String key; private final JsonNode value; }
使用时直接判断节点类型并取值:
// 示例:处理Request的value Request request = ...; JsonNode valueNode = request.getValue(); if (valueNode.isBoolean()) { boolean boolValue = valueNode.asBoolean(); } else if (valueNode.isNumber()) { Number numValue = valueNode.numberValue(); } else if (valueNode.isTextual()) { String strValue = valueNode.asText(); }
优点:灵活支持JSON结构的各种操作;
缺点:需要手动处理类型转换,代码相对繁琐。
内容的提问来源于stack exchange,提问作者Fynn
相关产品推荐
相关产品推荐

