java - Spring Boot JSON 空值序列化

标签 java spring-boot java-8 jackson

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

我希望它显示为:

{
    myProperty: "",
}

但是默认输出的是:

{
    myProperty: null,
}

我不希望 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);
    };

然后是我的 nullSerializer 对象类:

@Component
public class NullAsEmptyStringSerializer extends JsonSerializer<Object> {

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

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

最佳答案

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

ObjectMapper objectMapper = new ObjectMapper();
jacksonObjectMapperBuilder.configure(objectMapper);

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

public <T extends ObjectMapper> T build() {
  ObjectMapper mapper;
  // conditional instantiation of mapper
  configure(mapper);
  return (T) mapper;
}

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

遗憾的是,无法通过 Jackson2ObjectMapperBuilder 设置 SerializerProvider。可能该功能尚未在 API 中实现。

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

首先,根据 official Spring docs ,您始终可以创建自己的 ObjectMapper bean,标记为 @Primary 并根据您的意愿进行完全配置,例如:

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

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

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

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

}

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

jsonGenerator.writeString("\"\"");

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

jsonGenerator.writeString("");

关于java - Spring Boot JSON 空值序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49675945/

相关文章:

java - 从并发修改异常中恢复

java - 当android网络连接较弱时如何处理网络调用

Java - 获取不同数量的 json 变量

java - 需要澄清引导 Spring Boot 应用程序的推荐方法

java - @Profile 注释中的 AND 运算符

java - 如何计算 Spring 测试中 Spring Boot 加载的次数?

java - 从 json 反序列化 org.springframework.data.util.pair

java - 使用 Java 8 将 Streams 聚合成一个 DISTINCT 的最佳方法是什么

hibernate - Spring 在事务结束时启动不需要的 SQL 更新

java - 下载管理器如何在 Android 上工作?