【问题标题】:Enable Jackson Deserialization of Empty Objects to Null启用 Jackson 将空对象反序列化为 Null
【发布时间】:2019-12-19 05:28:22
【问题描述】:

我被要求更改我们的杰克逊映射配置,以便我们反序列化(来自 JSON)的每个空对象都将被反序列化为 null。

问题是我正在努力做到这一点,但没有任何运气。这是我们的ObjectMapper 配置示例(和示例):

ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, true);
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ISO_DATE_TIME));
javaTimeModule.addDeserializer(Instant.class, InstantDeserializer.INSTANT);
mapper.registerModule(javaTimeModule);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
warmupMapper(mapper);

return mapper;

我想到了添加:

mapper.configure(
    DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);

但它只适用于字符串。

恐怕使用自定义反序列化器对我没有帮助,因为我正在编写一个通用(适用于所有对象)映射器。所以我可能需要一个委托或后处理反序列化方法之类的东西。

所以对于像""{} 这样的json,我希望在java 中转换为null(而不是空字符串或Object 实例)。

【问题讨论】:

    标签: java jackson deserialization


    【解决方案1】:

    对你来说什么是空对象?具有空值字段的对象?没有字段的对象?您可以创建一个自定义来检查节点并反序列化您想要的方式。我认为以通用方式使用它没有问题。

    我做了一个小例子:

    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
    import com.fasterxml.jackson.databind.module.SimpleModule;
    import java.io.IOException;
    import java.util.Objects;
    
    public class DeserializerExample<T> extends StdDeserializer<T> {
    
        private final ObjectMapper defaultMapper;
    
        public DeserializerExample(Class<T> clazz) {
            super(clazz);
            defaultMapper = new ObjectMapper();
        }
    
        @Override
        public T deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
            System.out.println("Deserializing...");
    
            JsonNode node = jp.getCodec().readTree(jp);
    
            for (JsonNode jsonNode : node) {
                if (!jsonNode.isNull()) {
                    return defaultMapper.treeToValue(node, (Class<T>) getValueClass());
                }
            }
    
            return null;
        }
    
        public static void main(String[] args) throws IOException {
    
            ObjectMapper mapper = new ObjectMapper();
            SimpleModule module = new SimpleModule();
            module.addDeserializer(Person.class, new DeserializerExample(Person.class));
            mapper.registerModule(module);
    
            Person person = mapper.readValue("{\"id\":1, \"name\":\"Joseph\"}", Person.class);
    
            Person nullPerson = mapper.readValue("{\"id\":null, \"name\":null}", Person.class);
    
            System.out.println("Is null: " + Objects.isNull(person));
            System.out.println("Is null: " + Objects.isNull(nullPerson));
        }
    
    }
    

    【讨论】:

    • 对我来说,一个空对象是一个所有成员都为空的对象。而且不是序列化器,而是反序列化器(如果有什么改变的话)。
    • 对错误感到抱歉。
    【解决方案2】:

    我遇到了同样的问题。

    我有一个City 课程,有时我会从网络服务请求中收到'city':{}

    因此,标准序列化程序创建一个新的城市,所有字段均为空。

    我用这种方式创建了一个自定义的反序列化器

    public class CityJsonDeSerializer extends StdDeserializer<City> {
    
    @Override
    public City deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
        
        JsonNode node = jp.getCodec().readTree(jp);
        
        if(node.isNull() || node.asText().isEmpty()|| node.size()==0)
            return null;
        
        City city = new City();
        ... // set all fields
        return city;
    }
    }
    

    if 检查条件:

    • 'city' : null
    • 'city' : ''
    • 'city' : '{}'

    如果为真,则反序列化器返回null

    【讨论】:

    • 自定义反序列化器是一个我无法应用的解决方案,因为需求是将它应用于每个对象。无论如何,我不再为那家公司工作,而且我记得这项任务没有实施,因为它首先是愚蠢的 - 没有价值,只有风险和可能的绩效惩罚。我认为最好的解决方案是一开始就避免实施它,因为这可能意味着您的流程有问题。
    • @Aladin 我不同意。我觉得这很合理。我想做这个。我调用的一个 Rest 端点向我发送了一些空对象,我只是不想从中获取一个随机属性来知道它是否为空,我认为它是否为 null 更自然。顺便说一句,我的意思是 {} ,而不是 "" 或 []
    • 在您的情况下,您可以为特定休息点的请求对象编写自定义反序列化程序。我说的是所有端点通用的东西。
    • 我不记得它是否适用于所有 jackson 版本,但如果您使用 @JsonDeserializer(...) 将序列化程序放在类的顶部,它将始终使用跨度>
    【解决方案3】:

    这样做的唯一方法是使用自定义反序列化器:

    class CustomDeserializer extends JsonDeserializer<String> {
    
    @Override
    public String deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
        JsonNode node = jsonParser.readValueAsTree();
        if (node.asText().isEmpty()) {
            return null;
        }
        return node.toString();
    }
    }
    

    然后做:

    class EventBean {
    public Long eventId;
    public String title;
    
    @JsonDeserialize(using = CustomDeserializer.class)
    public String location;
    }
    

    此解决方案由 question 上的 Sach141 提供。

    【讨论】:

    • 我认为这个属性与序列化有关,与反序列化无关
    • 据我所见,您正在序列化,然后反序列化。你不能反序列化不存在的东西。
    猜你喜欢
    • 1970-01-01
    • 2023-03-13
    • 2016-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-09
    • 1970-01-01
    相关资源
    最近更新 更多