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

如何基于Cart的channel属性反序列化抽象Product子类型列表

方案1:修正注解配置(推荐,无需自定义反序列化器)

Jackson 2.9及以上版本本身支持EXTERNAL_PROPERTY类型的类型标识作用在集合字段上,你之前的写法不生效主要是两个配置问题:

  1. @JsonSubTypes.Type的name属性需要和Channel枚举的实际序列化值完全匹配
  2. 确保字段名和@JsonTypeInfo指定的property属性值一致

正确配置示例:

public class Cart {
    private Channel channel; // 取值为Channel.ONLINE或Channel.PRINT

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "channel")
    @JsonSubTypes(value = {
            @JsonSubTypes.Type(value = OnlineProduct.class, name = "ONLINE"), // 与Channel枚举序列化值对应
            @JsonSubTypes.Type(value = PrintProduct.class, name = "PRINT")
    })
    private List<Product> products;

    // 其余属性、getter/setter省略,新增Cart属性时不需要修改此处配置
}

方案2:改进自定义反序列化器(适用于Jackson版本低、类型匹配逻辑复杂的场景)

你之前的自定义反序列化器不生效是因为第一次调用readValue时已经消费了全部JSON流,后续无法再读取products字段的内容。改进后的写法可以自动适配Cart的字段变更,不需要每次扩展Cart都修改反序列化器:

  1. 先将JSON解析为JsonNode保留所有数据
  2. 复用Jackson默认的Cart反序列化器处理除products外的所有字段
  3. 根据反序列化得到的channel值单独解析products列表

实现代码:

public class CartDeserializer extends StdDeserializer<Cart> {
    private final JsonDeserializer<Object> defaultCartDeserializer;
    private final ObjectMapper objectMapper;

    public CartDeserializer(JsonDeserializer<?> defaultDeserializer, ObjectMapper objectMapper) {
        super(Cart.class);
        this.defaultCartDeserializer = (JsonDeserializer<Object>) defaultDeserializer;
        this.objectMapper = objectMapper;
    }

    @Override
    public Cart deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode root = p.readValueAsTree();
        // 复用默认反序列化器处理所有普通字段,Cart新增属性时不需要修改这部分逻辑
        Cart cart = (Cart) defaultCartDeserializer.deserialize(p.getCodec().treeAsTokens(root), ctxt);
        
        JsonNode productsNode = root.get("products");
        if (productsNode != null && !productsNode.isNull()) {
            // 根据channel选择具体的Product实现类
            Class<? extends Product> productClazz = Channel.ONLINE.equals(cart.getChannel()) 
                    ? OnlineProduct.class 
                    : PrintProduct.class;
            // 构造List的泛型类型进行反序列化
            CollectionType productListType = objectMapper.getTypeFactory()
                    .constructCollectionType(List.class, productClazz);
            List<Product> products = objectMapper.readValue(
                    objectMapper.treeAsTokens(productsNode), 
                    productListType
            );
            cart.setProducts(products);
        }
        return cart;
    }
}

反序列化器注册方式:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
    @Override
    public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        if (Cart.class.isAssignableFrom(beanDesc.getBeanClass())) {
            return new CartDeserializer(deserializer, mapper);
        }
        return deserializer;
    }
});
mapper.registerModule(module);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 01:57:02