Jackson序列化(7) —使用BeanSerializerModifier定义Jackson的序列化方式

时间:2021-6-4 作者:qvyue

需求:返回前端的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());
    }
}
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。