我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java整合Jackson实现反序列化器流程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java整合Jackson实现反序列化器流程

在使用 Jackson 时很多时候在自定义的数据结构时通过本身自带的序列化器可能实现不了自定义的结构转换,比如:需要从Json 字符串中读取某个字段,根据某个字段转换为对应的实体类,例如下面的结构,我需要根据 Json 字符串中的 messageType 字段转换为对应的实体,这时候我们可以通过自定义序列化器来进行转换

{
    "messageId": "1665709790068",
    "timestamp": 1665709790068,
    "point": "123.33, 123.555",
    "messageType": "MODEL",
    "payload": {
        "method": "POST",
        "modelType": "EVENT",
        "output": {
            "ouaaa": "name"
        },
        "timestamp": 1665709790068
    }
}

1. 实体类

这里 payload 可以使用成泛型通过指定对应的类型来转换为对应的实体类型

public class UniversalMessage<T extends Payload> {
    
    public static final String PAYLOAD = "payload";
    
    public static final String MESSAGE_ID = "messageId";
    
    public static final String TIMESTAMP = "timestamp";
    
    public static final String POINT = "point";
    
    public static final String MESSAGE_TYPE = "messageType";
    private static final long serialVersionUID = -3703724430631400996L;
    protected String messageId;
    protected Long timestamp;
    protected String point;
    protected MessageType messageType;
    private T payload;
}

下面是定义好的 Payload 实现类,这里我们定义一个就行了 ModelType 定义的枚举类型,随便写就行了,只要跟后面获取序列化器对应就好

@Type(value = "MODEL") //填写消息类型
public class ModelEventPayload implements Payload {
    
    private static final long serialVersionUID = -4371712921890795815L;
    private Map<String, Object> output;
    private Long timestamp;
    protected ModelType modelType;
    protected String method;
}

2. 反序列化器

反序列化器的整体结构

PayloadDeserialize 实现了 JacksonStdDeserializer 序列化器

  • 其中用到了 parser 里面的 ObjectCodec 对象编码,用于将对应的 Json 格式转换为实体
  • Jackon会将 Json 字符串中每个结构都会转换对应的类型添加到树结构中,例如:字符串就会转换为 TextNode,对象就会转换为 ObjectNode

其中根据每个转换类型,我这里封装了一个 DeserializeForType<Payload> 接口类型,用于根据自定的类型获取序列化器,用于替换写多个 If else 代码不美观

  • 接口里面定义一个 type() 方法,实现类用于实现,当前类用于什么类型的转换
  • 上面 Json 接口中,通过 messageType 转换了之后可能还需要通过实体中的 modelType 来进行转换,这里我又通过实现 DeserializeForType<Payload> 创建了两个匿名类 event()other() 方法返回,先根据 messageType 转换了,然后再根据 modelType 获取对应的反序列化器进行转换
public class PayloadDeserialize extends StdDeserializer<UniversalMessage<Payload>> {
    
    private static final long serialVersionUID = 7922419965896101563L;
    
    public static final String MESSAGE_TYPE = "messageType";
    
    public static final String PAYLOAD = "payload";
    
    protected PayloadDeserialize() {
        this(null);
    }
    
    protected PayloadDeserialize(Class<?> vc) {
        super(vc);
    }
    
    @Override
    public UniversalMessage<Payload> deserialize(JsonParser jsonParser,
    DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
    	//获取到对象编码对象,用当前对应可以对字符串进行转换
        ObjectCodec codec = jsonParser.getCodec();
        //读取出整个消息体的树型结构
        TreeNode treeNode = codec.readTree(jsonParser);
        //解析出的节点树结构,消息字段是处于第一层结构,所以这里可以直接通过get进行获取,jackson会将字符串不同的结构解析为不同的 TreeNode类型,例如字符串就会解析成 TextNode
        TreeNode messageTypeNode = Objects.requireNonNull(treeNode.get(MESSAGE_TYPE), "消息类型不能为空");
        Class<? extends TreeNode> messageTypeNodeClass = messageTypeNode.getClass();
        boolean assignableFrom = TextNode.class.isAssignableFrom(messageTypeNodeClass);
        Assertions.isTrue(assignableFrom, "消息类型字段类型错误:" + messageTypeNodeClass + "需要 TextNode");
        String messageTypeStr = ((TextNode) messageTypeNode).asText();
        //构建外层实体消息
        UniversalMessage<Payload> universalMessage = getPayloadUniversalMessage(treeNode, codec);
        //获取到json字符串中的 payload
        TreeNode payloadNode = treeNode.get(PAYLOAD);
        DeserializeForType<Payload> deserializeForType = DeserializeTypeContext.get(messageTypeStr);
        Objects.requireNonNull(deserializeForType, "不支持当前消息类型:" + messageTypeStr);
        //对 payload进行解析
        Payload payload = deserializeForType.deserialize(codec, payloadNode);
        universalMessage.setPayload(payload);
        return universalMessage;
    }
    
    private UniversalMessage<Payload> getPayloadUniversalMessage(TreeNode treeNode, ObjectCodec codec) throws IOException {
        ObjectNode node = (ObjectNode) treeNode;
        String messageId = Objects.requireNonNull(node.get(UniversalMessage.MESSAGE_ID), "消息ID不能为空").asText();
        String messageType = Objects.requireNonNull(node.get(UniversalMessage.MESSAGE_TYPE), "消息类型不能为空").asText();
        long timestamp = Objects.requireNonNull(node.get(UniversalMessage.TIMESTAMP), "时间戳不能为空").asLong();
        String point = Objects.requireNonNull(node.get(UniversalMessage.POINT), "Point不能为空").asText();
        return UniversalMessage.builder()
            .messageId(messageId)
            //枚举转换的工具,这里可以自己封装一个,根据名称进行转换
            .messageType(EnumUtils.nameOf(MessageType.class, messageType.toUpperCase()))
            .timestamp(timestamp)
            .point(point).build();
    }
    
    static class DeserializeTypeContext {
        
        private static Map<String, DeserializeForType<Payload>> deserializeForTypeMap = new HashMap<>(4);
        static {
            add(new ModelDeserialize());
            //如果有新的类型,直接在这里添加,这里也可以做成 spring容器管理进行注入
        }
        
        public static void add(DeserializeForType deserializeForType) {
            Assertions.notNull(deserializeForType, "序列化器不能为空");
            deserializeForTypeMap.putIfAbsent(deserializeForType.getType(), deserializeForType);
        }
        
        public static DeserializeForType<Payload> get(String type) {
            Assertions.notBlank(type, "消息类型不能为空");
            return deserializeForTypeMap.get(type);
        }
    }
    
    interface DeserializeForType<T extends Payload> {
        
        T deserialize(ObjectCodec codec,  TreeNode node) throws IOException;
        
        String getType();
    }
    
    public abstract static class AbstractDeserialize<T extends Payload> implements DeserializeForType<T> {
        
        private final String type;
        
        public AbstractDeserialize(String type) {
            this.type = type;
        }
        
        @Override
        public String getType() {
            return this.type;
        }
    }
    
    public static class ModelDeserialize extends AbstractDeserialize<Payload> {
        
        public static final String TYPE = "MODEL";
        
        public static final String MODEL_TYPE = "modelType";
        
        private static final Map<String, DeserializeForType<Payload>> MODEL_TYPE_MAP = new HashMap<>(4);
        static {
        	//这里根据 MODEL 类型又封装了几个子类型的方法进行转换
            add(other());
            add(event());
        }
        
        public ModelDeserialize() {
            super(TYPE);
        }
        
        @Override
        public Payload deserialize(ObjectCodec codec, TreeNode node) throws IOException {
            TreeNode modelTypeNode = Objects.requireNonNull(node.get(MODEL_TYPE), "消息类型不能为空");
            Class<? extends TreeNode> modelTypeNodeClass = modelTypeNode.getClass();
            boolean assignableFrom = TextNode.class.isAssignableFrom(modelTypeNodeClass);
            Assertions.isTrue(assignableFrom, "模型消息类型字段类型错误:" + modelTypeNodeClass + "需要 TextNode");
            //string 类型的字段会被转换成 TextNode的节点
            String messageTypeStr = ((TextNode) modelTypeNode).asText();
            DeserializeForType<Payload> deserializeForType = MODEL_TYPE_MAP.get(messageTypeStr);
            Assertions.notNull(deserializeForType, "模型:" + messageTypeStr + ",序列化器为空");
            return deserializeForType.deserialize(codec, node);
        }
        
        public static void add(DeserializeForType<Payload> deserializeForType) {
            Assertions.notNull(deserializeForType, "对应类型的序列化器不能为空");
            MODEL_TYPE_MAP.putIfAbsent(deserializeForType.getType(), deserializeForType);
        }
        
        private static DeserializeForType<Payload> other() {
            return new DeserializeForType<Payload>() {
                @Override
                public Payload deserialize(ObjectCodec codec, TreeNode node) throws IOException {
                    return node.traverse(codec).readValueAs(ModelOtherPayload.class);
                }
                @Override
                public String getType() {
                    return "OTHER";
                }
            };
        }
        
        private static DeserializeForType<Payload> event() {
            return new DeserializeForType<Payload>() {
                @Override
                public Payload deserialize(ObjectCodec codec, TreeNode node) throws IOException {
                    return node.traverse(codec).readValueAs(ModelEventPayload.class);
                }
                @Override
                public String getType() {
                    return "EVENT";
                }
            };
        }
    }
}

3. 序列化器

序列化器就比较简单了,可以先根据 payload 实体获取到对应的类型,写入一个 string类型 messageType 然后再写 payload 作为对象进行写成 Json 格式(其他几个字段我就不写了,根据对应的类型调用对应类型的 write方法即可)

public class PayloadSerialize extends StdSerializer<UniversalMessage<Payload>> {
    private static final long serialVersionUID = 7679701332948432903L;
    protected PayloadSerialize() {
        this(null);
    }
    protected PayloadSerialize(Class<Payload> t) {
        super(t);
    }
    @Override
    public void serialize(UniversalMessage<Payload> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        Payload payload = value.getPayload();
        gen.writeStartObject();
        if (payload != null) {
            Type type = payload.getClass().getAnnotation(Type.class);
            if (type != null) {
                gen.writeStringField("messageType", type.value());
            }
        }
        gen.writeObjectField("payload", payload);
        gen.writeEndObject();
    }
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Type {
    String value();
}

到此这篇关于Java整合Jackson实现反序列化器流程的文章就介绍到这了,更多相关Java Jackson反序列化器内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java整合Jackson实现反序列化器流程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java整合Jackson实现反序列化器流程

Jackson是一个开源的Java序列化和反序列化工具,可以将Java对象序列化为XML或JSON格式的字符串,以及将XML或JSON格式的字符串反序列化为Java对象。由于其使用简单,速度较快,且不依靠除JDK外的其他库,被众多用户所使用
2023-01-14

jackson多态反序列化怎么实现

在Jackson中,实现多态反序列化可以使用@JsonTypeInfo注解和@JsonSubTypes注解。首先,在父类上使用@JsonTypeInfo注解,指定多态类型的字段名和默认的多态类型处理策略。例如:@JsonTypeInfo(
2023-10-22

Java序列化与反序列化怎么实现

本篇内容主要讲解“Java序列化与反序列化怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java序列化与反序列化怎么实现”吧!序列化与反序列化概念序列化 (Serialization)是
2023-06-02

Java中如何实现序列化和反序列化

本篇文章给大家分享的是有关Java中如何实现序列化和反序列化,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。序列化序列化:将对象转换为二进制序列在网络中传输或保存到磁盘反序列化:
2023-06-15

Java的序列化与反序列化怎么实现

本篇内容介绍了“Java的序列化与反序列化怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Java对象的序列化Java平台允许我们在内
2023-07-04

如何在Java中实现序列化与反序列化

本篇文章给大家分享的是有关如何在Java中实现序列化与反序列化,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java可以用来干什么Java主要应用于:1. web开发;2. A
2023-06-14

Java IO流对象的序列化和反序列化实例详解

Java—IO流 对象的序列化和反序列化序列化的基本操作  1.对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化。  2.序列化流(ObjectOutputStream),writeObject 方法用于将对象写入输出
2023-05-31

Java怎么用Jackson序列化实现数据脱敏

这篇“Java怎么用Jackson序列化实现数据脱敏”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java怎么用Jackso
2023-07-05

Java利用Jackson序列化实现数据脱敏详解

在项目中有些敏感信息不能直接展示,比如客户手机号、身份证、车牌号等信息,展示时均需要进行数据脱敏,防止泄露客户隐私。本文将利用Jackson序列化实现数据脱敏,需要的可以参考一下
2023-05-13

Jackson反序列化时怎么实现大小写不敏感设置

这篇文章主要讲解了“Jackson反序列化时怎么实现大小写不敏感设置”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Jackson反序列化时怎么实现大小写不敏感设置”吧!常用配置ObjectM
2023-06-20

序列化与反序列化如何在java项目中实现

序列化与反序列化如何在java项目中实现 ?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。 1.Java序列化与反序列化 Java序列化是指把Java对象转换为字
2023-05-31

在Java中,如何实现对象的序列化与反序列化?(请描述Java对象序列化和反序列化的过程及其用途。)

Java对象的序列化是一种将对象转换为二进制流的过程,用于存储或传输。反序列化则是将二进制流还原为对象的逆过程。序列化过程包括将对象状态和类型信息写入二进制流,而反序列化过程从二进制流中读取信息并重建对象。Java序列化和反序列化广泛用于持久化、网络传输、轻量级通信、配置管理和缓存。可序列化的对象必须实现java.io.Serializable接口,并可定义serialVersionUID字段以确保跨版本兼容性。
在Java中,如何实现对象的序列化与反序列化?(请描述Java对象序列化和反序列化的过程及其用途。)
2024-04-02

SpringBoot怎么整合Redis实现序列化存储Java对象

今天小编给大家分享一下SpringBoot怎么整合Redis实现序列化存储Java对象的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解
2023-07-05

SpringBoot整合Redis实现序列化存储Java对象的操作方法

目录一、背景1、思考2、方案二、源码分析三、注入RedisTemplate1、引入依赖2、Redis 连接信息3、Redis 核心配置类4、Redis工具类四、测试1、创建 Java 实体类 UserInfo2、测试用例3、测试结果之前介绍
2023-03-23

Java对象流如何实现序列化的类

小编给大家分享一下Java对象流如何实现序列化的类,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java有哪些集合类Java中的集合主要分为四类:1、List列表
2023-06-14

CMS与自动化最佳拍档:实现无缝整合,优化网站工作流程

CMS与自动化强强联手,打造无缝集成、高效管理的网站工作流程,助力网站运营再创辉煌。
CMS与自动化最佳拍档:实现无缝整合,优化网站工作流程
2024-02-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录