杰克逊顶部

使用Spring 5和Spring Boot 2开始,通过学习的春天课程:

>>看看这个课程

1.概述

本文涵盖了前一篇文章中没有涉及的一些附加注释,杰克逊注释指南-我们会讲七个。

2。@JsonIdentityReference.

@JsonIdentityReference.用于定制对对象的引用,这些对象将被序列化为对象标识,而不是完整的pojo。它与@JsonIdentityInfo强制在每个序列化中使用对象身份,不同于第一次@JsonIdentityReference.缺席。当处理物体之间的循环依赖性时,这对辅助最有用。请参阅第4节杰克逊 - 双向关系文章以获取更多信息。

为了证明使用@JsonIdentityReference.,我们将定义两个不同的bean类,不使用这个注释和使用这个注释。

bean没有@JsonIdentityReference.

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") public class beanwithtidentityreference {private int id;私人字符串名称;//构造函数,getters和setter}

对于使用@JsonIdentityReference.,我们选择ID属性是对象标识:

@jsonidentityinfo(generator = objectidgenerators.propertygenerator.class,property =“id”)@jsonidentityReference(almanceAsid = True)公共类BeanWithIdentityReference {Private Int ID;私人字符串名称;//构造函数,getters和setter}

在第一种情况下,在哪里@JsonIdentityReference.不存在,该bean是在其属性的完整详细信息中序列化:

beanwithtidentityreference bean = new beanwithtidentityreference(1,“没有身份引用注释的bean”);字符串jsonstring = mapper.writevalueastring(bean);

序列化的输出:

{"id": 1, "name": "没有标识引用注释的Bean "}

@JsonIdentityReference.使用,bean序列化为简单的身份,而是

BeanWithIdentificerReference Bean = New BeanWithIdentityReference(1,“bean,具有身份参考注释”);字符串jsonstring = mapper.writevalueastring(bean);assertequals(“1”,jsonstring);

3.@JsonAppend

@JsonAppend注释用于在对象序列化时向对象添加虚拟属性以及常规属性。当我们想直接向JSON字符串中添加补充信息,而不是更改类定义时,这是必要的。例如,插入版本与相应的JSON文档的Bean元数据比提供额外的属性。

假设我们有一个没有@JsonAppend如下:

公共类beanwithoutappend {private int id;私人字符串名称;//构造函数,getters和setter}

测试将确认在没有的情况下@JsonAppend注释时,序列化输出不包含关于补充的信息版本财产,尽管我们试图添加到objectWriter.对象:

BeanWithoutAppend bean = new BeanWithoutAppend(2,“bean没有附加注释”);ObjectWriter writer = mapper.writerFor(BeanWithoutAppend.class)。withAttribute(“版本”,“1.0”);字符串jsonstring = writer.writevalueastring(bean);

序列化输出:

{"id": 2, "name": "没有附加注释的Bean "}

现在,让我们说我们有一个豆子注释@JsonAppend

@JsonAppend(attrs = {@JsonAppend;public class BeanWithAppend{私有int id;私人字符串名称;//构造函数,getters和setter}

与前一个类似的测试将验证当@JsonAppend应用注释,序列化后包含补充属性:

beanwithappend bean = new beanwithappend(2,“bean,附加annotation”);ObjectWriter Writer = Mapper.Writerfor(beanwithappend.class).withattribute(“版本”,“1.0”);字符串jsonstring = writer.writevalueastring(bean);

该序列化的输出显示版本已添加财产:

{“ID”:2,“名称”:“bean ampend注释”,“版本”:“1.0”}

4。@jsonnaming.

@jsonnaming.注释用于为序列化中的属性选择命名策略,覆盖默认值。使用价值元素,我们可以指定任何策略,包括自定义。

除了默认情况下,这是dight_camel_case.(例如。LowerCamelcase.), Jackson库为我们提供了另外四种方便的内置属性命名策略:

  • kebab_case.:例如,名称元素用连字符分隔。凯巴巴案
  • 下箱:所有字母都是小写,没有分隔符。小写
  • SNAKE_CASE:所有的字母都是小写,下划线作为名称元素之间的分隔符。Snake_case.
  • UPPER_CAMEL_CASE:所有名称元素,包括第一个元素,从大写字母开始,然后是小写字母,并且没有分隔符,例如,UpperCamelCase

此示例将说明使用蛇盒名称序列化属性的方法,其中名为豆章是序列化的bean_name。

给出bean定义:

@jsonnaming(propertynamingstrategy.snakecasstreatred.class)公共类命名{私有int id;私人字符串beanName;//构造函数,getters和setter}

下面的测试演示了指定的命名规则根据需要工作:

命名方豆=新的命名(3,“命名豆”);字符串jsonstring = mapper.writevalueastring(bean);assertthat(jsonstring,containstring(“bean_name”));

jsonString变量包含以下数据:

{“ID”:3,“bean_name”:“命名bean”}

5。@JsonPropertyDescription

jackson库能够在调用的单独模块的帮助下为Java类型创建JSON模式JSON Schema.。当我们想在序列化Java对象时指定预期输出或在反序列化之前验证JSON文档时,模式非常有用。

@JsonPropertyDescription注释允许将人类可读的描述添加到创建的JSON模式中,方法是提供描述场地。

本节利用下面声明的豆类来展示能力@JsonPropertyDescription

公共类PropertyDescriptionBean {Private Int ID;@jsonpropertydescription(“这是名称属性的描述”)私有字符串名称;// getters和setter}

添加JSON架构的添加方法描述字段如下所示:

schemafactorywrapper wrapper = new schemafactorywrapper();mapper.acceptjsonformatvisitor(propertyDescriptionBean.class,包装器);JSonschema JSonschema = Wrapper.Finalschema();字符串jsonstring = mapper.writevalueastring(Jsonschema);assertthat(jsonstring,containstring(“这是名称属性的描述));

正如我们所看到的,JSON Schema的生成成功:

{"type": "object", "id": "urn:jsonschema:com:b金宝搏188体育aeldung:jackson:annotation:extra:PropertyDescriptionBean", "properties": {"name": {"type": "string", "description": "这是名称属性的描述"},"id": {"type": "integer"}}}

6。@jsonpojobuilder.

@jsonpojobuilder.注释用于配置一个构建器类,以自定义JSON文档的反序列化,以便在命名约定与默认不同时恢复pojo。

假设我们需要反序列化以下JSON字符串:

{"id": 5, "name": "POJO Builder Bean"}

json源将用于创建一个实例PojobuilderBean.

@JsonDeserialize(builder = BeanBuilder.class) public class POJOBuilderBean {private int identity;私人字符串beanName;//构造函数,getters和setter}

Bean属性的名称与JSON字符串中的字段的名称不同。这是哪里@jsonpojobuilder.来拯救我。

@jsonpojobuilder.注释有两个属性:

  • buildmethodname.:No-arg方法的名称用于在将JSON字段绑定到该bean的属性之后实例化预期的bean。默认名称是构建
  • 用前缀:用于自动检测JSON和bean属性之间的匹配的名称前缀。默认前缀是

这个例子利用了豆核菜下面的类,用于使用它PojobuilderBean.

@jsonpojobuilder(buildmethodname =“createbean”,withprefix =“construct”)公共类beanbuilder {private int idvalue;私有字符串名称值;公共beanbuilder构造(int id){idvalue = id;返回这个;公共beanbuilder buildgraphame(字符串名称){namevalue = name;返回这个;public pojobuilderbean createBean(){return new pojobuilderbean(didvalue,namevalue);}}

在上面的代码中,我们已配置了@jsonpojobuilder.使用调用的构建方法createBean构造匹配属性的前缀。

应用@jsonpojobuilder.对一个bean的描述和测试如下:

字符串jsonString = "{\ \“id”:5,\“\”:\”比恩POJO Builder \“}”;POJOBuilderBean = mapper。readValue (jsonString POJOBuilderBean.class);assertequal (5, bean.getIdentity ());assertEquals("POJO Builder Bean", Bean . getbeanname ());

结果显示,尽管属性名不匹配,但已经从JSON源成功地重新创建了一个新的数据对象。

7。@JsonTypeId

@JsonTypeId注释用于指示在包含多态类型信息时,注释属性应作为类型id序列化,而不是作为常规属性序列化。在反序列化期间使用多态元数据来重新创建与序列化前相同的子类型的对象,而不是声明的超类型的对象。

关于Jackson处理继承的更多信息,请参见继承在杰克逊

假设我们有一个bean类定义如下:

public class TypeIdBean{私有int id;@JsonTypeId私有字符串名称;//构造函数,getters和setter}

下面的测试验证了这一点@JsonTypeId就像它的意思一样:

Mapper.enableDefaultty(defaulttyping.non_final);TypeIdBean Bean = New TypeidBean(6,“类型ID Bean”);字符串jsonstring = mapper.writevalueastring(bean);assertthat(jsonstring,containstring(“类型ID Bean”));

序列化过程'输出:

[“类型ID Bean”,{“ID”:6}]

8。@JsonTypeIdResolver

@JsonTypeIdResolver注释用于在序列化和反序列化中表示自定义类型标识处理程序。该处理程序负责在JSON文档中包含的Java类型和类型ID之间的转换。

假设我们希望在处理以下类层次结构时嵌入JSON字符串中的类型信息。

AbstractBean超类:

@JsonTypeInfo(使用= JsonTypeInfo.Id。NAME, include = JsonTypeInfo.As。@JsonTypeIdResolver(BeanIdResolver.class) public class AbstractBean{私有int id;protected AbstractBean(int id) {this。id = id;} //没有参数的构造函数,getter和setter}

FirstBean子类:

public class FirstBean extends AbstractBean {String firstName;public FirstBean(int id, String name) {super(id);setFirstName(名称);} //没有参数的构造函数,getter和setter}

LastBean子类:

public class LastBean extends AbstractBean {String lastName;public LastBean(int id, String name) {super(id);setLastName(名称);} //没有参数的构造函数,getter和setter}

这些类的实例用于填充a豆牢器对象:

public class BeanContainer {private List bean;// getter和setter}

我们可以看到AbstractBean班级被注释@JsonTypeIdResolver,表示它使用了自定义TypeidResolver.决定如何在序列化中包括子类型信息,以及如何反过来利用该元数据。

以下是处理包含类型信息的解析器类:

公共类BeanIdResolver扩展TypeidResolverBase {Private Javatype SuperType;@override public void init(javatype baseType){supertype = baseType;@override public id getMechanism(){return id.name;@Override公共字符串idfromValue(Object Obj){return idfromvalueandtype(obj,obj.getclass());@Override公共字符串idfromValueAndtype(对象obj,class <?>子类型){string typeid = null;switch(subtype.getsimpleName()){case“firstbean”:typeid =“bean1”;休息;案例“姓氏”:typeid =“bean2”;返回TypeId;@override公共javatype typefromid(databindcontext上下文,字符串ID){class <?>子类型= null; switch (id) { case "bean1": subType = FirstBean.class; break; case "bean2": subType = LastBean.class; } return context.constructSpecializedType(superType, subType); } }

最值得注意的两种方法是idFromValueAndTypetypefromid.如前所述,前者讲述了在序列化POJOS时包含类型信息的方法,并且后者使用该元数据确定重新创建对象的子类型。

为了确保序列化和反序列化良好工作,让我们编写一个测试来验证完整的进度。

首先,我们需要实例化bean容器和bean类,然后使用bean实例填充该容器:

FirstBean Bean1 =新的FirstBean(1,“Bean 1”);斋戒豆=新的姓氏(2,“bean 2”);列表 Beans = new arraylist <>();beans.add(bean1);beans.add(bean2);BeanContainer SerializedContainer = New BeanContainer();setializedContainer.setBeans(豆类);

接下来,这是豆牢器对象是序列化的,我们确认生成的字符串包含类型信息:

字符串jsonstring = mapper.writevalueastring(序列化Container);asserthat(jsonstring,containstring(“bean1”));assertthat(jsonstring,containstring(“bean2”));

序列化的输出如下所示:

{“beans”:[{“@type”:“bean1”,“id”:1,“firstname”:“bean 1”},{@type“:”bean2“,”id“:2,”lastname“:”bean 2“}]}

JSON结构将用于重新创建与序列化之前相同子类型的对象。以下是Deserialization的实现步骤:

BeanContainer DeserializedContainer = Mapper.ReadValue(JSONString,BeanContainer.class);列表 BeanList = DeserializedContainer.getBeans();assertthat(beanlist.get(0),instanceof(firstbean.class));asserthat(beanlist.get(1),instanceof(lastbean.class));

9.结论

本教程详细解释了几种不太常见的Jackson注释。中可以找到这些示例和代码片段的实现一个GitHub的项目

杰克逊底部

使用Spring 5和Spring Boot 2开始,通过学习的春天课程:

>>看看这个课程
评论在本文上关闭!