Jackson序列化(7) —使用BeanSerializerModifier定義Jackson的序列化方式(對(duì)于null,String格式要返回"")

需求:返回前端的JSON報(bào)文,對(duì)于null,String格式要返回"",Number格式需要返回0,array格式需要返回[],boolean類型需要返回false。

最終的解決方案是使用自定義BeanSerializerModifier來影響序列化方式。

1. 源碼分析

Jackson依賴BeanPropertyWriter對(duì)象對(duì)每一個(gè)屬性進(jìn)行序列化和反序列化。
對(duì)于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值序列化類來實(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)類型的空值轉(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ù)值類型
     */
    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ù)組集合類
     */
    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()));
    }

    //決定是否使用該類作為消息轉(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());
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容