java:jackson 二:Custom Deserialization in Jackson

news2024/11/19 11:17:12

java:jackson 二:Custom Deserialization in Jackson

1 前言

jackson支持自定义反序列化器,参考文档地址如下:

https://www.baeldung.com/jackson

https://www.baeldung.com/jackson-deserialization

依赖如下(这里使用jackson-databind的2.14.1版本):

<properties>
    <jackson.version>2.14.1</jackson.version>
</properties>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${jackson.version}</version>
</dependency>

2 使用

2.1 Standard Deserialization

Let’s start by defining two entities and see how Jackson will deserialize a JSON representation to these entities without any customization:

package com.xiaoxu.test.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.Data;
import lombok.ToString;

/**
 * @author xiaoxu
 * @date 2022-12-22
 * spring_boot:com.xiaoxu.test.jackson.TestCustomizeJackson
 */
public class TestCustomizeJackson {
    private static ObjectMapper objectMapper = new ObjectMapper();
    static {
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
    }

    public static void testStandard() throws Exception{
        Good g = new Good();
        g.setId(1);
        g.setGoodName("苹果");

        VIPUser vipUser = new VIPUser();
        vipUser.setUid(999L);
        vipUser.setUserName("xiaoxu");
        g.setVipUser(vipUser);

        String s = objectMapper.writeValueAsString(g);
        System.out.println(s);
        String msg = "{\n" +
                "  \"id\" : 1,\n" +
                "  \"goodName\" : \"苹果\",\n" +
                "  \"vipUser\" : {\n" +
                "    \"uid\" : 999,\n" +
                "    \"userName\" : \"xiaoxu\"\n" +
                "  }\n" +
                "}";
        Good good = objectMapper.readValue(msg, Good.class);
        System.out.println(good);
    }

    public static void main(String[] args) throws Exception{
        testStandard();
    }
}

@Data
@ToString
class Good{
    public int id;
    public String goodName;
    public VIPUser vipUser;
}

@Data
@ToString
class VIPUser{
    long uid;
    String userName;
}

执行如下:

{
  "id" : 1,
  "goodName" : "苹果",
  "vipUser" : {
    "uid" : 999,
    "userName" : "xiaoxu"
  }
}
Good(id=1, goodName=苹果, vipUser=VIPUser(uid=999, userName=xiaoxu))

上述场景不需要自定义反序列化器

2.2 Custom Deserializer on ObjectMapper

this will of course fail

package com.xiaoxu.test.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

/**
 * @author xiaoxu
 * @date 2022-12-22
 * spring_boot:com.xiaoxu.test.jackson.TestCustomizeJackson2
 */
public class TestCustomizeJackson2 {
    private static ObjectMapper objectMapper = new ObjectMapper();
    static {
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
    }

    public static void testStandard2() throws Exception{
        String msg = "{\n" +
                "  \"id\" : 1,\n" +
                "  \"goodName\" : \"苹果\",\n" +
                "  \"vipUser\" : {\n" +
                "  }\n" +
                "}";
        Good good = objectMapper.readValue(msg, Good.class);
        System.out.println(good);
        /* 将反序列化的字符串的key vipUser 改为  normalUser,
        * 反序列化将报错*/
        String msg2 = "{\n" +
                "  \"id\" : 1,\n" +
                "  \"goodName\" : \"苹果\",\n" +
                "  \"normalUser\" : {\n" +
                "    \"userName\" : \"tellMe\"\n" +
                "  }\n" +
                "}";
        Good good2 = objectMapper.readValue(msg2, Good.class);
        System.out.println(good2);
    }

    public static void main(String[] args) throws Exception{
        testStandard2();
    }
}

执行将报错,因为反序列化的json中含有实体类不存在的属性:

在这里插入图片描述

We’ll solve this by doing our own deserialization with a custom Deserializer:

package com.xiaoxu.test.jackson;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;

import java.io.IOException;

/**
 * @author xiaoxu
 * @date 2022-12-22
 * spring_boot:com.xiaoxu.test.jackson.TestCustomizeJackson2
 */
public class TestCustomizeJackson2 {
    private static ObjectMapper objectMapper = new ObjectMapper();
    static {
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);

        /* 注册自定义的反序列化器 */
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addDeserializer(Good.class, new GoodDeserializer());
        objectMapper.registerModule(simpleModule);
    }

    public static void testStandard2() throws Exception{
        String msg = "{\n" +
                "  \"id\" : 1,\n" +
                "  \"goodName\" : \"苹果\",\n" +
                "  \"vipUser\" : {\n" +
                "  }\n" +
                "}";
        Good good = objectMapper.readValue(msg, Good.class);
        System.out.println("实体类:"+good+"\n");
        /* 将反序列化的字符串的key vipUser 改为  normalUser,
        * 反序列化将报错*/
        String msg2 = "{\n" +
                "  \"id\" : 1,\n" +
                "  \"goodName\" : \"苹果\",\n" +
                "  \"normalUser\" : {\n" +
                "    \"userName\" : \"tellMe\"\n" +
                "  }\n" +
                "}";
        Good good2 = objectMapper.readValue(msg2, Good.class);
        System.out.println("实体类2:"+good2+"\n");
    }

    public static void main(String[] args) throws Exception{
        testStandard2();
    }
}


class GoodDeserializer extends StdDeserializer<Good>{

    protected GoodDeserializer(){
        this(null);
    }

    protected GoodDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public Good deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
        JsonNode jNode = jsonParser.getCodec().readTree(jsonParser);
        System.out.println("node: "+jNode);

        int id = jNode.get("id").intValue();
        String goodName = jNode.get("goodName").asText();
        JsonNode normalUser = jNode.get("normalUser");

        Good good = new Good();
        good.setId(id);
        good.setGoodName(goodName);
        good.setVipUser(null);
        if(null != normalUser){
            String normalUserName = jNode.get("normalUser").get("userName").asText();

            VIPUser vipUser = new VIPUser();
            vipUser.setUid(1000000L);
            vipUser.setUserName(normalUserName);
            good.setVipUser(vipUser);
            return good;
        }

        return good;
    }
}

执行自定义反序列化器,结果如下:

node: {"id":1,"goodName":"苹果","vipUser":{}}
实体类:Good(id=1, goodName=苹果, vipUser=null)

node: {"id":1,"goodName":"苹果","normalUser":{"userName":"tellMe"}}
实体类2Good(id=1, goodName=苹果, vipUser=VIPUser(uid=1000000, userName=tellMe))

2.3 Custom Deserializer on the Class

区别于2.2的全部配置,可使用注解单独配置。

Alternatively, we can also register the deserializer directly on the class:

在这里插入图片描述
在这里插入图片描述

再次执行效果一致:

在这里插入图片描述

2.4 Custom Deserializer for a Generic Type

Let’s now create a Wrapper class that only contains a unique argument of the generic type T,The User attribute of our Item will now be of type Wrapper< User > instead.

Let’s implement a custom deserializer for this case.

First, we need to implement the ContextualDeserializer interface so that we’ll be able to get the type of the entity inside the Wrapper. We’ll do this by overriding the createContextual() method. When this method is called, the context is resolved and the actual content of the Wrapper can be retrieved via the BeanProperty argument.

We also have to extend JsonDeserializer. Thus, we can set the concrete type of the Wrapper‘s value inside deserialize():

package com.xiaoxu.test.jackson;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import lombok.Data;
import lombok.ToString;

import java.io.IOException;
import java.lang.annotation.*;

/**
 * @author xiaoxu
 * @date 2022-12-22
 * spring_boot:com.xiaoxu.test.jackson.TestCustomizeJackson3
 */
public class TestCustomizeJackson3 {

    private static ObjectMapper objectMapper = new ObjectMapper();
    static {
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);

        /* 注册自定义的序列化器、反序列化器 */
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addDeserializer(WrapClazz.class, new WrapperDeserializer());
        simpleModule.addSerializer(WrapClazz.class, new WrapperSerializer());
        objectMapper.registerModule(simpleModule);
    }

    public static String buildDto() throws JsonProcessingException {
        WrapGood wrapGood = new WrapGood();
        wrapGood.setId(111);
        wrapGood.setGoodName("美味的东西");

        NorUser norUser = new NorUser();
        norUser.setUid(555L);
        norUser.setUserName("xiaoxu");

        WrapClazz<NorUser> wrapClazz = new WrapClazz<>();
        wrapClazz.setVal(norUser);

        wrapGood.setNorUserWrapClazz(wrapClazz);

        /* 因为注册了自定义的序列化器,针对 WrapGood 的 NorUserWrapClazz,
        * 将会精确实施序列化  */
        String s = objectMapper.writeValueAsString(wrapGood);
        System.out.println("序列化的json数据:");
        System.out.println(s);
        return s;
    }

    public static void testCustomizeDeserializer() throws JsonProcessingException {
        String s = buildDto();
        WrapGood wrapGood = objectMapper.readValue(s, WrapGood.class);
        System.out.println("反序列化实体类结果:");
        System.out.println(wrapGood);
        WrapClazz<NorUser> norUserWrapClazz = wrapGood.getNorUserWrapClazz();
        System.out.println(norUserWrapClazz);
    }

    public static void main(String[] args) throws JsonProcessingException {
        testCustomizeDeserializer();
    }
}

/* 自定义序列化器 */
@SuppressWarnings(value = "rawtypes")
class WrapperSerializer extends JsonSerializer<WrapClazz> implements ContextualSerializer {

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        JavaType type = beanProperty.getType();
        System.out.println("序列化type:"+type);
        return this;
    }

    @Override
    public void serialize(WrapClazz wrapClazz, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        System.out.println("自定义序列化:");
        WrapClazz<NorUser> norUserWrapClazz = new WrapClazz<>();
        NorUser norUser = new NorUser();
        norUser.setUid(666L);
        norUser.setUserName("xiaoxuya");
        norUserWrapClazz.setVal(norUser);

        /* 序列化1: */
//        jsonGenerator.writeStartObject();
//        jsonGenerator.writeObjectField("xiaoxu",norUser);
//        jsonGenerator.writeEndObject();

        /* 序列化2:对于泛型对象的序列化,直接使用writeObject,就可以直接写入对象,序列化出来的json,将没有泛型的val这个key */
        jsonGenerator.writeObject(norUser);
    }
}

/* 自定义反序列化器 */
class WrapperDeserializer extends JsonDeserializer<WrapClazz<?>> implements ContextualDeserializer{
//    protected WrapperDeserializer(){
//        super();
//    }

    private JavaType javaType;

    @Override
    public WrapClazz<?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
        System.out.println("当前的类型:"+this.javaType);
        WrapClazz<?> wrapClazz = new WrapClazz<>();
        wrapClazz.setVal(deserializationContext.readValue(jsonParser, this.javaType));
        return wrapClazz;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext deserializationContext, BeanProperty beanProperty) throws JsonMappingException {
        System.out.println("BeanProperty:"+beanProperty);

        /* 获取 WrapGood实体类的 WrapClazz<NorUser> norUserWrapClazz 属性的注解*/
        TestMe annotation = beanProperty.getAnnotation(TestMe.class);
        if(null != annotation){
            System.out.println(annotation.value());
        }
        JavaType javaType = beanProperty.getType().containedType(0);
        System.out.println("反序列化type:"+javaType);
        this.javaType = javaType;
        return this;
    }
}

@ToString
class WrapClazz<T> {
    T val;

    public T getVal(){
        return val;
    }

    public void setVal(T val){
        this.val = val;
    }
}

@Data
@ToString
class WrapGood{
    public int id;
    public String goodName;
    @TestMe
    WrapClazz<NorUser> norUserWrapClazz;
}

@Data
@ToString
class NorUser{
    long uid;
    String userName;
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface TestMe{
    String value() default "9999";
}

执行结果如下:

序列化type:[simple type, class com.xiaoxu.test.jackson.WrapClazz<com.xiaoxu.test.jackson.NorUser>]
自定义序列化:
序列化的json数据:
{
  "id" : 111,
  "goodName" : "美味的东西",
  "norUserWrapClazz" : {
    "uid" : 666,
    "userName" : "xiaoxuya"
  }
}
BeanProperty:[property 'norUserWrapClazz']
9999
反序列化type:[simple type, class com.xiaoxu.test.jackson.NorUser]
当前的类型:[simple type, class com.xiaoxu.test.jackson.NorUser]
反序列化实体类结果:
WrapGood(id=111, goodName=美味的东西, norUserWrapClazz=WrapClazz(val=NorUser(uid=666, userName=xiaoxuya)))
WrapClazz(val=NorUser(uid=666, userName=xiaoxuya))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/110852.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于FPGA的幅频均衡带通滤波器的设计

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 数字通信系统中&#xff0c;由于多径传输、信道衰落等影响&#xff0c;在接收端会产生严重的码间干扰&#xff0c;增大误码率。为了克服码间干扰&#xff0c;提高通信系统的性能&#xff0c;在接…

记录Android Jni编译过程

Gradle配置 我们主要看这个配置文件里面吧&#xff0c;这里面有关于ndk配置的选项。 大概介绍一下&#xff0c;这里面一些字段是干嘛的。 我们看&#xff0c;这里面有两个相仿的字段&#xff0c;都是externalNativeBuild字段&#xff0c;但是位于两个不同的位置&#xff0c;其…

小程序02/小程序 响应式单位rpx 、image组件概念说明 和 mode属性介绍

一. 响应式单位rpx rpx 说明 rpx: 规定不管屏幕为多少px , 100%的屏幕宽度就是750rpx 100% 屏幕的宽度 750rpx rpx响应单位 rpx是微信小程序独有的&#xff0c;解决屏幕自适应的尺寸单位 可以根据屏幕宽度进行自适应&#xff0c;不论大小屏幕&#xff0c;规定屏幕宽为750…

数据首发!空气悬挂前装搭载率破1%,明年冲刺70万套

新能源智能化的合力变革&#xff0c;带动汽车行业进入新的发展周期&#xff1a;如何进一步提升整车轻量化、驾驶和乘坐的安全和体验。这其中&#xff0c;乘用车悬挂系统也在发生新的变化。 此前&#xff0c;除了传统固定式金属螺旋弹簧悬挂&#xff0c;主动悬架系统的前装上车主…

学计算机网络太难?原来方法没用对...

计算机世界里的三座大山: 计算机网络&#xff0c;操作系统&#xff0c;算法与数据结构。跨过去的人都是神一样的存在了。 学计算机网络也要讲究学习方法 从实际案例出发&#xff08;比如我们在浏览器输入一个网址到展示出内容中间发生了什么事情&#xff09; 计算机网络出现的…

简单记录一下怎么看package.json文件

首先每个vue工程文件从仓库克隆代码下来的时候&#xff0c;一般都会包含这个文件&#xff0c;这个文件非常重要&#xff0c;package.json包含了关于项目重要信息&#xff0c;如下图所示 其中包含了name、version、description、author、scripts、dependencies、devDependencies…

Django基础

Django 1.项目的创建 创建项目&#xff1a; 删除一些内容&#xff1a; settings.py中&#xff1a; 2.默认项目文件的介绍 3.APP 创建APP&#xff1a; APP文件介绍&#xff1a; 4.快速上手 APP注册&#xff1a; 在app中找到apps.py&#xff1a; 在django的项目setti…

海量数据处理

1.给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址&#xff1f; 如何找到top K的IP&#xff1f; 思路&#xff1a;&#xff08;哈希切割&#xff09; 1.ip本身就是一个字符串&#xff0c;先把ip变成一个整数hash(ip) 2.文件的下标index…

用知识图谱打开梁山好汉一百单八将

说起《水浒传》大家一定不会陌生&#xff0c;《水浒传》是一部以描写古代农民起义为题材的长篇小说&#xff0c;全书描写北宋末年以宋江为首的108位好汉在梁山聚义&#xff0c;之后接受招安、四处征战的故事。它的一大看点便是其人物的描写&#xff0c;用金人瑞曾评的话说&…

算法之贪心算法

目录 前言&#xff1a; 如何理解贪心算法&#xff1f; 贪心算法的实战分析 分糖果 钱币找零 问题 总结&#xff1a; 参考资料 前言&#xff1a; 贪心算法有很多经典的应用&#xff0c;比如霍夫曼编码&#xff08;Huffman Coding&#xff09;、Prim 和 Kruskal 最小生成树…

Windows下Jenkins常见问题汇总

Jenkins运行时&#xff0c;场景遇到一些奇怪的问题&#xff0c;特别是在Powershell下能运行的命令&#xff0c;在Jenkins下运行就不行。 原因在于其特殊性&#xff1a;Jenkins执行脚本时&#xff0c;不是用当前Windows的登录账户执行的&#xff0c;所以当前登录账户的很多属性&…

数据库,计算机网络、操作系统刷题笔记16

数据库&#xff0c;计算机网络、操作系统刷题笔记16 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle…

【码极客精讲】二维数组

二维数组本质上是以数组作为数组元素的数组&#xff0c;即“数组的数组”&#xff0c;类型说明符 数组名[常量表达式][常量表达式]。二维数组又称为矩阵&#xff0c;行列数相等的矩阵称为方阵。对称矩阵a[i][j] a[j][i]&#xff0c;对角矩阵&#xff1a;n阶方阵主对角线外都是…

Go语言web极速入门-(Gin+Mysql实现后端接口)

文章目录Gin框架github地址 ⬅️点击此处安装Gin及安装框架超时问题解决参考地址 ⬅️点击此处Mysql操作建表增加测试数据代码实现需要导的包数据库连接函数及常量、数据传输结构体业务代码:获取一条信息(GET请求)业务代码:获取多条信息(GET请求)业务代码:保存一条信息(POST请求…

指令重排现象,多线程情况下,你的代码执行顺序可能不是顺序执行,结果会不一致

一、思考多线程情况下&#xff0c;程序执行顺序是否是按顺序执行 首先定义x 0; y 0; a 0; b 0;然后思考a 1;x b;两行代码谁先执行问题&#xff1f; 二、实战测试 2.1 测试逻辑 首先默认为x 0; y 0; a 0; b 0;然后开启两个线程&#xff1b;线程1执行&#xff1a;a…

java 瑞吉外卖day6 移动端 套餐 菜品展示 购物车加减,清空,用户下单

导入用户地址簿相关功能代码 菜品展示 购物车模块 加入购物车&#xff1a; PostMapping("/add") public R add(RequestBody ShoppingCart shoppingCart){//获取当前线程用户的id并设置到shoppingCart中Long currentId BaseContext.getCurrentId();shoppingCart.set…

使用3种不同的算法从倾斜风速计中检索3个风分量(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

如何确保电子招标的透明度、公正性和及时性?

采购的主要目标是确保以竞争的方式及时获得货物、工程和服务&#xff0c;确保资金的最佳价值&#xff0c;同时保持透明度和公正性。特别是在公共或非盈利组织中&#xff0c;他们利用捐助者的资金来完成任务&#xff0c;必须强调透明度、公平性和及时性。因此&#xff0c;更需要…

图像分类:Pytorch图像分类之--AlexNet模型

文章目录前言数据的处理数据集的下载数据集的划分AlexNet介绍程序的实现model.pyDropout()函数train.py数据预处理导入数据集前言 搭建AlexNet来进行分类模型的训练&#xff0c;大致训练流程和图像分类&#xff1a;Pytorch图像分类之–LetNet模型差不多&#xff0c;两者最大的…

NewStarCTF公开赛week4密码学题目wp

目录前言一、LCG Revenge1.原题2.解题思路1) 考察知识2) 分析本质3.解题Python脚本二、代数关系1.原题2.解题思路3.解题Python脚本前言 哎呦喂&#xff0c;第三周勉强做了一道题&#xff0c;果然第四周就爆零了QAQ ———————————悲伤的分割线——————————— …