原文 JSON Binding API (JSR 367)
- 本规范定义java对象和JSON转换的API,JSON具体详情可以参考附录[1], 假定认为读者对于JSON非常熟悉,更多关于json参考如下:
- 架构风格与基于网络的软件架构设计 参考附录[2]
- REST Wiki 参考附录[3]
- JSON Wiki 参考附录[4]
1、简介
1.1 状态
- 可以在以下位置找到未解决问题的列表:
- https://github.com/javaee/jsonb-spec/issues
- 与之对应的源码地址:
- https://github.com/javaee/jsonb-spec
- 参考实现可从以下位置获取:
- https://projects.eclipse.org/projects/rt.yasson
- 专家组正在寻求社区对本规范任何方面的反馈。请加入我们的讨论组:
- https://javaee.groups.io/g/jsonb-spec
1.2、目标
- API的目标:
- JSON:支持所有兼容RFC 7159的JSON文档绑定(序列化和反序列化)
- 与JSON相关规范的关系:将调查与JSON相关的规范,以确定它们与JSON-Binding的关系。
- 一致性:在适当的情况下,保持与JAXB(用于XML绑定的Java API)以及其他Java EE和SE API的一致性。
- 约定:定义Java类和实例到JSON文档副本的默认映射。
- 自定义:允许自定义默认映射定义。
- 易于使用:API的默认用法不要求了解JSON文档格式和规范
- 部分映射: 在许多用例中,仅需要将JSON文档的子集映射到Java对象实例。
- 整合:定义或启用与JSR374的集成:JSON处理的Java API (JSON-P)1.1.
1.3、非目标
- 以下是非目标的内容
- 保存等同(往返)
- 该规范建议但是不要求反序列化和序列化的JSON文档的内容相等
- JSON模式
- 从Java类生成JSON模式,以及基于JSON模式的验证
- JEP 198 轻量级 JSON API
- JEP 198中定义的与Lightweight JSON API 的支持和集成不在本规范的范围之内,将在以后的规范修订版中重新考虑。
- 保存等同(往返)
1.4、约定
-
关键字“MUST”(必须), “MUST NOT”(禁止), “REQUIRED”(要求),“SHALL”(最好), “SHALL NOT”(最好不), “SHOULD”(应该), “SHOULD NOT”(不应该), “RECOMMENDED”(推荐), “MAY”(可能)和“OPTION”(可选) 具体含义已经在RFC2119说明了,详情参看附录[5]
-
java 代码格式示例如下
-
package com.example.hello; public class Hello{ public static void main(String[] args[]){ System.out.println("Hello World"); } }
-
-
URI 表示示例: ‘http://example.org/…’ 或 ‘http://example.com/…’
-
本规范的所有部分均为规范性内容,但示例,注释和部分明确标记为“非规范性”, 非规范性注释的格式如下所示:
- 注释:这是注释
1.5、术语
- Data binding(数据绑定) : 将JSON文档中的信息表示形式定义为对象实例的过程,反之亦然
- Deserialization(反序列): 读取JSON文档并构造对象树的过程,其中每个对象对应于JSON文档的一部分,因此内容反映了文档的内容。
- Serialization(序列化):反序列化的逆过程,遍历内容对象树并编写可反映树的内容的JSON文档的过程。
1.6、专家组成员
- 该规范是Java社区流程下JSR 367的一部分,这是JSR367专家组成成员共同努力的结果。以下是目前的专家组成员:
- Dmitry Kornilov (Oracle)
- Roman Grigoriadi (Oracle)
- Lukas Jungmann (Oracle)
- Martin Vojtek (Datlowe)
- Hendrik Saly (Individual Member)
- Gregor Zurowski (Individual Member)
- Inderjeet Singh (Individual Member)
- Eugen Cepoi (Individual Member)
- Przemyslaw Bielicki (Individual Member)
- Kyung Koo Yoon (TmaxSoft, Inc.)
- Otavio Santana (Individual Member)
- Nathan Rauh (IBM)
- Alexander Salvanos (Individual Member)
- Romain Manni-Bucau (Tomitribe)
1.7、致谢
- 在此JSR的过程中,我们收到了许多很好的建议。特别感谢Heather VanCura, David Delabassee 和 Reza Rahman的反馈和对规范传播的帮助,以及John Clingan的反馈和语法更正。
- 在本次JSR期间,我们还收到了许多的出色的建议。特别感谢 Mark Struberg, Olena Syrota, Oleg Tsal-Tsalko 和整个JUG UA的贡献。
2、运行时API
- JSON-B运行时API提供对序列化和反序列化操作的访问权,以处理JSON文档以及映射的JSON-B类和实例,绑定框架的完整规范可在javadoc中获得,该规范随附有javax.json.bind包
3、默认映射
本部分定义Java组件和类与JSON文档的默认绑定(表示)。可以按照“自定义映射“中的指定进一步自定义此处定义的默认绑定
3.1、常规
- JSON绑定实现(下文中的实现)必须支持RFC7159JSON语法[1]中定义的JSON文档的绑定。序列化的JSON输出务必符合RFC7159JSON语法[1],并按照RFC7159[1]第8.1(字符编码)中定义的UTF-8编码进行编码,实现必须支持对符合RFC7159JSON语法[1]的文档进行反序列化,另外,实施方式不应允许对RFC7159[1]不符合要求的文本进行反序列化(例如,不支持的编码等),并在这种情况下报告错误。对反序列化文档的UTF编码的检测必须遵循RFC4627[6]的第3节(编码)中定义的编码的过程。实现应忽略UTF字节顺序标记(BOM)存在,并且不应将其视为错误。
3.2、异常
- 实施不应该对RFC7159[1]不符合要求的文本进行反序列化(例如,不支持的编码等),并在这种情况下报告错误,如果无法用期望的Java类型标识JSON文档的值,则实现还应该在反序列化操作期间报告错我。
3.3、基本java类型
- 实现必须支持以下基本Java类及其对应的基本数据类型的绑定:
- java.lang.String
- java.lang.Character
- java.lang.Byte
- java.lang.Short
- java.lang.Integer
- java.lang.Long
- java.lang.Float
- java.lang.Double
- java.lang.Boolean
3.3.1、java.lang.String, Character
- 类型为java.lang.String 和java.lang.Character的实例被序列化为JSON字符串值,如RFC7159第7节(字符串)[1]中定义的那样,采用UTF-8编码,没有自己顺序标记。
- [JSB-3.3.1-1]实现应该支持JSON文本反序列化(除了UTF-8)将UTF编码转换为java.lang.String实例
3.3.2、java.lang.Byte, Short, Integer, Long, Float, Double
- 将类型java.lang.Byte, Short, Integer, Long, Float或Double(及其对应的原始类型)序列化为JSON的Number必须遵循javadoc规范中为相应的类型的toString()方法【JSB-3.3.2-1】。将JSON值反序列化为java.lang.Byte,Short,Integer,Long, Float或Double实例(或对应的原始类型)必须遵循javadoc规范中为相应的parse$Type方法定义的转换过程,例如java.lang.Byte.parseByte()表示字节。
3.3.3、java.lang.Boolean
- 将类型java.lang.Boolean及其对应的布尔原始类型序列化为JSON值,必须遵循javadoc规范中为java.lang.Boolean.toString() 方法定义的转换过程,将JSON值反序列化为java.lang.Boolean实例或布尔基础数据类型必须遵循javadoc规范中为java.lang.Boolean.parseBoolean()方法定义的转换过程。
3.3.4、java.lang.Number
- 将java.lang.Number实例(如果在未在本章其他地方定义更具体的类型)序列化为JSON字符串,则必须从java.lang.Number.doubleValue()方法检索双精度值并将其转换为定义的JSON Number在3.3.2节中,将JSON值反序列化为java.lang.Number类型必须通过使用javadoc规范中为java.math.BigDecimal的构造函数使用java.lang.String参数定义的转换过程来返回java.math.BigDecimal的实例。
3.4、特定的标准Java SE 类型
- 实现必须支持绑定以下标准java SE 类:
- java.math.BigInteger
- java.math.BigDecimal
- java.net.URL
- java.net.URI
- java.util.Optional
- java.util.OptionInt
- java.util.OptionLong
- java.util.OptionDouble
3.4.1、java.math.BigInteger, BigDecimal
- 将类型java.math.BigInteger或BigDecimal序列化为JSON的数字,必须遵循javadoc规范中为相应类型的toString()方法定义的转换过程,将JSON值反序列化为java.math.BigInteger或BigDecimal实例必须遵循javadoc规范中为java.math.BigInteger或BigDecimal的构造函数(带有java.lang.String参数)定义的转换过程。
3.4.2、java.net.URL, URI
- 将类型java.net.URL或URI序列化为JSON字符串,必须遵循javadoc规范中为相应类型的toString()方法定义的转换过程,将JSON值反序列化为java.net.URL或URI实例必须遵循javadoc规范中为java.net.URL或URI的构造函数(带有java.lang.String参数)定义的转换过程。
3.4.3、java.util.Optional, OptionalInt, OptionalLong, OptionalDouble
- 通过检索其包含的实例并将其实例类型转换为JSON值,并在本章中将其转换为JSON值,将类型为java.util.Optional, OptionalInt, OptionalLong, OptionDouble的非空实例序列化JSON值,包含空的可选实例的类字段被视为具有空值,并根据3.14.1进行序列化。
- 数组项中的空可选实例被序列化为null。
- 反序列化为Optional, OptionalInt, OptionalLong, OptionalDouble对于包含空值的属性返回空的可选值。否则,将根据本章中定义的映射反序列化任何非空的Optional, OptionalInt, OptionalLong, OptionalDouble值。
- 单独将T序列化为JSON对象时,将类型java.util.Optional实例序列化为JSON值作为JSON对象,如果将T序列化为JSON值(例如(java.lang.String, java.lang.Integer)则将java.util.Optional的实例序列化JSON值(不带大括号)。
- 如果支持将JSON值反序列化为T实例,则必须支持将JSON值反序列化为java.util.Optional.
3.5、日期
- 实现必须支持绑定接下来标准的java的日期和时间的类:
- java.util.Date
- java.util.Calendar
- java.util.GregorianCalendar
- java.util.TimeZone
- java.util.SimpleTimeZone
- java.time.Instant
- java.time.Duration
- java.time.Period
- java.time.LocalTime
- java.time.LocalDate
- java.time.LocalDateTime
- java.time.ZonedDateTime
- java.time.ZoneId
- java.time.ZoneOffset
- java.time.OffsetDateTime
- java.time.OffsetTime
- 如果本节中未另行指定,则使用GMT标准时区和UTC 的Greenwich指定的偏移量,如果没有另外指定,则用于序列化和反序列化的日期格式为ISO 8601,不带偏移 如:java.time.format.DateTimeFormatter.ISO_DATE中所指定。
- 如果JSON文档中的日期/时间字符串与预期的日期/时间格式不符,则实现必须报告错误。
- 如果处于严格的I-JSON遵从模式,则默认日期格式将按照4.4.1中的描述进行更改。
3.5.1、java.util.Date, Calendar, GregorianCalendar
- 如果没有时间信息的java.util.Date, Calendar,GregorianCalendar实例的序列化格式为ISO_DATE. 如果存在时间信息,则格式为ISO_DATE_TIME,实现必须支持将ISO_DATE和ISO_DATE_TIME反序列化为java.util.Date, Calendar和GregorianCalendar实例。
3.5.2、java.util.TimeZone, SimpleTimeZone
- 实现必须支持将java.util.TimeZone中指定的任何时区格式反序列化为类型为java.util.TimeZone和SimpleTimeZone的字段或属性。
- 实现必须报告java.util.Timezone中指定的已经弃用的三个字母的时区ID的错误。
- 如java.util.TimeZone中指定,java.util.TimeZone和SimpleTimeZone的序列化格式为NormalizedCustomID.
3.5.3、java.time.*
-
java.time.Instant实例的序列化输出必须采用ISO_INSTANT格式,如java.time.format.DateTimeFormatter中指定。实现必须支持将ISO_INSTANT格式的JSON字符串反序列化为java.time.Instant实例。
-
对于其他java.time.*类,接下来映射表展示java类型到它对应的格式
-
Java 类型 格式 java.time.Instant ISO_INSTANT java.time.LocalDate ISO_LOCAL_DATE java.time.LocalTime ISO_LOCAL_TIME java.time.LocalDateTime ISO_LOCAL_DATE_TIME java.time.ZonedDateTime ISO_ZONED_DATE_TIME java.time.OffsetDateTime ISO_OFFSET_DATE_TIME java.time.OffsetTIme ISO_OFFSET_TIME 实现必须支持将java.time.ZoneId中指定的任何时区ID格式反序列化为类型java.time.ZoneId的字段或属性。java.timeZoneId的序列化格式是在java.time.ZoneId中指定的标准化区域ID。
-
实现必须支持将java.time.ZoneOffset中指定的任何时区ID格式反序列化为java.timeZoneOffset类型的字段或属性。java.time.ZoneOffset的序列化格式在java.time.ZoneOffset中指定的标准化区域ID。
-
实现必须支持将java.time.Duration中指定的任何持续时间格式反序列化为类型java.time.Duration的字段或属性。这是ISO8601持续时间格式的超集。java.time.Duration的序列化格式是基于ISO 8601秒的表示形式,例如PT8H6M12.345S
-
实现必须支持将java.time.Period中指定的任何周期格式反序列化为类型java.time.Period的字段或属性。这是ISO 8601期间格式的超集。java.time.Period的序列化格式为ISO8601周期表示。零长度期间表示为零天"P0D"。
3.6、无类型映射
-
对于反序列化操作的未指定输出类型,以及输出类型为如果指定为Object.class, 则实现必须在下表中指定: 使用Java反序列化JSON文档
-
JSON值 Java 类型 object java.util.Map<String,Object> array java.util.List string java.lang.String number java.math.BigDecimal true, false java.lang.Boolean null null JSON对象值以可预测的迭代顺序反序列化为java.util.Map<String, Object>实现。
3.7、 java类
- 传递给反序列化操作的任何实例都必须具有public或protected的无参数构造函数。如果不满足此条件,实现应该抛出一个错误。此限制不适用与序列化操作,也不适用于指定显式实例化方法的类,如第4.5节中所述。
3.7.1、作用域和字段获取策略
- 对于Java属性的反序列化操作,如果存在匹配的public的setter方法,则将调用该方法以及设置属性的值。如果存在具有private,protected或默认(仅为包访问)的匹配setter方法,则将忽略此字段,如果不存在匹配的设置方法,并且该字段是public字段,则使用直接字段分配。
- 对于序列化操作,如果存在匹配的public的getter方法,则将调用该方法以获取属性的值。如果存在具有private,protected,默认(仅为包访问)的匹配getter方法,则将忽略此字段。如果不存在匹配的getter方法并且该字段是public字段,则直接从该字段获取值。
- JSON绑定实现不得将其反序列化为transient,final或static修饰字段,并且必须忽略与此类字段相对应的名称/值对。
- 实现必须支持final修饰的字段的序列化,在序列化操作期间必须忽略transient和static字段
- 如果JSON文档包含于字段或设置方法不对应的键值对,则将跳过该键值对。
- 必须支持没有相应字段的public的getter/setter方法,当类中仅存在没有对应字段的public的getter/setter方法时,将调用getter方法以获取要序列化的值,并在反序列化操作期间调用setter方法。
3.7.2、内部类
- 实现必须支持public和protected修饰的内部类的绑定,对于反序列化的操作,内部类和封装类都必须满足3.7.1中指定的相同实例化要求。
3.7.3、静态内部类
- 实现必须支持public和protected的静态内部类的绑定,对于反序列化操作,内部类必须满足3.7.1中指定的实例化要求。
3.7.4、匿名类
- 不支持反序列化匿名类。支持匿名类的序列化映射成默认的对象。
3.8、多态类型
- 默认映射不支持将反序列化为多态类型。
3.9、枚举类
- 将Enum实例序列化为JSON字符串值时,必须遵循javadoc规范中为其name()定义的转换过程。
- 必须通过调用枚举的valueOf(String)方法将JSON值反序列为枚举实例。
3.10、接口
- 实现必须支持对3.11和3.3.4中定义的特定接口进行反序列化。
- 不支持反序列化到其他接口,在这种情况下,实现应报告错误。
- 如果类属性是使用接口而不是具有类型定义的,则将根据序列化属性的运行时类型来解析器映射。
3.11、集合
- 实现必须支持以下集合接口,类以其实现的绑定:
- java.util.Collection
- java.util.Map
- java.util.Set
- java.util.HashSet
- java.util.NavigableSet
- java.util.SortedSet
- java.util.TreeSet
- java.util.LinkedHashSet
- java.util.HashMap
- java.util.NavigableMap
- java.util.SortedMap
- java.util.TreeMap
- java.util.LinkedHashMap
- java.util.List
- java.util.ArrayList
- java.util.LinkedList
- java.util.Deque
- java.util.ArrayDeque
- java.util.Queue
- java.util.PriorityQueue
- 这些接口的实现必须提供可访问的默认构造函数。如果默认构造函数不存在或不在可访问范围内,则JSON绑定实现必须报告反序列化错误。
3.12、数组
- JSON绑定实现必须支持本章中所有受支持的Java类型的Java数组到RFC7159[1]第5节中定义的JSON数组结构中的绑定。
- 必须支持基本类型的数组和多维数组。
3.13、属性的顺序
- 类属性必须按字典顺序序列化为结果JSON文档。在继承的情况下,在父类中声明的属性必须在子类中声明的属性之前序列化。
- 反序列化JSON文档时,必须按照JSON文档中存在的属性的顺序设置字段值。
3.14、空值处理
3.14.1、Null Java字段
- 用空值序列化java字段,JSON文档中缺少该属性。
- JSON文档中不存在属性的反序列化操作务必不要设置字段的值,必须不要调用setter(如果可用),因此必须保留字段的原始值。
- JSON文档中具有空值的属性的反序列化操作必须将字段的值设置为空值(或如果存在setter,则使用空值调用setter)。以下情况除外:java.util.Optional, OptionalInt, OptionalLong, OptionalDouble 实例。在这种情况下,该字段的值设置为空的可选值。
3.14.2、Null 数组的值
- JSON文档中表示的反序列化n元数组的结果是n元Java的数组。JSON数组中的空值由Java数组中的空值表示。在索引i为空值的Java数组上的序列化操作必须在结果JSON文档中在数组的索引i处输出空值。
3.15、名称和标识符
- 根据RFC 7159第7节[1],可以使用标识符函数将每个Java标识符名称转换为有效的JSON字符串,标识函数必须用于将Java标识符名称转换为JSON文档中的字符串。
- 对于3.6节中定义的反序列化操作,标识函数用于将JSON名称字符串转换为结果映射Map<String, Object>中的Java String 实例。可以在定制中进一步定制命名策略。
3.16、大数字
- JSON绑定实现必须序列化、反序列化数字,这些数字表示的幅度或精度比作为字符串的IEEE 754双精度数字更大
3.17、泛型
- JSON绑定必须支持泛型
- 由于类型擦除,在某些情况下无法获得泛型信息,JSON绑定实现有两种获取泛型信息的方法
- 如果有可用的类文件(在下文中称为静态类型信息),则可以从Signature属性(如果存在此信息)获取泛型信息(有效地是泛型声明)
- 第二个选项是在运行时提供泛型信息,为了在运行时提供泛型信息,必须将java.lang.reflect.Type的参数传递给Jsonb::toJson或Jsonb::fromJson方法。
3.17.1、类型解析的算法
-
JSON绑定实现可以获取有关字段/类/接口类型的多种信息:
- 通过传递给Jsonb::toJson 或Jsonb::fromJson方法的java.lang.reflect.Type参数提供的运行时类型
- 在类文件的静态类型(存储在签名属性当中)
- 原生类型
- 没有有关类型的信息。
-
如果没有关于类型的信息,则JSON绑定实现必须将此类型视为java.lang.Object.
-
如果只有给定字段/类/接口的原始类型是已知的,则必须将该类型视为原始类型。例如,如果唯一可用的信息是给定的字段/接口的类型为java.util.ArrayList, 则必须将类型视为java.util.ArrayList。
-
JSON绑定实现必须使用从可用信息中派生的最具体的类型。
-
让我们考虑一个这样的情况:只有已知的给定字段/类/接口的静态类型信息,而没有运行时类型信息。
-
假设GenericClass<T 1 _{1} 1…T n _{n} n>的一部分信息,T 1 _{1} 1…T n _{n} n是GenericClass的声明的参数,对于每个T i _{i} i(i=1…n) ,这里3个可能选项:
- T i _{i} i 是一个具体的类型
- T i _{i} i 是一个有边界的类型
- T i _{i} i 是一个通配符且没有边界的类型
-
对于第1种情况: 最具体的参数类型必须是给定具体参数类型T i _{i} i
-
对于边界参数类型,让我们来使用边界参数B 1 _{1} 1…, B m _{m} m
-
如果m=1,那么具体参数类型必须从给定边界B 1 _{1} 1中衍生出来。
-
如果B 1 _{1} 1是一个类或接口, 那么具体参数类型必须是类或接口。
-
除此之外,其他具体参数类型应该是java.lang.Object.
-
如果存在多个边界参数类型,第一步就是要分别解决边界问题,让我们来定义解决S 1 _{1} 1,…,S m _{m} m的具体参数类型
-
如果S 1 _{1} 1,…,S m _{m} m都是java.lang.Object, 那么边界参数类型T i _{i} i必须为java.lang.Object.
-
如果具体类型为S k _{k} k , 当1<=k<=m 是不同于java.lang.Object,那么对于边界参数的最具体参数类型T i _{i} i必须是S k _{k} k
-
如果存在具体类型为S k 1 _{k1} k1, S k 2 _{k2} k2, 当1<=k1<=k2<=m, 那么最具体的参数类型是S k 1 _{k1} k1
-
对于没有边界通配符的参数类型,这个具体参数类型必须是java.lang.Object.
-
任何其他未解析参数类型必须被作为java.lang.Object对待
-
如果通过java.lang.reflect.Type提供的参数类型传递给Jsonb::toJson或Jsonb::fromJson方法,那么运行时参数类型将适当地情况下重写静态声明的参数类型
-
在某些情况下,有必要结合使用运行时和静态类型信息。
-
public class MyGenericType<T,U>{ public T field1; public U field2; }
-
若要解析field1的类型,需要MyGenericType的运行时类型和field1的静态类型。
3.18、必要忽略策略
- 当反序列化期间的JSON绑定实现遇到无法识别的键/值对中的键时,应将JSON文档的其余部分视为元素根本没有出现,尤其是,实现不得将其视为错误
3.19、属性的唯一性
- JSON绑定实现不得产生成员名称重复的JSON文档。在此上下文中,”重复“表示处理任何转义字符后的名称是相同的Unicode字符序列。
- 当发现非唯一性属性(在重写和重命名之后)时,实现必须抛出异常。这不适用与使用JsonAdapter和JsonbSerializer/JsonbDeserializer机制实现的自定义用户序列化行为。
3.20、json处理和整合
- JSON绑定实现必须支持以下JSON处理类型的绑定:
- javax.json.JsonObject
- javax.json.JsonArray
- javax.json.JsonStructure
- javax.json.JsonValue
- javax.json.JsonString
- javax.json.JsonNumber
- 支持的javax.json.*对象/接口/字段的序列化必须与使用javax.json.JsonWriter序列化这些对象的结果相同。
- 反序列化为受支持的javax.json.*对象/接口/字段的结果必须与使用javax.json.JsonReader反序列化为此类对象的结果相同。
4、自定义映射
该小节定义几种自定义默认行为的方法,这些默认行为可以通过注解一个给定的字段,JavaBean属性,类型或包名或提供实现具体策略(例如 PropertyOrderStrategy)等方法实现, JSON 绑定提供者必须支持这些自定义的选项。
4.1、自定义属性名称
- 这里有两种如何自定义JSON文档中的序列化字段(或JavaBean 属性)的方法,这种方式同样应用于反序列,第一种方法使用javax.json.bind.annotation.JsonbProperty注解去标记字段或JavaBean的属性。第二种方法设置javax.json.bind.config.PropertyNamingStrategy.
4.1.1、javax.json.bind.annotation.JsonbTransient
- JSON绑定实现一定不能处理 带有javax.json.bind.annotation.JsonbTransient标识的字段或javabean 属性或类型
- JsonbTransient注解与所有其他JSON绑定定义的注解是互斥,在以下情况下,实现必须抛出JsonbException:
- 类字段被标记为@JsonbTransient
- 如果该字段或getter或setter方法被标记其他JSON绑定注解将需要抛出异常。
- Getter方法被标记为@JsonbTransient
- 如果使用其他JSON绑定注解对字段或此getter方法进行注解,则会引发异常,如果在setter上显示JSON 绑定的注解,则不会引发异常。
- Setter方法被标记为@JsonbTransient
- 如果使用其他JSON绑定注解对字段或此setter方法进行注解,则会引发异常,如果在getter上显示JSON绑定的注解,则不会引发异常。
- 类字段被标记为@JsonbTransient
4.1.2、javax.json.bind.annotation.JsonbProperty
- 根据默认映射3.15,属性名称被原样化为JSON文档(标识转换),为了提供给定字段(或JavaBean属性)的自定义名称,可以使用javax.json.bind.annotation.JsonbProperty.可以在字段,getter或setter方法上指定JsonProperty注解。如果在字段上指定,则自定义名称将同时用于序列化和反序列化。
- 如果javax.json.bind.annotation.JsonbProperty用于getter方法,那么它只用于序列化,如果javax.json.bind.annotation.JsonbProperty用于setter方法,那么它只用于反序列化
4.1.3、javax.json.bind.config.PropertyNamingStrategy
- 为自定义转换的属性名称,JSON绑定提供了javax.json.bind.config.PropertyNamingStrategy 接口。接口javax.json.bind.config.PropertyNamingStrategy提供了最常见的命名策略
- IDENTITY
- LOWER_CASE_WITH_DASHES (带破折号的小写字母)
- LOWER_CASE_WITH_UNDERSCORES ( 带下划线的小写字母)
- UPPER_CAMEL_CASE (驼峰命名法)
- UPPER_CAMEL_CASE_WITH_SPACES (带空格的驼峰命名法)
- CASE_INSENSITIVE ( 大小不敏感)
- 这个命名策略详细描述可以参见javadoc
- 这个方法设置自定义命名策略可以使用javax.json.bind.JsonbConfig::withPropertyNamingStrategy方法。
4.1.4、属性名称解析
- 属性名称的解析有两部分组成
- 标准的重写机制
- 应用属性名称解析,其中涉及@JsonbProperty的值
- 如果发现重复的名称,则必须抛出异常,重复的定义(非唯一)属性可在3.19中找到
4.2、自定义属性顺序
- 为自定义序列化属性的顺序,JSON 绑定提供javax.json.bind.config.PropertyOrderStrategy类
- javax.json.bind.config.PropertyOrderStrategy提供最常用属性顺序的策略
- LEXICOGRAPHICAL (字典顺序)
- ANY (任意)
- REVERSE (逆序)
- 属性顺序策略的详细描述可以在javadoc中找到
- 设置自定义属性顺序策略的方法是使用javax.json.bind.JsonbConfig::withPropertyOrderStrategy方法。为了仅针对一种特定类型自定义序列化属性的顺序,JSON 绑定提供了javax.json.bind.annotation.JsonbPropertyOrder注解。由JsonbPropertyOrder注解指定的顺序将覆盖由PropertyOrderStrategy指定的顺序。
- 该顺序将应用于4.1中所述的已重命名的属性。
4.3、自定义空值处理
- 有三种方法可以更改默认的空处理,第一种选择是使用javax.json.bind.annotation.JsonbNillable注解对类型或包进行注解。第二个选项是使用javax.json.bind.annotation.JsonbProperty注解字段或JavaBean属性,并将nillable参数设置为true。第三个选项是通过JsonbConfig::withNullValues方法设置整个配置范围的配置。
- 如果不同级别的注解(JsonbNillable或JsonbProperty)应用于同一个字段(或JavaBean属性),或者存在配置范围内的配置,并且某些注解(JsonbNillable或JsonbProperty)应用于同一个字段(或JavaBean属性),则带有适用最小范围。例如,如果将类型级别的JsonbNillable注解应用于带有字段的某个类,且该字段使用带有nillable=false的JsonbProperty注解进行注解,则JsonbProperty注解将覆盖JsonbNillable注解。
4.3.1、javax.json.bind.annotation.JsonbNillable
- 为了自定义序列化字段或JavaBean属性时值为null时,JSON 绑定提供javax.json.bind.annotation.JsonbNillable and javax.json.bind.annotation.JsonbProperty注解
- 当给定对象(类型或包)使用javax.json.bind.annotation.JsonbNillable注解进行标记时,空值的结果将是JSON文档中存在具有显式空值的关联属性。
- javax.json.bind.annotation.JsonbProperty注解及其nillable参数提供与JsonbNillable相同的行为,但仅在字段,参数和方法(JavaBean属性)级别提供。
- JSON绑定实现必须根据注释目标(FIELD,PARAMETER,METHOD,TYPE,PACKAGE)实现对注解的覆盖,TYPE注解会覆盖PACKAGE级别设置的行为。FIELD,PARAMETER,METHOD会覆盖TYPE设置的行为。
4.3.2、全局null处理配置
- null值处理行为可以通过自定义javax.json.bind.JsonbConfig::withNullValues方法。
- 这种方法在序列化null值的时候,它会调用javax.json.bind.JsonbConfig::withNullValues参数为true。
- 跳过空值序列化的方法是调用方法参数为false的javax.json.bind.JsonbConfig::withNullValues.
4.4、I-JSON 支持
- I-JSON(Internet JSON的缩写)是JSON的受限制的配置文件,旨在最大程度第提高互操作性并增强对软件可以成功地以可预期的结果进行处理的信心,该配置文件在附录[7]中定义
- JSON绑定完全支持I-JSON标准。无需任何配置,JSON 绑定会生成I-JSON兼容的JSON文档,但有三个例外:
- JSON绑定不限制既不是对象也不是数组的顶级JSON文本的序列化,该限制应发生在应用程序级别。
- JSON绑定不会使用base64url编码序列化二进制数据
- JSON绑定不对日期/时间/时间间隔施加其他限制。
- 这些例外仅涉及I-JSON的推荐区域。
- 为了严格遵守序列化JSON文档,JSON绑定实现必须实现配置选项"jsonb.strict-ijson"。
- 严格遵循序列化JSON文档的方法是使用参数true调用方法JsonbConfig::withStrictIJSON.
- 严格的I-JSON合规性仅更改默认映射行为(请参见第3节)
4.4.1、限制日期序列化
- 必须使用大写字母而不是小写字母。
- 即使时区的值为”00“, 也必须始终包括时区,并且必须包括可选的尾随秒。
- JSON绑定实现必须以与java.time.ZonedDateTime相同的格式序列化java.util.Date, java.util.Calendar, java.util.GregorianCalendar, java.time.LocalDate, java.timeLocalDateTime和java.time.Instant.
- 持续时间序列化的结果必须符合RFC3339附录A中的”持续时间“, 并具有相同的附加限制。
4.5、自定义实例
- 在许多情况下,使用默认构造函数进行实例化是不够的,为了支持这些场景,JSON 绑定提供了javax.json.bind.annotation.JsonbCreator注解。
- 最多可以使用一个JsonbCreator注解对类中的自定义构造函数或静态工厂方法进行注解,否则必须抛出JsonbException.
- 带有JsonbCreator注解的工厂方法应返回此注解用于特定类的实例,否则必须抛出JsonbException。在所有参数上使用JsonbProperty注解定义使用JsonbCreator注解的构造函数/工厂方法的参数与JSON字段之间的映射。
- 如果不使用参数上的JsonbProperty注解,则应从具有相同名称的JSON字段映射参数。在这种情况下,不能保证正确的映射。
- 如果JSON文档中不存在参数映射所需的字段,则必须抛出JsonbException
4.6、自定义可见性
- 要自定义第3.7.1节中指定的作用域和字段访问策略,可以指定javax.json.bind.annotation.JsonbVisibility注解,或使用给定的自定义属性可见性策略全局调用JsonbConfig::withPropertyVisibilityStrategy方法来覆盖默认行为。
4.7、自定义映射
- 某些Java类型不能自然地映射到JSON文本,并且不能使用注解来自定义映射。一个示例可以是某些第三方类或没有no-arg构造函数的类,在这种情况下,要自定义映射,JSON绑定具有两种机制:适配器和序列化器
4.7.1、适配器
- Adapter是一个实现javax.json.bind.Adapter.JsonbAdapter接口的类,它具有一个自定义代码,可将“不可映射”类型(原始)转换为JSONB可以处理的另一种类型(自适应)。在对原始类型进行序列化时,JSONB调用适配器的JsonbAdapter::adaptToJson方法以将Original转换为Adapted并序列化Adapted标准方式。
- 在反序列化时,JSONB使用JsonbAdapter::adaptFromJson方法反序列化Adapted来自JSON并将其转换为Original。
- 这里有两种方法去处理注册JsonbAdapter:
- 使用JsonbConfig::withAdapters方法。
- 使用JsonbTypeAdapter注解去标记一个类
- 通过JsonbConfig::withAdapters注册的JsonbAdapter对于使用给定JsonbConfig执行的所有序列化/反序化操作都是可见的,通过注解的注册的JsonbAdapter对仅用于带注解字段的序列化/反序列化操作可见。
- 实现必须在适配器中提供CDI支持,以允许将CDI管理的bean注入其中
4.7.2、序列化/反序列化
- 有时适配机制还不够,因此需要对JSONP解析器/生成器的低级别访问。
- 序列化器的类需要实现javax.json.bind.serializers.JsonbSerializer接口,它用于注册到原始类型进行序列化,在序列化JSONB的原始类型时将会调用JsonbSerializer::serialize方法,这个方法包含JsonpGenerator类提供自定义序列化原始类型的代码
- 反序列化器的类需要实现javax.json.bind.serializers.JsonbDeserializer接口,它用于注册到原始类型进行反序列化,在序列化JSONB的原始类型时将会调用JsonbDeserializer::deserialize方法,这个方法包含JsonpGenerator类提供自定义反序列化原始类型的代码
- 这里有种方法去注册JsonbSerializer/JsonbDeserializer
- 使用JsonbConfig::withSerializers/ JsonbConfig::withDeserializers方法。
- 使用JsonbSerializer/JsonbDeserializer注解type
- 实现必须在适配器中提供CDI支持,以允许将CDI管理的bean注入其中
4.8、自定义日期格式
- 要指定自定义日期格式,必须使用javax.json.bind.annotation.JsonbDateFormat注解对给定的注解目标进行注解,JsonbDateFormat注解可以应用于以下目标:
- field 字段
- getter/setter
- type 类型
- parameter 参数
- package 包
- 可以使用javax.json.bind.JsonbConfig::withDateFormat和javax.json.bind.JsonbConfig::withLocale方法在全局范围内自定义默认日期格式和默认语言环境。
- 如果是javax.json.bind.annotation, JsonbDateFormat是在getter方法上指定的,仅用于序列化,如果是javax.json.bind.annotation.JsonbDateFormat是在setter方法上指定的,仅用于反序列化。
- 应用于更具体目标的注解会覆盖应用于具有广泛范围和全局配置的目标相同注解,例如,应用于类型目标的注解将覆盖应用于包目标的相同的注解。
4.9、自定义数字格式
- 要指定自定义数字格式,必须使用javax.json.bind.annotation.JsonbNumberFormat注解对给定的注解目标进行标记,JsonbNumberFormat注解可以应用于以下目标:
- field 字段
- getter/setter
- type 类型
- parameter 参数
- package 包
- 如果javax.json.bind.annotation.JsonbNumberFormat被设置到getter方法,那么它仅用于序列化,如果javax.json.bind.annotation.JsonbNumberFormat设置到setter方法,那么它仅用于反序列化。
- 应用于更具体目标的注解会覆盖应用于具有广泛范围和全局配置的目标相同注解,例如,应用于类型目标的注解将覆盖应用于包目标的相同的注解。
4.10、自定义二进制数据处理
- 为自定义编码二进制数据,JSON绑定提供javax.json.bind.config.BinaryDataStrategy类。
- javax.json.bind.config.BinaryDataStrategy提供通用的二进制编码策略
- BYTE 字节
- BASE_64
- BASE_64_URL
- 具体策略的描述可以参考java文档
- 设置自定义二进制数据处理策略可以使用javax.json.bind.JsonbConfig::withBinaryDataStrategy方法。
附录
- [1] E. T. Bray, “The JavaScript Object Notation (JSON) Data Interchange Format,” March 2014. [Online]. Available: https://tools.ietf.org/html/rfc7159.
- [2] R. Fielding, “Architectural Styles and the Design of Network-based Software Architectures,” 2000.
- [3] “REST Wiki,” [Online]. Available: http://rest.blueoxen.net/cgi-bin/wiki.pl.
- [4] “JSON,” [Online]. Available: http://en.wikipedia.org/wiki/JSON.
- [5] S. Bradner, “Key words for use in RFCs to Indicate Requirement Levels,” March 1997. [Online]. Available: https://www.ietf.org/rfc/rfc2119.txt.
- [6] D. Crockford, “The application/json Media Type for JavaScript Object Notation (JSON),” July 2006. [Online]. Available: https://tools.ietf.org/html/rfc4627.
- [7] E. T. Bray, “The I-JSON Message Format,” March 2015. [Online]. Available: https://tools.ietf.org/html/rfc7493.
- [8] K. Kawaguchi, “The Java Architecture for XML Binding (JAXB),” 2009.
- [9] K.-M. Chung, “Java API for JSON Processing,” 2015.