我有一个带有 React 前端的 Spring 应用程序。前端希望将空字符串值表示为“”而不是null。有没有一种方法可以做到这一点,而不必注释项目中的每个字符串字段(并记住注释我的 DTO 中的每个未来字符串值)?
我希望我可以注册一个自定义字符串序列化器,如果值为空,它只会输出“”,但当值为空时不会调用 StringValueSerializer。所有空值都直接进入 NullValueSerializer,当您到达 NullValueSerializer 时,无法确定哪个字段具有空值(或者它是什么类型的字段)。
一旦我弄清楚了 NullValueSerializer 问题,我就必须弄清楚如何自定义 SerializerProvider,事实证明这比我在 Spring、Spring-MVC 和 Jackson 的组合中所希望的更具挑战性。
首先我创建了这个新的 SerializerProvider 实现。它重写了 findNullValueSerializer,在这里我们可以查看正在序列化的属性类型,而不仅仅是值。它只是查看属性类型是否为 String,如果是,则给出一个仅写入“”的序列化器,否则它让常规 NullValueSerializer 工作。这意味着任何非字符串(Long、Date、Object、Collection)仍将具有输出 null、{} 或 [] 而不是“”的“正确”行为。我在其他一些解决方案中看到的问题是它们会为空集合输出“”。
package com.mycompany.internal;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
import com.fasterxml.jackson.databind.ser.SerializerFactory;
import java.io.IOException;
/**
* Customization to write "" instead of 'null' when a string value is null in our JSON response to the front end.
*/
public class NullStringFriendlySerializerProvider extends DefaultSerializerProvider {
public NullStringFriendlySerializerProvider(DefaultSerializerProvider provider) {
super(provider);
}
public NullStringFriendlySerializerProvider(SerializerProvider src, SerializationConfig config, SerializerFactory factory) {
super(src, config, factory);
}
/**
* Magic that writes an empty string instead of null for null string values.
*/
JsonSerializer<Object> nullAsEmptyStringSerializer = new JsonSerializer<>() {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString("");
}
};
/**
* The really real magic that only uses the null string serializer if the field is of type string.
*
* @param property the property (not the value) that is being serialized
* @return the serializer to use for the property.
* @throws JsonMappingException if bad things happen
*/
@Override
public JsonSerializer<Object> findNullValueSerializer(BeanProperty property) throws JsonMappingException {
if (String.class.equals(property.getType().getRawClass())) {
return nullAsEmptyStringSerializer;
} else {
return super.findNullValueSerializer(property);
}
}
/**
* Needed for the abstract implementation
*
* @param serializationConfig dunno
* @param serializerFactory dunno
* @return our singleton instance that delegates for everything else.
*/
@Override
public DefaultSerializerProvider createInstance(SerializationConfig serializationConfig, SerializerFactory serializerFactory) {
return new NullStringFriendlySerializerProvider(this, serializationConfig, serializerFactory);
}
}
一旦你有了这个类,你需要在 ObjectMapper 上设置它。我对网上提到的其他选项没有任何运气,但我确实在我的 Spring Boot 应用程序中得到了这个工作。它是一个允许您自定义 ObjectMapper 的钩子。
@Configuration
public static class JacksonConfig {
/**
* We need to configure with this implementation so that we write a null value in a string field as empty string instead of null.
*
* @return the builder customizer.
*/
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizeObjectMapper() {
return builder -> builder.postConfigurer(mapper -> {
mapper.setSerializerProvider(new NullStringFriendlySerializerProvider((DefaultSerializerProvider) mapper.getSerializerProvider()));
}
);
}
}