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

Jackson ObjectMapper添加List<Object>反序列化及模块覆盖与自定义反序列化器问题

嘿,我来帮你解决这两个Jackson相关的问题,结合你已经写的自定义反序列化器来一步步说明:

一、先确认自定义List反序列化器的正确写法

首先,你的ProductDeserialized和OrderDeserialized需要补全构造方法(Jackson要求StdDeserializer必须提供无参构造或指定类型的构造),这里给你补全完整的实现示例:

ProductDeserialized 完整实现

public class ProductDeserialized extends StdDeserializer<List<Product>> {

    // 无参构造,Jackson需要用它来实例化反序列化器
    public ProductDeserialized() {
        this(null);
    }

    // 指定类型的构造,父类需要这个参数
    public ProductDeserialized(Class<?> vc) {
        super(vc);
    }

    @Override
    public List<Product> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        // 解析JSON数组为Product列表的示例逻辑
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        List<Product> products = new ArrayList<>();
        ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec();
        
        if (node.isArray()) {
            for (JsonNode itemNode : node) {
                Product product = mapper.treeToValue(itemNode, Product.class);
                products.add(product);
            }
        }
        return products;
    }
}

OrderDeserialized 完整实现

public class OrderDeserialized extends StdDeserializer<List<Order>> {

    public OrderDeserialized() {
        this(null);
    }

    public OrderDeserialized(Class<?> vc) {
        super(vc);
    }

    @Override
    public List<Order> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        List<Order> orders = new ArrayList<>();
        ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec();
        
        if (node.isArray()) {
            for (JsonNode itemNode : node) {
                Order order = mapper.treeToValue(itemNode, Order.class);
                orders.add(order);
            }
        }
        return orders;
    }
}

二、给ObjectMapper添加List的反序列化支持

List<Object>的特殊之处在于Jackson无法自动识别数组中每个元素的具体类型,这里提供三种常用解决方案:

方案1:使用TypeReference指定类型(针对混合类型场景)

如果你的List<Object>实际是混合了Product和Order的数组,可以直接用TypeReference反序列化,再转成List<Object>:

String mixedJson = "[{\"id\":1,\"name\":\"Wireless Mouse\"}, {\"orderId\":101,\"amount\":29.99}]";

ObjectMapper mapper = new ObjectMapper();
// 先注册你的List<Product>和List<Order>反序列化器
SimpleModule module = new SimpleModule();
module.addDeserializer(new TypeReference<List<Product>>(){}, new ProductDeserialized());
module.addDeserializer(new TypeReference<List<Order>>(){}, new OrderDeserialized());
mapper.registerModule(module);

// 反序列化为List<Object>
List<Object> mixedList = mapper.readValue(mixedJson, new TypeReference<List<Object>>() {});

注意:这种方式下,Jackson会把无法识别的对象转成LinkedHashMap,如果需要识别具体类型,建议用下面的多态方案。

方案2:通过多态注解识别类型

给Product和Order添加父类并标记多态注解,让Jackson自动识别类型:

// 定义父类,标记多态类型信息
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Product.class, name = "product"),
    @JsonSubTypes.Type(value = Order.class, name = "order")
})
public class BaseEntity {}

// Product继承父类
public class Product extends BaseEntity {
    private Long id;
    private String name;
    // getter/setter
}

// Order继承父类
public class Order extends BaseEntity {
    private Long orderId;
    private Double amount;
    // getter/setter
}

反序列化时先转成List<BaseEntity>,再转成List<Object>:

List<BaseEntity> entityList = mapper.readValue(mixedJson, new TypeReference<List<BaseEntity>>() {});
List<Object> objectList = new ArrayList<>(entityList);

方案3:自定义List反序列化器

如果你不想用多态注解,可以直接写一个专门处理List<Object>的反序列化器,通过字段判断元素类型:

public class ListObjectDeserializer extends StdDeserializer<List<Object>> {

    public ListObjectDeserializer() {
        this(null);
    }

    public ListObjectDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public List<Object> deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException {
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        List<Object> result = new ArrayList<>();
        ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec();

        if (node.isArray()) {
            for (JsonNode itemNode : node) {
                // 根据字段判断类型,比如有name字段是Product,有orderId是Order
                if (itemNode.has("name")) {
                    result.add(mapper.treeToValue(itemNode, Product.class));
                } else if (itemNode.has("orderId")) {
                    result.add(mapper.treeToValue(itemNode, Order.class));
                } else {
                    // 其他类型默认转成LinkedHashMap
                    result.add(mapper.treeToValue(itemNode, LinkedHashMap.class));
                }
            }
        }
        return result;
    }
}

注册到模块即可:

module.addDeserializer(new TypeReference<List<Object>>(){}, new ListObjectDeserializer());
mapper.registerModule(module);

三、注册模块时覆盖旧模块的方法

Jackson默认的registerModule()是追加模块,不会覆盖已有的模块或反序列化器。如果需要替换旧的配置,有三种常用方式:

方式1:先移除旧模块,再添加新模块

如果你知道旧模块的名称或实例,可以先遍历移除再添加新模块:

ObjectMapper mapper = new ObjectMapper();

// 假设已经注册了旧模块
SimpleModule oldModule = new SimpleModule("OldProductModule");
oldModule.addDeserializer(new TypeReference<List<Product>>(){}, new OldProductDeserializer());
mapper.registerModule(oldModule);

// 遍历移除旧模块
Iterator<Module> iterator = mapper.getRegisteredModules().iterator();
while (iterator.hasNext()) {
    Module module = iterator.next();
    if (module instanceof SimpleModule && module.getName().equals("OldProductModule")) {
        iterator.remove();
        break;
    }
}

// 添加新模块
SimpleModule newModule = new SimpleModule();
newModule.addDeserializer(new TypeReference<List<Product>>(){}, new ProductDeserialized());
newModule.addDeserializer(new TypeReference<List<Order>>(){}, new OrderDeserialized());
mapper.registerModule(newModule);

方式2:用BeanDeserializerModifier直接覆盖反序列化器

不需要替换整个模块,直接修改指定类型的反序列化器:

SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
    @Override
    public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        // 覆盖List<Product>的反序列化器
        if (List.class.isAssignableFrom(beanDesc.getBeanClass()) 
            && beanDesc.getType().getContentType().getRawClass() == Product.class) {
            return new ProductDeserialized();
        }
        // 覆盖List<Order>的反序列化器
        if (List.class.isAssignableFrom(beanDesc.getBeanClass()) 
            && beanDesc.getType().getContentType().getRawClass() == Order.class) {
            return new OrderDeserialized();
        }
        return super.modifyDeserializer(config, beanDesc, deserializer);
    }
});
mapper.registerModule(module);

这种方式会直接覆盖对应类型的任何已注册反序列化器。

方式3:用ObjectMapperBuilder直接设置反序列化器

如果是初始化ObjectMapper时配置,可以用ObjectMapperBuilder的deserializerByType方法直接设置,覆盖所有旧配置:

ObjectMapper mapper = ObjectMapperBuilder.create()
    .deserializerByType(new TypeReference<List<Product>>(){}, new ProductDeserialized())
    .deserializerByType(new TypeReference<List<Order>>(){}, new OrderDeserialized())
    // 可以继续添加其他配置
    .build();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:18:46