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

qf9go6mv  于 2023-01-15  发布在  Java
关注(0)|答案(4)|浏览(287)

我被要求更改JacksonMap配置,以便我们(从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);

但它只对弦起作用。
我担心使用自定义反序列化器对我没有帮助,因为我正在编写一个通用的(针对所有对象)Map器,所以我可能需要一些类似于委托器或后处理反序列化方法的东西。
因此,对于像""{}这样的json,我希望在java中转换为null(而不是空字符串或Object示例)。

drkbr07n

drkbr07n1#

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

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

}
tzcvj98z

tzcvj98z2#

唯一的方法是使用自定义反序列化程序:

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提供。

s5a0g9ez

s5a0g9ez3#

我也有同样的问题。
我有一个City类,有时我会从Web服务请求中收到'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;
}
}

如果检查条件:

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

如果为真,则反串行化器返回null

qlfbtfca

qlfbtfca4#

另一种方法是使用com.fasterxml.jackson.databind.util.Converter<IN,OUT>,它本质上是反序列化的后处理器。
假设我们有一个类:

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

现在假设我们想将一个空JSON对象{}反序列化为null,而不是将idname反序列化为null值的Person,我们可以创建以下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类:

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

这种方法的好处是您根本不必考虑或关心反序列化;你只需要决定在反序列化对象之后如何处理它,还有很多其他的转换你也可以用Converter来做,但是这很适合于使“空”值无效。

相关问题