簡體   English   中英

啟用 Jackson 將空對象反序列化為 Null

[英]Enable Jackson Deserialization of Empty Objects to Null

我被要求更改我們的 jackson 映射配置,以便我們反序列化(來自 JSON)的每個空 object 將被反序列化為 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實例)。

什么是你的空對象? 具有空值字段的對象? 一個沒有字段的對象? 您可以創建一個自定義來檢查節點並反序列化您想要的方式。 我認為以通用方式使用它沒有問題。

我做了一個小例子:

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

}

我有同樣的問題。

我有一個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

做到這一點的唯一方法是使用自定義解串器:

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

這個解決方案由 Sach141 在這個問題上提供

另一種方法是使用com.fasterxml.jackson.databind.util.Converter<IN,OUT> ,它本質上是用於反序列化的后處理器。

假設我們有一個 class:

public class Person {
    public String id;
    public String name;
}

現在假設我們想要將一個空的 JSON object {}反序列化為null ,而不是將Personidname值反序列化為null 我們可以創建以下Converter

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 class:

@JsonDeserialize(converter=PersonConverter.class)
public class Person {
    public String id;
    public String name;
}

這種方法的好處是您根本不必考慮或關心反序列化; 您只是在反序列化后決定如何處理反序列化的 object。 您還可以使用Converter進行許多其他轉換。 但這對於使“空”值無效很有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM