需求:返回前端的JSON報(bào)文,對(duì)于null弛矛,String格式要返回""够吩,Number格式需要返回0,array格式需要返回[]丈氓,boolean類(lèi)型需要返回false周循。
最終的解決方案是使用自定義BeanSerializerModifier來(lái)影響序列化方式。
1. 源碼分析
Jackson依賴(lài)BeanPropertyWriter
對(duì)象對(duì)每一個(gè)屬性進(jìn)行序列化和反序列化万俗。
對(duì)于null值的序列化和反序列化湾笛,提供了com.fasterxml.jackson.databind.ser.BeanPropertyWriter#_nullSerializer
序列化類(lèi)。
@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值序列化類(lèi)來(lái)實(shí)現(xiàn)
_nullSerializer.serialize(null, gen, prov);
}
return;
}
...
}
那么如何修改BeanPropertyWriter中的_nullSerializer呢该编?
public class BeanSerializerFactory
extends BasicSerializerFactory
implements java.io.Serializable // since 2.1
{
protected JsonSerializer<Object> constructBeanOrAddOnSerializer(SerializerProvider prov,
JavaType type, BeanDescription beanDesc, boolean staticTyping)
throws JsonMappingException
{
...
// 獲取到每個(gè)屬性的BeanPropertyWriter集合對(duì)象
List<BeanPropertyWriter> props = findBeanProperties(prov, beanDesc, builder);
if (props == null) {
props = new ArrayList<BeanPropertyWriter>();
} 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對(duì)象迄本,修改props的集合
for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
props = mod.changeProperties(config, beanDesc, props);
}
}
...
}
}
思路:我們可以修改BeanSerializerFactory對(duì)象中的_factoryConfig屬性,添加自定義serializerModifiers對(duì)象课竣。從而影響對(duì)象List<BeanPropertyWriter>嘉赎。替換BeanPropertyWriter對(duì)象中的_nullSerializer屬性,實(shí)現(xiàn)自定義的serialize方法于樟。
2. 實(shí)現(xiàn)
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<String, JsonSerializer<Object>> map = new HashMap<String, JsonSerializer<Object>>() {{
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<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
//替換內(nèi)部的方法
for(BeanPropertyWriter beanPropertyWriter:beanProperties){
String type = getType(beanPropertyWriter);
//獲取對(duì)應(yīng)類(lèi)型的空值轉(zhuǎn)換器
JsonSerializer<Object> objectJsonSerializer = map.get(type);
if(objectJsonSerializer!=null){
//分配空值轉(zhuǎn)換器
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;
}
/**
* 是否是數(shù)組
*/
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);
}
/**
* 是否是數(shù)值類(lèi)型
*/
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 {
/**
* 數(shù)組集合類(lèi)
*/
public static class NullArrayJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartArray();
gen.writeEndArray();
}
}
/**
* String
*/
public static class NullStringJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString("");
}
}
/**
* Number
*/
public static class NullNumberJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeNumber(0);
}
}
/**
* Boolean
*/
public static class NullBooleanJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeBoolean(false);
}
}
/**
* Object
*/
public static class NullObjectJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
gen.writeEndObject();
}
}
}
測(cè)試代碼:
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的序列化方式
加入斷點(diǎn):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()));
}
//決定是否使用該類(lèi)作為消息轉(zhuǎn)換器進(jìn)行序列化公条。
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return super.canWrite(clazz, mediaType);
}
}
優(yōu)先級(jí)最高,注意不要使用@EnableWebMvc
注解迂曲。
@Configuration
public class MessageConverterConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0, new ContentMappingJackson2HttpMessageConverter());
}
}