Jackson 2.x 系列【21】序列化修饰器 BeanSerializerModifier

210 阅读5分钟

有道无术,术尚可求,有术无道,止于术。

本系列Jackson 版本 2.17.0

源码地址:https://gitee.com/pearl-organization/study-jaskson-demo

1. 概述

Java Bean对象的序列化过程是比较复杂的,因为它可能包含了各种类型的属性,在Jackson中该过程是交由BeanSerializer来负责的。同时Jackson也提供了扩展机制,允许通过BeanSerializerModifierBeanSerializer的创建过程中进行干预和修改,从而实现对序列化过程的自定义。

2. 抽象方法

BeanSerializerModifier定义了很多抽象的钩子方法。

2.1 changeProperties

changeProperties是最常用的方法的,目的是提供一个钩子,允许用户自定义和调整BeanSerializer序列化过程中使用的属性集合。通过修改这个集合,可以控制哪些属性应该被序列化,哪些应该被忽略,或者替换为其他属性等。

    /**
     * 自定义和调整 BeanSerializer 序列化过程中使用的属性集合
     *
     * @param config         序列化配置
     * @param beanDesc       Bean 对象信息
     * @param beanProperties 属性集合
     * @return 属性集合
     */
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
                                                     BeanDescription beanDesc, 
                                                     List<BeanPropertyWriter> beanProperties) {
        return beanProperties;
    }

2.2 orderProperties

orderProperties方法看名字就很好理解,允许自定义和调整序列化过程中属性的顺序。

    public List<BeanPropertyWriter> orderProperties(SerializationConfig config,
                                                    BeanDescription beanDesc, 
                                                    List<BeanPropertyWriter> beanProperties) {
        return beanProperties;
    }

2.3 updateBuilder

updateBuilder方法允许在序列化器构建的最后阶段进行自定义修改或替换。

    /**
     * 序列化器构建的最后阶段进行自定义修改或替换
     *
     * @param config   序列化配置
     * @param beanDesc Bean 对象信息
     * @param builder  BeanSerializer 构建者
     * @return 属性集合
     */
    public BeanSerializerBuilder updateBuilder(SerializationConfig config,
                                               BeanDescription beanDesc,
                                               BeanSerializerBuilder builder) {
        return builder;
    }

2.4 modifyXx

BeanSerializerModifier定义了很多modify开头的方法,在DeserializerFactory根据类型创建了对应的序列化器之后进行调用,允许替换或增强这个反序列化器,为其添加额外的功能。

    /**
     * 允许在 BeanSerializer 构造完成后对其进行修改或替换。
     *
     * @param config         序列化配置
     * @param beanDesc       Bean 对象信息
     * @param serializer 序列化器
     * @return 序列化器
     */
    public JsonSerializer<?> modifySerializer(SerializationConfig config,
                                              BeanDescription beanDesc,
                                              JsonSerializer<?> serializer) {
        return serializer;
    }
   /**
     * 增强或替换 ArrayType 对应的序列化器
     *
     * @param config         序列化配置
     * @param valueType      类型         
     * @param beanDesc       Bean 对象信息
     * @param serializer 序列化器
     * @return  序列化器
     */
    public JsonSerializer<?> modifyArraySerializer(SerializationConfig config,
                                                   ArrayType valueType,
                                                   BeanDescription beanDesc,
                                                   JsonSerializer<?> serializer) {
        return serializer;
    }

    /**
     * @since 2.2
     */
    public JsonSerializer<?> modifyCollectionSerializer(SerializationConfig config,
                                                        CollectionType valueType,
                                                        BeanDescription beanDesc,
                                                        JsonSerializer<?> serializer) {
        return serializer;
    }

    /**
     * @since 2.2
     */
    public JsonSerializer<?> modifyCollectionLikeSerializer(SerializationConfig config,
                                                            CollectionLikeType valueType,
                                                            BeanDescription beanDesc,
                                                            JsonSerializer<?> serializer) {
        return serializer;
    }

    /**
     * @since 2.2
     */
    public JsonSerializer<?> modifyMapSerializer(SerializationConfig config,
                                                 MapType valueType,
                                                 BeanDescription beanDesc,
                                                 JsonSerializer<?> serializer) {
        return serializer;
    }

    /**
     * @since 2.2
     */
    public JsonSerializer<?> modifyMapLikeSerializer(SerializationConfig config,
                                                     MapLikeType valueType,
                                                     BeanDescription beanDesc,
                                                     JsonSerializer<?> serializer) {
        return serializer;
    }

    /**
     * @since 2.2
     */
    public JsonSerializer<?> modifyEnumSerializer(SerializationConfig config,
                                                  JavaType valueType,
                                                  BeanDescription beanDesc,
                                                  JsonSerializer<?> serializer) {
        return serializer;
    }

    /**
     * @since 2.2
     */
    public JsonSerializer<?> modifyKeySerializer(SerializationConfig config,
                                                 JavaType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) {
        return serializer;
    }

3. 案例演示

BeanSerializerModifier的功能非常强大,几乎可以自定义很多序列化的骚操作,例如:添加额外字段、更改字段值、自定义序列化器、null值处理、字典翻译、数据脱敏等等....

下面演示一个最简单的需求,修改某个属性序列化的值,其他高级用法后面会单独介绍。当前对象有一个password属性,需要序列化为********显示:

public class UserVO {
    Long id;

    String username;
    // 省略.............
}

3.1 实现

实现BeanSerializerModifier,当存在password属性时,注册一个自定义的JsonSerializer,将值写为********

public class ModifyPasswordBeanSerializerModifier extends BeanSerializerModifier {

    /**
     * 自定义和调整 BeanSerializer 序列化过程中使用的属性集合
     *
     * @param config         序列化配置
     * @param beanDesc       Bean 对象信息
     * @param beanProperties 属性集合
     * @return 属性集合
     */
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
        System.out.println("changeProperties");
        // 查询是否开启某个特征
        boolean enabled = config.isEnabled(SerializationFeature.FAIL_ON_SELF_REFERENCES);

        // 获取当前Bean 的类型、真实 Class
        JavaType javaType = beanDesc.getType();
        Class<?> rawClass = javaType.getRawClass();

        // 循环所有属性集合
        for (BeanPropertyWriter beanPropertyWriter : beanProperties) {
            // 属性类型
            JavaType type = beanPropertyWriter.getType();
            // 属性名称
            String name = beanPropertyWriter.getName();
            // 属性的序列化器
            JsonSerializer<Object> serializer = beanPropertyWriter.getSerializer();
            // 属性的类型列化器
            TypeSerializer typeSerializer = beanPropertyWriter.getTypeSerializer();
            // 是否有Null值序列化器
            boolean hasNullSerializer = beanPropertyWriter.hasNullSerializer();
            // 获取注解
            Annotation annotation = beanPropertyWriter.getAnnotation(JsonSerialize.class);

            // 修改字段名称
            if("password".equals(name)){
                // 当前属性Writer对象,注册自定义的序列化器
                beanPropertyWriter.assignSerializer(new JsonSerializer<>() {
                    @Override
                    public void serialize(Object value, JsonGenerator jg, SerializerProvider sp) throws IOException, JsonProcessingException {
                        jg.writeString("********");
                    }
                });
            }
        }

        return beanProperties;
    }
}

PS:实际开发中,不推荐这么用,这个逻辑是全局的,会作用于所有Java Bean,重点是了解基础用法,这里可以添加自定义注解(后续讲解)。

3.2 注册

可以直接在ObjectMapper对象中注册BeanSerializerModifier

        ObjectMapper objectMapper = new ObjectMapper();
        // 创建新的 SerializerFactory,并设置 BeanSerializerModifier
        SerializerFactory serializerFactory = objectMapper.getSerializerFactory().withSerializerModifier(new ModifyPasswordBeanSerializerModifier());
        // 需要重新设置进去,因为SerializerFactory 是不可变对象
        objectMapper.setSerializerFactory(serializerFactory);

也可以新建模块并注册:

        // 使用模块注册BeanSerializerModifier:
        SimpleModule simpleModule=new SimpleModule("myModule");
        simpleModule.setSerializerModifier(new ModifyPasswordBeanSerializerModifier());
        objectMapper.registerModule(simpleModule);// 注册模块

3.3 测试

执行序列化操作:

        UserVO userVO = new UserVO();
        userVO.setId(1699657986705854464L);
        userVO.setPassword("123456");
        userVO.setUsername("jack");
        userVO.setCreateTime(LocalDateTime.now());
        String userVoJson = objectMapper.writeValueAsString(userVO);
        System.out.println(userVoJson);

可以看到原有的password值被修改了:

changeProperties
{"id":1699657986705854464,"username":"jack","password":"********","createTime":"2024-04-11 14:57:51"}

4. BeanDeserializerModifier

同样也提供了用于反序列化Java Bean对象的扩展机制,也就是BeanDeserializerModifier抽象类,在BeanDeserializer的创建过程中进行干预和修改,从而实现对反序列化过程的自定义。和BeanSerializerModifier用法一致,这里简单提一下,没必要赘述了。

public abstract class BeanDeserializerModifier implements Serializable {
    private static final long serialVersionUID = 1L;

    public List<BeanPropertyDefinition> updateProperties(DeserializationConfig config, BeanDescription beanDesc, List<BeanPropertyDefinition> propDefs) {
        return propDefs;
    }

    public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder) {
        return builder;
    }

    public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        return deserializer;
    }

    public JsonDeserializer<?> modifyEnumDeserializer(DeserializationConfig config, JavaType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        return deserializer;
    }

    public JsonDeserializer<?> modifyReferenceDeserializer(DeserializationConfig config, ReferenceType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        return deserializer;
    }

    public JsonDeserializer<?> modifyArrayDeserializer(DeserializationConfig config, ArrayType valueType, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        return deserializer;
    }

    public JsonDeserializer<?> modifyCollectionDeserializer(DeserializationConfig config, CollectionType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        return deserializer;
    }

    public JsonDeserializer<?> modifyCollectionLikeDeserializer(DeserializationConfig config, CollectionLikeType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        return deserializer;
    }

    public JsonDeserializer<?> modifyMapDeserializer(DeserializationConfig config, MapType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        return deserializer;
    }

    public JsonDeserializer<?> modifyMapLikeDeserializer(DeserializationConfig config, MapLikeType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        return deserializer;
    }

    public KeyDeserializer modifyKeyDeserializer(DeserializationConfig config, JavaType type, KeyDeserializer deserializer) {
        return deserializer;
    }
}