Spring Boot JSON 空值序列化

Jos*_*aag 3 java jackson java-8 spring-boot

如何在 Spring Boot 的默认 JSON 响应中强制将 null 对象序列化为空字符串?

我希望它显示为:

{
    myProperty: "",
}
Run Code Online (Sandbox Code Playgroud)

但默认输出的是:

{
    myProperty: null,
}
Run Code Online (Sandbox Code Playgroud)

我不希望 myProperty 被排除在该列表之外,所以我对更改JsonInclude.Include.NON_NULL

这是我尝试过的:

在我的主课中WebMvcConfigurerAdapter

@Autowired
private NullAsEmptyStringSerializer nullSerializer;

@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomSerialization() {
    return jacksonObjectMapperBuilder -> {
        DefaultSerializerProvider serializerProvider = new DefaultSerializerProvider.Impl();
        serializerProvider.setNullValueSerializer(nullSerializer);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializerProvider(serializerProvider);
        jacksonObjectMapperBuilder.configure(objectMapper);
    };
Run Code Online (Sandbox Code Playgroud)

然后是我的nullSerializer对象类:

@Component
public class NullAsEmptyStringSerializer extends JsonSerializer<Object> {

    @Override
    public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeString("\"\"");
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是该serialize()方法从未在我的自定义类上调用。

Ant*_*tot 5

此配置的问题在于Jackson2ObjectMapperBuilderCustomizer以下几行:

ObjectMapper objectMapper = new ObjectMapper();
jacksonObjectMapperBuilder.configure(objectMapper);
Run Code Online (Sandbox Code Playgroud)

事实上,这没有任何效果,因为构建器总是使用ObjectMapper内部创建的自己的实例。如果我们检查构建器的源代码:

public <T extends ObjectMapper> T build() {
  ObjectMapper mapper;
  // conditional instantiation of mapper
  configure(mapper);
  return (T) mapper;
}
Run Code Online (Sandbox Code Playgroud)

我们之前的实例ObjectMapper被忽略了。

不幸的是,没有办法设置SerializerProviders 通过Jackson2ObjectMapperBuilder。可能该功能尚未在 API 中实现。

但这个问题至少有两种可能的解决方案。

首先,根据Spring 官方文档,您始终可以根据需要创建自己的ObjectMapper标记@Primary并完全配置的 bean,例如:

@Bean
@Primary
public ObjectMapper objectMapper() {
  DefaultSerializerProvider serializerProvider = new DefaultSerializerProvider.Impl();
  serializerProvider.setNullValueSerializer(nullSerializer);
  ObjectMapper objectMapper = new ObjectMapper();
  objectMapper.setSerializerProvider(serializerProvider);
  return objectMapper;
}
Run Code Online (Sandbox Code Playgroud)

这将正确启用nullSerializer,但缺点是 Spring 的实例自动配置ObjectMapper将会丢失,而这可能不是您总是想要的。

第二种解决方案是引导默认实例ObjectMapper并在其上设置所需的属性。这可以通过实现接口来实现InitializingBean,方法非常简单:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ObjectMapperConfig implements InitializingBean {

  @Autowired
  private NullAsEmptyStringSerializer nullSerializer;

  @Autowired
  private ObjectMapper objectMapper;

  // will be called by Spring after all the beans are created
  // and the proper `objectMapper` instance is available here.
  @Override
  public void afterPropertiesSet() throws Exception {
    DefaultSerializerProvider serializerProvider = new DefaultSerializerProvider.Impl();
    serializerProvider.setNullValueSerializer(nullSerializer);
    objectMapper.setSerializerProvider(serializerProvider);
  }

}
Run Code Online (Sandbox Code Playgroud)

最后但并非最不重要的一点是,上面有一个小问题NullAsEmptyStringSerializer

jsonGenerator.writeString("\"\"");
Run Code Online (Sandbox Code Playgroud)

将输出"myProperty":"\"\"". 这应该改为

jsonGenerator.writeString("");
Run Code Online (Sandbox Code Playgroud)