Jackson: 将 null 字符串反序列化为空字符串

24

我有一个类,由Jackson映射(简化版本):

public class POI {
    @JsonProperty("name")
    private String name;
}
在某些情况下,服务器会返回"name": null,我想将名称设置为空的Java字符串。
是否有任何Jackson注释可以使用,或者我应该在getter中检查null并返回空字符串,如果属性是null

好的,这是一个副本: https://dev59.com/JW025IYBdhLWcg3wzpaK - spa
5个回答

28
Jackson 2.9提供了一种新机制,目前还未被提及:可以使用@JsonSetter注解来设置属性,以及类型如String.class的“配置覆盖”等价物。 更长的解释在此:https://medium.com/@cowtowncoder/jackson-2-9-features-b2a19029e9ff 简而言之,您可以像这样标记字段(或setter):
@JsonSetter(nulls=Nulls.AS_EMPTY) public String stringValue;

或者配置映射器以对所有String值属性执行相同的操作:

mapper.configOverride(String.class)
 .setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));

两者都会将传入的null转换为空值,对于字符串而言是 ""。

这同样适用于CollectionMap


2
当API可以发送“null”作为值或根本不发送字段时,设置@JsonSetter(nulls = Nulls.AS_EMPTY)对我很有用。在这两种情况下,它都被映射为空字符串。正是我所需要的,谢谢! - AbstractVoid
对于集合:至少在使用Jackson 2.11.3时,这对于缺失属性不起作用。当反序列化显式空值和缺失属性时,有效的方法是将最终集合字段初始化为空集合,并仅提供getter方法,并指定Nulls.SKIP - 可以在字段本身上或通过配置映射器来实现,如此答案所述。 - Yaniv Nahoum
@YanivNahoum 正确,没有传入值的属性不会被处理,除了构造函数传递(@JsonCreator)的情况,其中必须提供一些值。因此,您是正确的,这是解决限制的一种方法。 - StaxMan

17

再次说明,本回答是为那些偶然发现这个帖子的SO用户准备的。

虽然已接受的答案在所有方面都是被认可和有效的,但它在我这种情况下并没有帮助我,那就是在我们将服务提供给客户端之后才决定将null字符串值设置为空字符串。

因此,在实例化相关对象时或者在声明时初始化大约30-40个pojo(增加)是太多了。

以下是我们的解决方法。

public class CustomSerializerProvider extends DefaultSerializerProvider {

    public CustomSerializerProvider() {
        super();
    }

    public CustomSerializerProvider(CustomSerializerProvider provider, SerializationConfig config,
            SerializerFactory jsf) {
        super(provider, config, jsf);
    }

    @Override
    public CustomSerializerProvider createInstance(SerializationConfig config, SerializerFactory jsf) {
        return new CustomSerializerProvider(this, config, jsf);
    }

    @Override
    public JsonSerializer<Object> findNullValueSerializer(BeanProperty property) throws JsonMappingException {
        if (property.getType().getRawClass().equals(String.class))
            return Serializers.EMPTY_STRING_SERIALIZER_INSTANCE;
        else
            return super.findNullValueSerializer(property);
    }
}

而且,序列化程序

public class Serializers extends JsonSerializer<Object> {
    public static final JsonSerializer<Object> EMPTY_STRING_SERIALIZER_INSTANCE = new EmptyStringSerializer();

    public Serializers() {}

    @Override
    public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
            throws IOException, JsonProcessingException {
        jsonGenerator.writeString("");
    }

    private static class EmptyStringSerializer extends JsonSerializer<Object> {
        public EmptyStringSerializer() {}

        @Override
        public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException, JsonProcessingException {
            jsonGenerator.writeString("");
        }
    }
}

然后在ObjectMapper中设置序列化器。(Jackson 2.7.4

ObjectMapper nullMapper = new ObjectMapper();
nullMapper.setSerializerProvider(new CustomSerializerProvider());

希望这可以节省其他人的时间。


SO用户是什么意思? - 某某某
stackoverflow -> SO - Tirath
我看到了,谢谢你的回答。 - 某某某

12

一个不使用Jackson特性的简单解决方案:为名称编写一个Getter方法,该方法返回一个空字符串而不是null,因为Jackson使用null进行序列化。

public String getName() {
  return name != null ? name : "";
}

还有一种方法是编写自定义反序列化器。请看这里:http://wiki.fasterxml.com/JacksonHowToCustomSerializers


9

您可以在默认构造函数中设置它,也可以在声明时设置:

public class POI {
    @JsonProperty("name")
    private String name; 

    public POI() {
        name = "";
    }
}

或者

public class POI {
    @JsonProperty("name")
    private String name = "";
} 

很棒的答案。当Lombok管理无参数构造函数时,是否有任何解决方案? - ElPiter

1

如果您正在寻找一个适用于Spring Boot的全局解决方案,您可以配置ObjectMapper

@Configuration
public class JacksonConfiguration {

    @Bean
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder mapperBuilder) {
        DefaultSerializerProvider sp = new DefaultSerializerProvider.Impl();
        sp.setNullValueSerializer(new JsonSerializer<Object>() {
            public void serialize(Object value, JsonGenerator jgen,
                                  SerializerProvider provider)
                    throws IOException, JsonProcessingException
            {
                jgen.writeString("");
            }
        });
        ObjectMapper mapper = mapperBuilder.build();
        mapper.setSerializerProvider(sp);
        return mapper;
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接