为了账号安全,请及时绑定邮箱和手机立即绑定

启用 Jackson 将空对象反序列化为 Null

启用 Jackson 将空对象反序列化为 Null

大话西游666 2023-06-04 11:25:33
我被要求更改我们的 jackson 映射配置,以便我们反序列化(来自 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实例)。
查看完整描述

4 回答

?
素胚勾勒不出你

TA贡献1827条经验 获得超9个赞

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


我做了一个小例子:


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));

    }


}


查看完整回答
反对 回复 2023-06-04
?
噜噜哒

TA贡献1784条经验 获得超7个赞

唯一的方法是使用自定义解串器:


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;

}


查看完整回答
反对 回复 2023-06-04
?
一只萌萌小番薯

TA贡献1795条经验 获得超7个赞

我有同样的问题。


我有一个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.


查看完整回答
反对 回复 2023-06-04
?
慕斯709654

TA贡献1840条经验 获得超5个赞

另一种方法是使用 a com.fasterxml.jackson.databind.util.Converter<IN,OUT>,它本质上是一个用于反序列化的后处理器。


假设我们有一个类:


public class Person {

    public String id;

    public String name;

}

现在假设我们想要将一个空的 JSON 对象{}反序列化为null, 而不是Person具有和null值的。我们可以创建以下内容:idnameConverter


public PersonConverter implements Converter<Person,Person> {

    @Override

    public Person convert(Person p) {

        return isEmpty(p) ? null : value;

    }


    private static boolean isEmpty(Person p) {

        if(p == null) {

            return true;

        }

        if(Optional.ofNullable(p.id).orElse("").isEmpty() && 

                Optional.ofNullable(p.name).orElse("").isEmpty()) {

            return true;

        }

        return false;

    }


    @Override

    public JavaType getInputType(TypeFactory typeFactory) {

        return typeFactory.constructType(Person.class);

    }


    @Override

    public JavaType getOutputType(TypeFactory typeFactory) {

        return typeFactory.constructType(Person.class);

    }

}

请注意,我们必须处理空白String情况,因为这是(违反直觉)分配给 JSON 中未给出的属性的默认值,而不是null.


给定转换器,然后我们可以注释我们的原始Person类:


@JsonDeserialize(converter=PersonConverter.class)

public class Person {

    public String id;

    public String name;

}

这种方法的好处是您根本不必考虑或关心反序列化;您只是在反序列化后决定如何处理反序列化的对象。您还可以使用 a 进行许多其他转换Converter。但这对于使“空”值无效很有效。


查看完整回答
反对 回复 2023-06-04
  • 4 回答
  • 0 关注
  • 496 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信