需求:返回前端的JSON报文,对于null,String格式要返回””,Number格式需要返回0,array格式需要返回[],boolean类型需要返回false。
最终的解决方案是使用自定义BeanSerializerModifier来影响序列化方式。
1. 源码分析
Jackson依赖BeanPropertyWriter
对象对每一个属性进行序列化和反序列化。
对于null值的序列化和反序列化,提供了com.fasterxml.jackson.databind.ser.BeanPropertyWriter#_nullSerializer
序列化类。
@Override
public void serializeAsField(Object bean, JsonGenerator gen,
SerializerProvider prov) throws Exception {
// inlined 'get()'
final Object value = (_accessorMethod == null) ? _field.get(bean)
: _accessorMethod.invoke(bean, (Object[]) null);
// Null handling is bit different, check that first
if (value == null) {
if (_nullSerializer != null) {
gen.writeFieldName(_name);
//使用null值序列化类来实现
_nullSerializer.serialize(null, gen, prov);
}
return;
}
...
}
那么如何修改BeanPropertyWriter中的_nullSerializer呢?
public class BeanSerializerFactory
extends BasicSerializerFactory
implements java.io.Serializable // since 2.1
{
protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvider prov,
JavaType type, BeanDescription beanDesc, boolean staticTyping)
throws JsonMappingException
{
...
// 获取到每个属性的BeanPropertyWriter集合对象
List props = findBeanProperties(prov, beanDesc, builder);
if (props == null) {
props = new ArrayList();
} else {
props = removeOverlappingTypeIds(prov, beanDesc, builder, props);
}
// [databind#638]: Allow injection of "virtual" properties:
prov.getAnnotationIntrospector().findAndAddVirtualProperties(config, beanDesc.getClassInfo(), props);
// [JACKSON-440] Need to allow modification bean properties to serialize:
if (_factoryConfig.hasSerializerModifiers()) {
//遍历所有自定义的BeanSerializerModifier对象,修改props的集合
for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
props = mod.changeProperties(config, beanDesc, props);
}
}
...
}
}
思路:我们可以修改BeanSerializerFactory对象中的_factoryConfig属性,添加自定义serializerModifiers对象。从而影响对象List。替换BeanPropertyWriter对象中的_nullSerializer属性,实现自定义的serialize方法。
2. 实现
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import java.util.*;
public class CustomizeBeanSerializerModifier extends BeanSerializerModifier {
public static final String ARRAY_TYPE = "array";
public static final String STRING_TYPE = "string";
public static final String BOOLEAN_TYPE = "boolean";
public static final String NUMBER_TYPE = "number";
public static final String OBJECT_TYPE = "object";
public static final Map> map = new HashMap>() {{
put(ARRAY_TYPE, new CustomizeNullJsonSerializer.NullArrayJsonSerializer());
put(STRING_TYPE, new CustomizeNullJsonSerializer.NullStringJsonSerializer());
put(BOOLEAN_TYPE, new CustomizeNullJsonSerializer.NullBooleanJsonSerializer());
put(NUMBER_TYPE, new CustomizeNullJsonSerializer.NullNumberJsonSerializer());
put(OBJECT_TYPE, new CustomizeNullJsonSerializer.NullObjectJsonSerializer());
}};
@Override
public List changeProperties(SerializationConfig config, BeanDescription beanDesc, List beanProperties) {
//替换内部的方法
for(BeanPropertyWriter beanPropertyWriter:beanProperties){
String type = getType(beanPropertyWriter);
//获取对应类型的空值转换器
JsonSerializer objectJsonSerializer = map.get(type);
if(objectJsonSerializer!=null){
//分配空值转换器
beanPropertyWriter.assignNullSerializer(objectJsonSerializer);
}
}
return beanProperties;
}
public String getType(BeanPropertyWriter p) {
if (isArrayType(p)) {
return ARRAY_TYPE;
}
if (isStringType(p)) {
return STRING_TYPE;
}
if (isBooleanType(p)) {
return BOOLEAN_TYPE;
}
if (isNumberType(p)) {
return NUMBER_TYPE;
}
return null;
}
/**
* 是否是数组
*/
private boolean isArrayType(BeanPropertyWriter writer) {
Class> clazz = writer.getType().getRawClass();
return clazz.isArray() || Collection.class.isAssignableFrom(clazz);
}
/**
* 是否是String
*/
private boolean isStringType(BeanPropertyWriter writer) {
Class> clazz = writer.getType().getRawClass();
return CharSequence.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz);
}
/**
* 是否是数值类型
*/
private boolean isNumberType(BeanPropertyWriter writer) {
Class> clazz = writer.getType().getRawClass();
return Number.class.isAssignableFrom(clazz);
}
/**
* 是否是boolean
*/
private boolean isBooleanType(BeanPropertyWriter writer) {
Class> clazz = writer.getType().getRawClass();
return clazz.equals(Boolean.class);
}
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
public class CustomizeNullJsonSerializer {
/**
* 数组集合类
*/
public static class NullArrayJsonSerializer extends JsonSerializer {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartArray();
gen.writeEndArray();
}
}
/**
* String
*/
public static class NullStringJsonSerializer extends JsonSerializer {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString("");
}
}
/**
* Number
*/
public static class NullNumberJsonSerializer extends JsonSerializer {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeNumber(0);
}
}
/**
* Boolean
*/
public static class NullBooleanJsonSerializer extends JsonSerializer {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeBoolean(false);
}
}
/**
* Object
*/
public static class NullObjectJsonSerializer extends JsonSerializer {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
gen.writeEndObject();
}
}
}
测试代码:
public class TestJackson {
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializerFactory(objectMapper.getSerializerFactory().withSerializerModifier(new CustomizeBeanSerializerModifier()));
OrderDto orderDto=new OrderDto();
try {
String s = objectMapper.writeValueAsString(orderDto);
System.out.println(s);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}
3. 修改@RequestBody和@ResponseBody的序列化方式
加入断点:org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters(org.springframework.http.HttpInputMessage, org.springframework.core.MethodParameter, java.lang.reflect.Type)
public class ContentMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
public ContentMappingJackson2HttpMessageConverter() {
super();
objectMapper.setSerializerFactory(objectMapper.getSerializerFactory().withSerializerModifier(new CustomizeBeanSerializerModifier()));
}
//决定是否使用该类作为消息转换器进行序列化。
@Override
public boolean canWrite(Class> clazz, MediaType mediaType) {
return super.canWrite(clazz, mediaType);
}
}
优先级最高,注意不要使用@EnableWebMvc
注解。
@Configuration
public class MessageConverterConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List> converters) {
converters.add(0, new ContentMappingJackson2HttpMessageConverter());
}
}