You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何修改集合反序列化器实现条件过滤及异常容错?

解决方案

针对你遇到的Jackson集合反序列化时无法自动过滤无效Link、以及希望具备异常容错性的问题,这里有两种针对性的解决方案,完全符合你不想编写专门JsonDeserializer<Collection<Link>>且要全局遵循Link#valid规则的要求:

问题1:修改集合反序列化器生成过滤后的集合

方案1:利用Link反序列化器返回null + 全局过滤null元素

这是最简洁的方案,不需要修改集合反序列化逻辑,仅通过调整LinkDeserialiser和Jackson配置实现全局过滤:

  1. 修改LinkDeserialiser,在反序列化完成后校验Link#valid(),不满足则返回null:
@Override
public Link deserialize(JsonParser parser, DeserializationContext context) throws IOException {
    final JsonNode node = context.readValue(parser, JsonNode.class);
    Link link = Link.builder()
            .title(node.path(Constants.TITLE).asText().trim())
            .href(node.path(Constants.HREF).asText().trim())
            .links(loadLinks(node.path(Constants.LINKS)))
            .build();
    // 验证不通过则返回null,后续由Jackson自动过滤
    return link.valid() ? link : null;
}
  1. 在你的ObjectMapper中启用DeserializationFeature.FILTER_NULL_VALUES,让集合反序列化时自动跳过null元素:
ObjectMapper mapper = new ObjectMapper();
// 启用null元素过滤
mapper.configure(DeserializationFeature.FILTER_NULL_VALUES, true);
// 注册自定义Link反序列化器
mapper.registerModule(new SimpleModule().addDeserializer(Link.class, new LinkDeserialiser()));

这个方案的优势在于:

  • 完全复用Jackson默认的集合反序列化逻辑,不需要编写专门的Collection<Link>反序列化器
  • 全局遵循Link#valid规则,不管是单个Link还是集合中的Link,都会被自动校验过滤
  • 调用方无需任何额外处理,反序列化后的集合直接是有效Link的集合

方案2:继承CollectionDeserializer自定义元素过滤(不依赖null)

如果你不想依赖null值过滤,可以通过继承Jackson的CollectionDeserializer,在元素添加到集合前做校验:

  1. 创建自定义的FilteringCollectionDeserializer,重写addItem方法实现过滤:
public class FilteringCollectionDeserializer extends CollectionDeserializer {
    public FilteringCollectionDeserializer(CollectionDeserializer src) {
        super(src);
    }

    @Override
    protected void addItem(DeserializationContext ctxt, Collection<Object> result, Object item) throws IOException {
        // 仅当元素是Link且有效时,才添加到集合中
        if (item instanceof Link && ((Link) item).valid()) {
            super.addItem(ctxt, result, item);
        }
    }

    // 重写createContextual方法,确保上下文参数正确传递
    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
        CollectionDeserializer contextualDeserializer = (CollectionDeserializer) super.createContextual(ctxt, property);
        return new FilteringCollectionDeserializer(contextualDeserializer);
    }
}
  1. 通过BeanDeserializerModifier注册这个自定义集合反序列化器,仅对Link类型的集合生效:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
// 注册Link反序列化器
module.addDeserializer(Link.class, new LinkDeserialiser());
// 注册自定义集合过滤逻辑
module.setDeserializerModifier(new BeanDeserializerModifier() {
    @Override
    public JsonDeserializer<?> modifyCollectionDeserializer(DeserializationConfig config, CollectionType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        // 仅处理元素类型为Link的集合
        if (type.getContentType().getRawClass() == Link.class) {
            return new FilteringCollectionDeserializer((CollectionDeserializer) deserializer);
        }
        return super.modifyCollectionDeserializer(config, type, beanDesc, deserializer);
    }
});
mapper.registerModule(module);

问题2:让集合反序列化器具备异常容错性(抛出异常时继续收集有效对象)

要实现元素反序列化失败时不中断整个集合的处理,你可以在LinkDeserialiser中捕获反序列化异常,返回null,再结合上面的FILTER_NULL_VALUES配置,自动跳过异常元素:

修改LinkDeserialiser,添加异常捕获逻辑:

@Override
public Link deserialize(JsonParser parser, DeserializationContext context) throws IOException {
    try {
        final JsonNode node = context.readValue(parser, JsonNode.class);
        Link link = Link.builder()
                .title(node.path(Constants.TITLE).asText().trim())
                .href(node.path(Constants.HREF).asText().trim())
                .links(loadLinks(node.path(Constants.LINKS)))
                .build();
        return link.valid() ? link : null;
    } catch (Exception e) {
        // 捕获任何反序列化过程中的异常(比如字段缺失、类型不匹配等),返回null
        // 你也可以在这里记录异常日志,方便排查问题
        return null;
    }
}

同时保持ObjectMapperFILTER_NULL_VALUES配置,这样不管是无效的Link还是反序列化失败的Link,都会被自动跳过,集合中只保留有效且反序列化成功的元素。


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

火山引擎 最新活动