Jackson-反序列化期间不允许对象属性和数组元素为null



当遇到任何(非基元)对象属性或任何(非基元)数组元素null时,Jackson中是否有让反序列化失败的选项?

它的工作原理应类似于反序列化功能(FAIL_ON_NULL_FOR_PRIMITIVES)。

示例#1

因此,当反序列化为POJO 时,反序列化{"name": null}应该抛出异常

class User { 
    private String name = "Default name";
    //+setters/getters 
}

但是,当将{}反序列化到该POJO中时,它应该可以正常工作,并且不会引发异常,因为name字段的默认值不会被覆盖(请参阅注释)。

示例#2

我也希望避免数组中的null元素,因此反序列化["A", "B", null]在反序列化为List<String>时应该引发异常。

据我所知,没有简单的方法可以做到这一点(jackson databind 2.4.2)。
我建议您考虑使用自定义构造函数/工厂方法从Json中创建对象。这允许您对传入的Json字符串进行更高级的验证。

示例#1的解决方案

您可以通过向添加的BeanDeserializerModifier注册SimpleModule来添加此功能,以便更改反序列化功能
通过重写适当的方法,您可以使用默认的JsonDeserializer来轻松地反序列化对象,并在发生null属性时抛出映射异常
您可以在类似SO问题的答案中找到详细信息。

扩展现有的反序列化:

//instantiate an objectMapper and alter the deserialization functionality
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.setDeserializerModifier(new BeanDeserializerModifier() {
    @Override
    public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        return new DisallowNullDeserializer(beanDesc.getBeanClass(), deserializer);
    }
});
mapper.registerModule(simpleModule);

实际的反序列化和异常抛出发生在这个实用程序类中:

public class DisallowNullDeserializer<T> extends StdDeserializer<T> implements ResolvableDeserializer {
    private final JsonDeserializer<?> delegateDeserializer;
    public DisallowNullDeserializer(Class<T> clazz, JsonDeserializer<?> delegateDeserializer) {
        super(clazz);
        this.delegateDeserializer = delegateDeserializer;
    }
    @Override
    public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        // delegate actual deserialization to default deserializer
        T out = (T) delegateDeserializer.deserialize(jp, ctxt);
        // check for null properties & throw exception
        // -> there may be a better, more performant way to find null properties
        Map<String, Object> propertyMap = mapper.convertValue(out, Map.class);
        for (Object property: propertyMap.values())
            if (property == null)
                throw ctxt.mappingException("Can not map JSON null values.");
        return out;
    }
    // there is no obvious reason why this is needed; see linked SO answers 
    @Override
    public void resolve(DeserializationContext ctxt) throws JsonMappingException {
        ((ResolvableDeserializer) delegateDeserializer).resolve(ctxt);
    }
}

最新更新