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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 21:57:27