springboot对象序列化自定义序列化注解

这篇具有很好参考价值的文章主要介绍了springboot对象序列化自定义序列化注解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

在开发中有时候会遇到一些内容返回时需要翻译,或者一些内容在序列化之前需要特殊处理(脱敏啥的)。

一般对单个属性可以直接用jackson的序列化注解对某个属性单独处理
com.fasterxml.jackson.databind.annotation.JsonSerialize(using= xxx.class)

但是直接使用不太灵活,可以进一步引入注解,配上参数来灵活的序列化。

这里就会涉及到
com.fasterxml.jackson.databind.ser.ContextualSerializer
它可以通过回调拿到序列化的属性上的注解参数。

我的jdk版本是17
springboot3.1.2
因为用了spring-web,默认用的就是jackson,所以不需要再额外引入jackson依赖了

自定义注解序列化化

通过com.fasterxml.jackson.databind.ser.ContextualSerializer序列化时获取字段上的注解信息;
ContextualSerializer.createContextual方法只会在第一次序列化字段时调用(因为字段的上下文信息在运行期不会改变),所以不用担心影响性能。
类似JsonFormat注解也是这样使用的

package org.xxx.common.translation.annotation;

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.qps.common.translation.core.handler.TranslationHandler;

import java.lang.annotation.*;

/**
 * 通用翻译注解
 */
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@Documented
//让jackson的注解拦截器(com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector)能发现当前注解
@JacksonAnnotationsInside
//指定当前注解修饰的属性/方法使用具体哪个序列化类来序列化
@JsonSerialize(using = TranslationHandler.class)
public @interface Translation {

    /**
     * 类型 (需与实现类上的 {@link TranslationType} 注解type对应)
     * <p>
     * 默认取当前字段的值 如果设置了 @{@link Translation#mapper()} 则取映射字段的值
     */
    String type();

    /**
     * 映射字段 (如果不为空则取此字段的值)
     */
    String mapper() default "";

    /**
     * 其他条件 例如: 字典type(sys_user_sex)
     */
    String other() default "";

}









package org.xxx.xxx.translation.core.handler;

import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import org.xxx.common.core.utils.StringUtils;
import org.xxx.common.core.utils.reflect.ReflectUtils;
import org.xxx.common.translation.annotation.Translation;
import org.xxx.common.translation.core.TranslationInterface;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 翻译处理器
 * 通过回调(ContextualSerializer.createContextual),将声明的属性上的Translation注解,传递给当前的序列化器
 */
@Slf4j
public class TranslationHandler extends JsonSerializer<Object> implements ContextualSerializer {

    /**
     * 全局翻译实现类映射器
     */
    public static final Map<String, TranslationInterface<?>> TRANSLATION_MAPPER = new ConcurrentHashMap<>();

    private Translation translation;

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
    	//这里是通过一个接口,提前定义好了一批翻译类,这里通过注解上的type去获取对应的翻译类
        TranslationInterface<?> trans = TRANSLATION_MAPPER.get(translation.type());
        
        if (ObjectUtil.isNotNull(trans)) {
            // 如果映射字段不为空 则取映射字段的值
            if (StringUtils.isNotBlank(translation.mapper())) {
            	//通过反射去调用注解中指定的属性(比如shopName通过shopId去翻译)
                value = ReflectUtils.invokeGetter(gen.getCurrentValue(), translation.mapper());
            }
            // 如果为 null 直接写出
            if (ObjectUtil.isNull(value)) {
                gen.writeNull();
                return;
            }
			//调用翻译类进行翻译
            Object result = trans.translation(value, translation.other());
            gen.writeObject(result);
        } else {
            gen.writeObject(value);
        }
    }

	//通过回调,在第一次调用的时候获取注解参数,并赋值给当前class中的注解变量
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        Translation translation = property.getAnnotation(Translation.class);
        if (Objects.nonNull(translation)) {
            this.translation = translation;
            return this;
        }
        return prov.findValueSerializer(property.getType(), property);
    }
}

BeanSerializerModifier自定义null序列化

package com.xxx.xxx.translation.core.handler;

import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;

import java.util.List;

/**
 * Bean 序列化修改器 自定义 Null 值修改
 */
public class TranslationBeanSerializerModifier extends BeanSerializerModifier {

    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
                                                     List<BeanPropertyWriter> beanProperties) {
        for (BeanPropertyWriter writer : beanProperties) {
            //这里做个业务判断,和上面的序列化对象TranslationHandler对应
            if (writer.getSerializer() instanceof TranslationHandler) {
            	//简单来说就是给当前属性声明一个null值的序列化处理对象
                writer.assignNullSerializer(writer.getSerializer());
            }
        }
        return beanProperties;
    }

}

注册null值序列化文章来源地址https://www.toymoban.com/news/detail-731859.html

package com.xxx.common.translation.config;
import com.xxx.common.translation.core.handler.TranslationBeanSerializerModifier;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;


@Slf4j
@Configuration
public class TranslationConfig {

    @Resource
    private ObjectMapper objectMapper;

    @PostConstruct
    public void init() {
        // 设置 Bean 序列化修改器
        objectMapper.setSerializerFactory(
            objectMapper.getSerializerFactory()
                .withSerializerModifier(new TranslationBeanSerializerModifier()));
    }

}

到了这里,关于springboot对象序列化自定义序列化注解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot利用自定义json序列化器实现敏感字段数据脱敏

    物料准备: 1.hutool依赖 2.自定义的jackson序列化器 3.测试@JsonSerialize效果 因为案例代码用到了hutool提供的DesensitizedUtil数据脱敏工具类,这里要引入hutool的依赖。 如果你需要自定义 数据脱敏的逻辑,可以不引入这个依赖 自定义一个手机号脱敏序列化器 自定义一个邮箱脱敏序列化

    2024年02月12日
    浏览(52)
  • Java进阶(4)——结合类加载JVM的过程理解创建对象的几种方式:new,反射Class,克隆clone(拷贝),序列化反序列化

    1.类什么时候被加载到JVM中,new,Class.forName: Class.forName(“包名.类名”); 2.创建对象的方式,反射,本质是获得类的类对象Class; 3.克隆clone,深拷贝,浅拷贝的对比; 4.序列化和反序列化的方式; Hello h; // 此时没有用Hello,jvm并没有进行类加载 看到new : new Book() Class.forName:

    2024年02月12日
    浏览(33)
  • 【优化技术专题】「性能优化系列」针对Java对象压缩及序列化技术的探索之路

    序列化和反序列化 序列化就是指把对象转换为字节码; 对象传递和保存时,保证对象的完整性和可传递性。把对象转换为有字节码,以便在网络上传输或保存在本地文件中; 反序列化就是指把字节码恢复为对象; 根据字节流中保存的对象状态及描述信息,通过反序列化重建

    2024年01月22日
    浏览(39)
  • Qt 对象序列化/反序列化

    阅读本文大概需要 3 分钟 日常开发过程中,避免不了对象序列化和反序列化,如果你使用 Qt 进行开发,那么有一种方法实现起来非常简单和容易。 我们知道 Qt 的元对象系统非常强大,基于此属性我们可以实现对象的序列化和反序列化操作。 比如有一个学生类,包含以下几

    2024年02月13日
    浏览(28)
  • 4.4. 对象序列化与反序列化

    在本节中,我们将详细讨论Java中的对象序列化与反序列化概念、使用方法以及实例。对象序列化是将对象的状态信息转换为字节流的过程,而反序列化则相反,是将字节流恢复为对象的过程。 4.4.1 为什么需要对象序列化? 对象序列化的主要目的是为了在不同的系统间传输对

    2024年02月07日
    浏览(39)
  • WEB攻防-Java安全&原生反序列化&SpringBoot攻防&heapdump提取&CVE

    知识点: 1、Java安全-原生反序列化-3大类接口函数利用 2、Java安全-SpringBoot攻防-泄漏安全CVE安全 序列化是将Java对象转换成字节流的过程。而反序列化是将字节流转换成Java对象的过程,java序列化的数据一般会以标记( ac ed 00 05 )开头,base64编码的特征为 rO0AB 。 JAVA常见的序列化

    2024年02月03日
    浏览(28)
  • jackson自定义序列化反序列化

    自定义序列化 序列化主要作用在返回数据的时候 以BigDecimal统一返回3位小数为例 自定义序列化处理类 继承jackson的 JsonSerializer 类,重写 serialize 方法 使用的时候,可以直接使用Jackson的 @JsonSerialize 注解 自定义反序列化 接收前端传入数据 继承 JsonDeserializer 类,重写 deserializ

    2024年02月13日
    浏览(33)
  • 【Linux】自定义协议+序列化+反序列化

    喜欢的点赞,收藏,关注一下把! 协议是一种 “约定”。在前面我们说过父亲和儿子约定打电话的例子,不过这是感性的认识,今天我们理性的认识一下协议。 socket api的接口, 在读写数据时,都是按 “字符串”(其实TCP是字节流,这里是为了理解) 的方式来发送接收的。如

    2024年04月08日
    浏览(30)
  • jackjson自定义序列化和反序列化

    JRT引用的jackjson作为json处理库。由于JRT.ORM要求表不用datetime类型,把日期和时间用Int存储,所以ORM要支持日期时间的转换。为什么要把日期时间不用datetime而用Int,比如日期:20240117,时间就是从0点到当前的秒数。因为不用datetime兼容性好,不会因为不同库datetime函数不同而要

    2024年01月18日
    浏览(26)
  • SharedPreferences工具类保存List对象,自动完成序列化和反序列化

    以下是一个示例的SharedPreferences工具类,其中包含了setList()和getList()方法,用于将List序列化为JSON字符串并存储到SharedPreferences中,以及从SharedPreferences中获取JSON字符串并反序列化为List对象: 在上述代码中,我们定义了一个SharedPreferencesUtils工具类,其中包含了setList()和getLis

    2024年02月16日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包