Jackson 2.x 系列【6】注解大全篇二

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

本系列Jackson 版本 2.17.0

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

文章目录

    • 注解大全
      • 2.11 @JsonValue
      • 2.12 @JsonKey
      • 2.13 @JsonAnySetter
      • 2.14 @JsonAnyGetter
      • 2.15 @JacksonInject
      • 2.16 @JsonCreator
      • 2.17 @JsonTypeInfo
      • 2.18 @JsonSubTypes
      • 2.19 @JsonTypeName
      • 2.20 @JsonTypeId

注解大全

2.11 @JsonValue

@JsonValue用于将整个对象序列化为单个值,常用于只包含单个值的简单对象或枚举类型。Jackson 会忽略对象的其他属性和字段,只序列化由 @JsonValue 注解指定的方法或属性值。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonValue {
    boolean value() default true;
}

例如当前有个性别枚举类:

public enum GenderEnum {

    MAN("man", "男"),

    WOMAN("woman", "女");

    GenderEnum(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    private String code;

    private String desc;

   // 省略getter\serter.......
}

用户对象类包含了性别枚举类属性:

    GenderEnum gender;

设置性别并进行序列化:

        user.setGender(GenderEnum.WOMAN);
        String jsonValuesStr = objectMapper.writeValueAsString(user);
        System.out.println(jsonValuesStr);

输出时可以看到枚举类被序列化为WOMAN,我们期望输出的是

{"gender":"WOMAN","userAge":25,"mobilePhone":"13899996666"}

在枚举类字段上添加@JsonValue

    @JsonValue
    private String desc;

再次执行,可以看到将整个枚举类序列化为了一个值:

{"gender":"女","userAge":25,"mobilePhone":"13899996666"}

2.12 @JsonKey

@JsonKey也是将某个对象序列化为单个值,但是仅在实例作为Map类型中的键进行序列化时有效。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonKey {
    boolean value() default true;
}

例如下方代码:

        Org org1=new Org();
        org1.setId(1765672919981232128L);
        org1.setOrgName("阿里巴巴");

        Org org2=new Org();
        org2.setId(1772078846569590784L);
        org2.setOrgName("支付宝");


        Map<Org, String> map = new HashMap<>();
        map.put(org1,"顶级机构");
        map.put(org2,"下级机构");

        String orgStr = objectMapper.writeValueAsString(map);
        System.out.println(orgStr);

序列化后输出如下:

{"Org{id=1765672919981232128, orgName='null', address='null'}":"顶级机构","Org{id=1772078846569590784, orgName='null', address='null'}":"下级机构"}

Org属性上添加@JsonKey注解,表示序列化该对象时,使用orgName值作为Map中的键:

    @JsonKey
    private String orgName;

输出如下:

{"阿里巴巴":"顶级机构","支付宝":"下级机构"}

2.13 @JsonAnySetter

@JsonAnySetter用于反序列化时,将被忽略无法反序列化的内容,统一存放在Map集合中。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonAnySetter {
    boolean enabled() default true;
}

UserInfo中添加一个Map属性,Setter方法使用@JsonAnySetter标识:

    private Map<String,Object> collect =new HashMap<>();

    @JsonAnySetter
    public void setCollect(String key,Object value) {
        this.collect.put(key,value);
    }

JSON中有一个idCard属性是UserInfo类没有的:

        String jsonAnySetterStr="{\"idCard\":\"43268825255522222\",\"userSex\":\"男\",\"id\":1767798780627279873,\"username\":\"坤坤\",\"userAge\":18,\"org\":{\"id\":1699967647585800192,\"orgName\":\"阿里巴巴\",\"address\":\"浙江杭州\"},\"roleList\":null}";
        UserInfo readUserByAnySetter = objectMapper.readValue(jsonAnySetterStr, UserInfo.class);
        System.out.println(readUserByAnySetter);

这时idCard会被存放到Map中:
在这里插入图片描述

2.14 @JsonAnyGetter

@JsonAnyGetter则用于在序列化时,将Map集合中的内容以对象属性的方式进行输出。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonAnyGetter {
    boolean enabled() default true;
}

直接将上面@JsonAnySetter反序列化的对象进行序列化时,和之前的JSON内容不一致:

{"collect":{"idCard":"43268825255522222","id":1767798780627279873},"userAge":18,"userSex":"男","mobilePhone":null}

添加@JsonAnyGetter

    @JsonAnyGetter
    public Map<String, Object> getCollect() {
        return collect;
    }

输出结果如下:

{"mobilePhone":null,"idCard":"43268825255522222","id":1767798780627279873}

2.15 @JacksonInject

@JacksonInject标识该属性值不是直接从JSON数据中读取,而是通过注入的方式,根据ObjectMapper的配置或其他机制提供。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JacksonInject {
	// 逻辑ID,根据该ID从配置或者其他环境中查询对应的值并注入
    String value() default "";

    OptBoolean useInput() default OptBoolean.DEFAULT;
    // 省略........
}

应用场景:

  • 依赖注入:在对象创建时,可能有一些值需要通过外部机制(如Spring框架的依赖注入)提供,而不是从JSON中解析,这时可以使用@JacksonInject来标记这些属性
  • 默认值:有时我们可能希望为某些属性提供默认值,而这些默认值不是从JSON数据中读取的。使用@JacksonInject可以确保在没有从JSON中找到对应值的情况下使用这些默认值。
  • 上下文相关值:当处理与特定上下文相关的数据时,可能需要将某些上下文信息注入到对象中。这些上下文信息可能不是JSON数据的一部分,而是由调用方或应用程序的其他部分提供的

添加@JacksonInject注解:

    @JacksonInject(value = "phone")
    private String phone;

使用InjectableValues注入默认值:

        // 设置默认值
        InjectableValues.Std injectableValues = new InjectableValues.Std();
        injectableValues.addValue("phone","13788889999");
        objectMapper.setInjectableValues(injectableValues);
        // 反序列化
        String jsonInjectStr="{}";
        UserInject readUserByInject = objectMapper.readValue(jsonInjectStr, UserInject.class);
        System.out.println(readUserByInject);

输出结果如下:

User{name='null', phone='13788889999'}

2.16 @JsonCreator

@JsonCreator指定反序列化时构造对象实例使用的方法。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonCreator {

    // 构建者类型
    Mode mode() default JsonCreator.Mode.DEFAULT;

    public static enum Mode {
        DEFAULT,
        DELEGATING,
        PROPERTIES,
        DISABLED;

        private Mode() {
        }
    }
}

添加无参、有参的构造方法:

    public UserInject() {
        System.out.println("无参构造");
    }

    public UserInject(String name, String phone) {
        this.name = name;
        this.phone = phone;
        System.out.println("有参构造");
    }

进行序列化:

        String jsonCreatorStr="{\"phone\":\"13566666665\",\"name\":\"张三\"}";
        UserInject readUserByCreator = objectMapper.readValue(jsonCreatorStr, UserInject.class);
        System.out.println(readUserByCreator);

输出结果中,可以看到默认使用的是无参构造和setter方法:

无参构造
setPhone
setName
User{name='张三', phone='13566666665'}

可以使用 @JsonCreator指定使用的构造函数,使用@JsonProperty指定属性映射关系:

    @JsonCreator
    public UserInject(@JsonProperty("name") String name, @JsonProperty(value = "phone") String phone)  {
        this.name = name;
        this.phone = phone;
        System.out.println("有参构造");
    }

输出结果如下:

有参构造
User{name='张三', phone='13566666665'}

2.17 @JsonTypeInfo

@JsonTypeInfo用于多态类型时指定子类类型,以便在反序列化时能够准确地重建原始对象类型。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonTypeInfo {
	// 定义如何包含类型信息
    Id use();
	// 定义类型信息应该在哪里包含
    As include() default JsonTypeInfo.As.PROPERTY;
	// 当 use 设置为 Id.AS_PROPERTY 时,这个属性定义了包含类型信息的 JSON 属性的名称
    String property() default "";
	// 当无法确定具体的子类型时,使用的默认实现类
    Class<?> defaultImpl() default JsonTypeInfo.class;
	// 定义是否传递类型标识符值的属性
    boolean visible() default false;
	// 确定在其子类型的多态反序列化过程中是否应严格要求类型ID
    OptBoolean requireTypeIdForSubtypes() default OptBoolean.DEFAULT;

例如,定义了一个抽象类Person,它有两个类型StudentTeacher,并定义一个返回对象PersonVO定义了属性为Person实例集合:

public abstract class Person {

    public String name;
	// getters and setters  
}

public class Student extends Person{
}

public class Teacher extends Person{
}

public class PersonVO {

  List<Person> personList;
  // getters and setters  
}

执行序列化和反序列化操作:

        Student student=new Student();
        student.setName("坤坤童鞋");

        Teacher teacher=new Teacher();
        teacher.setName("悠上老师");

        List<Person> personList=new ArrayList<>();
        personList.add(student);
        personList.add(teacher);

        PersonVO personVO=new PersonVO();
        personVO.setPersonList(personList);


        String jsonStrByPerson = objectMapper.writeValueAsString(personVO);
        System.out.println(jsonStrByPerson);

        PersonVO readUserByPerson = objectMapper.readValue(jsonStrByPerson, PersonVO.class);
        System.out.println(readUserByPerson);

反序列化时,直接调用抽象类Person的构造导致报错(应该调用具体的实现类的构造):

{"personList":[{"name":"坤坤童鞋"},{"name":"悠上老师"}]}
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.pearl.jacksoncore.demo.databind.anno.Person` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
 at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 16] (through reference chain: com.pearl.jacksoncore.demo.databind.anno.PersonVO["personList"]->java.util.ArrayList[0])

Person类上添加@JsonTypeInfoproperty配置表示使用@class作为类型属性名,JsonTypeInfo.Id.CLASS表示使用全限定类名作为类型值:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
public abstract class Person {}

再次执行,可以看到序列化时,包含了一个对象的Class类型属性键值对,所以在反序列时使用指定类型的构造,正确输出:

{"personList":[{"@class":"com.pearl.jacksoncore.demo.databind.anno.Student","name":"坤坤童鞋"},{"@class":"com.pearl.jacksoncore.demo.databind.anno.Teacher","name":"悠上老师"}]}
com.pearl.jacksoncore.demo.databind.anno.PersonVO@32eff876

2.18 @JsonSubTypes

@JsonSubTypes用于指定用于多态类型时,指定子类的类型标识。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonSubTypes {
    Type[] value();

    boolean failOnRepeatedNames() default false;

下方示例中,@JsonTypeInfo表示使用type作为子类类型属性名,使用自定义名称作为子类类型值,@JsonSubTypes指定Student类的名称为stuTeacher类的名称为stu

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Student.class,name = "stu"),
        @JsonSubTypes.Type(value = Teacher.class,name = "tea")
})
public abstract class Person {//......}

序列化后输出如下:

{"personList":[{"type":"stu","name":"坤坤童鞋"},{"type":"tea","name":"悠上老师"}]}

2.19 @JsonTypeName

@JsonTypeName作用在类上,用于添加当前类的类型标识符,常用于配合@JsonTypeInfo多态类型处理问题。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonTypeName {
    String value() default "";
}

Student类上添加注解:

@JsonTypeName("student111111")
public class Student extends Person{//......}

可以看到在序列化后携带了配置的类型标识:

{"personList":[{"student111111":{"name":"坤坤童鞋"}},{"teacher":{"name":"悠上老师"}}]}

2.20 @JsonTypeId

除了使用@JsonTypeName还可以使用@JsonTypeId添加类型标识,可以添加在属性、方法、参数上。

@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonTypeId {
}

示例代码:

public class Student extends Person{

    @JsonTypeId
    private String typeId;
  // getters and setters     
}

public class Student extends Person{

    @JsonTypeId
    private String typeId;
  // getters and setters     
}

```java
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({
        @JsonSubTypes.Type(value = Student.class,name = "sut11111111"),
        @JsonSubTypes.Type(value = Teacher.class,name = "tea1111111")
})

输出结果:

{"personList":[{"sut11111111":{"name":"坤坤童鞋"}},{"tea1111111":{"name":"悠上老师"}}]}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【进程控制】进程程序替换的原理以及exec函数族

文章目录 替换原理exec函数族解释函数名解释参数 替换原理 在Linux中&#xff0c;进程的程序替换&#xff08;Process Program Replacement&#xff09;是指一个正在运行的进程使用exec函数族系统调用来加载并执行另一个程序的过程。这个新程序将替换掉原先正在执行的程序&…

VR全景赋能智慧农业,打造沉浸式种植体验平台

随着人口的增长&#xff0c;传统农业也正在面临着不一样的挑战&#xff0c;加上很多人对农业的固有印象&#xff0c;很少有年轻人愿意下到农田里&#xff0c;那么该如何提高产量、降低成本以及引导年轻人深刻感受现代农业成为了急需解决的问题。 随着城市化脚步的推进&#xff…

Codeforces Round 841 (Div. 2) C. Even Subarrays

题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e6 5, inf 1e9, maxm 4e4 5; co…

Tomcat配置https

前言&#xff1a;本文内容为实操记录&#xff0c;仅供参考&#xff01; 一、证书 CA证书申请下载不赘述了。 二、上传证书 进入tomcat根目录&#xff0c;conf同级目录下创建cert文件夹&#xff0c;并将证书两个文件上传到该文件夹&#xff1b; 三、编辑conf/server.xml文件 ① …

0 决策树基础

目录 1 绪论 2 模型 3 决策树面试总结 1 绪论 决策树算法包括ID3、C4.5以及C5.0等&#xff0c;这些算法容易理解&#xff0c;适用各种数据&#xff0c;在解决各种问题时都有良好表现&#xff0c;尤其是以树模型为核心的各种集成算法&#xff0c;在各个行业和领域都有广泛的…

火车头通过关键词采集文章的原理

随着互联网信息的爆炸式增长&#xff0c;网站管理员和内容创作者需要不断更新和发布新的文章&#xff0c;以吸引更多的用户和提升网站的排名。而火车头作为一款智能文章采集工具&#xff0c;在这一过程中发挥着重要作用。本文将探讨火车头如何通过关键词采集文章&#xff0c;以…

新能源汽车驱动电机振动噪音分析

驱动电机示例图 驱动电机的噪声主要分为空气动力噪声、电磁噪声和机械噪声。其中在高速运转时空气动力噪声是主要噪声&#xff0c;中低速运转时电磁噪声为主要噪声。 1、空气动力噪声&#xff1a; 空气噪声主要由于风扇转动&#xff0c;使空气流动、撞击、摩擦而产生&#x…

109、Recent Advances in 3D Gaussian Splatting

简介 论文 对3D Gaussian Splatting的综述 质量提升 Mip-Splatting观察到&#xff0c;改变采样率&#xff0c;例如焦距&#xff0c;可以通过引入高频高斯类形伪影或强膨胀效应&#xff0c;极大地影响渲染图像的质量&#xff0c;因此Mip-Splatting将3D表示的频率限制在训练图…

win10微软拼音输入法 - bug - 在PATH变量为空的情况下,无法输入中文

文章目录 win10微软拼音输入法 - bug - 在PATH变量为空的情况下&#xff0c;无法输入中文概述笔记实验前提条件100%可以重现 - 无法使用win10拼音输入法输入中文替代的输入法软件备注END win10微软拼音输入法 - bug - 在PATH变量为空的情况下&#xff0c;无法输入中文 概述 在…

【Leetcode每日一题】模拟 - 提莫攻击(难度⭐)(42)

1. 题目解析 题目链接&#xff1a;495. 提莫攻击 2.算法原理 一、分情况讨论 要计算中毒的总时长&#xff0c;我们需要考虑时间点之间的差值&#xff0c;并根据这些差值来确定中毒的实际持续时间。 情况一&#xff1a;差值大于等于中毒时间 假设你的角色在时间点A中毒&#…

Jenkins拉取github项目相关问题

1.私有仓库问题 1.1如果你的仓库是私有的&#xff0c;21年起github就不支持账号密码的方式拉取代码了 那么就需要在github上面创建一个token (classic) 然后在Jenkins代码设置那里 然后应该就可以顺利打包了。 2.找不到pom&#xff08;多了一层文件夹&#xff09;问题 解…

关闭 I2C 时钟延展功能的使用介绍

1.问题发生的背景 某客户使用 STM32L452&#xff08;作为 I2C 设备&#xff09;开发光模块产品&#xff0c;在测试时发现&#xff0c;同一设备&#xff08;硬件及软件均未变动&#xff09;&#xff0c;当插入交换机时&#xff0c;可正常通信&#xff0c;但是当插入 FPGA 测试机…

公链角逐中突围,Solana 何以成为 Web3 世界的流量焦点?

在众多区块链公链中&#xff0c;Solana 凭借其创纪录的处理速度和极低的交易费用&#xff0c;成为了众多开发者和投资者的宠儿。就像网络上流行的那句话所说&#xff1a;“Why slow, when you can Solana?”&#xff0c;Solana 正以它的速度和强大的生态系统&#xff0c;重新定…

centos node puppeteer chrome报错问题

原因&#xff1a;缺少谷歌依赖包&#xff0c;安装以下即可 yum install atkyum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf…

GenICam-GenApi简介

EMVA 1288标准之GemICam-GenApi学习与解读 背景介绍 当前相机不仅用于传输图像&#xff0c;还打包了越来越多的功能。这就导致相机的编程接口越来越复杂。 GenICam的目标是为所有类型的相机提供一个通用的编程接口&#xff0c;无论相机使用何种接口技术&#xff0c;或者实现…

人工智能(pytorch)搭建模型25-基于pytorch搭建FPN特征金字塔网络的应用场景,模型结构介绍

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能(pytorch)搭建模型25-基于pytorch搭建FPN特征金字塔网络的应用场景&#xff0c;模型结构介绍。特征金字塔网络&#xff08;FPN&#xff09;是一种深度学习模型结构&#xff0c;主要应用于目标检测任务中&am…

如何利用webpack来优化前端性能

当涉及前端性能优化时&#xff0c;Webpack 是一款不可或缺的工具。它不仅仅是一个模块打包工具&#xff0c;还提供了各种功能和插件&#xff0c;可以帮助开发人员优化前端应用程序的性能。在这篇文章中&#xff0c;我们将深入探讨如何有效地利用 Webpack 来优化前端性能&#x…

HCIP的学习(6)

OSPF—开放式最短路径优先协议 动态路由的评判标准 1、占用资源 2、收敛速度 3、选路动态路由分类&#xff1a; IGP---内部网关协议DV型---距离矢量型---RIPLS型---链路状态型---OSPFEGP---外部网关协议OSPF---无类别的路由协议&#xff08;携带真实掩码&#xff09;组播224.0…

基于单片机HX711电子秤称重控制设计

**单片机设计介绍&#xff0c;基于单片机HX711电子秤称重控制设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机HX711的电子秤称重控制设计是一个融合了单片机技术、称重传感器技术和显示技术的综合性项目。其设计目…

基于单片机智能家居控制系统设计

**单片机设计介绍&#xff0c;基于单片机智能家居控制系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的智能家居控制系统设计旨在实现家居设备的自动化控制和智能化管理&#xff0c;提高家庭生活的便利性和舒…