有道无术,术尚可求,有术无道,止于术。
本系列Jackson 版本 2.17.0
源码地址:https://gitee.com/pearl-organization/study-jaskson-demo
文章目录
-
- 1. 前言
- 2. JsonWriteFeature
- 3. JsonReadFeature
-
- 3.1 ALLOW_JAVA_COMMENTS
- 3.2 ALLOW_YAML_COMMENTS
- 3.3 ALLOW_SINGLE_QUOTES
- 3.4 ALLOW_UNQUOTED_FIELD_NAMES
- 3.5 ALLOW_UNESCAPED_CONTROL_CHARS
- 3.6 ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER
- 3.7 ALLOW_LEADING_ZEROS_FOR_NUMBERS
- 3.8 ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS
- 3.9 ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS
- 3.10 ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS
- 3.11 ALLOW_NON_NUMERIC_NUMBERS
- 3.12 ALLOW_MISSING_VALUES
- 3.13 ALLOW_TRAILING_COMMA
1. 前言
在上上篇文档中,有了解过JsonGenerator.Feature
、JsonParser.Feature
中的很多枚举项都已经被标记过时,官方对其进行了拆分:
JsonReadFeature
、JsonWriteFeature
(专门处理Json
格式)StreamReadFeature
、StreamWriteFeature
(处理任何格式)
2. JsonWriteFeature
一组特定于JSON
格式的生成器特性,用于控制如何生成JSON
文本,并确保输出的JSON
是有效和符合规范的。
2.1 QUOTE_FIELD_NAMES
QUOTE_FIELD_NAMES(true, Feature.QUOTE_FIELD_NAMES),
QUOTE_FIELD_NAMES
配置属性名称是否使用双引号,默认开始。根据JSON
规范,字段名应该使用双引号进行引用,这个特性允许开发者选择是否遵循这一规范。
关闭示例:
UserInfo user = new UserInfo();
user.setId(1767798780627279333L);
user.setName("老三");
user.setAge(25);
JsonFactory jsonFactory = JsonFactory.builder()
.configure(JsonWriteFeature.QUOTE_FIELD_NAMES, false)// 配置特性
.build();
JsonMapper jsonMapper=new JsonMapper(jsonFactory);
String jsonStr = jsonMapper.writeValueAsString(user);
System.out.println(jsonStr);
输出结果:
{id:1767798780627279333,name:"老三",userAge:25}
2.2 QUOTE_FIELD_NAMES
WRITE_NAN_AS_STRINGS(true, Feature.QUOTE_NON_NUMERIC_NUMBERS),
如何处理JSON
中的非数值(NaN
)、正无穷大(Positive Infinity
)和负无穷大("Negative Infinity
)的浮点数和双精度数值。默认启用,非数值、正无穷大和负无穷大的浮点数或双精度数值会被作为JSON
字符串输出,以遵守JSON
规范。
该特征主要关注三种特殊的数值,同时,也会考虑对应的浮点数(Float
)值:
Double.NaN
(表示非数值)Double.POSITIVE_INFINITY
(表示正无穷大)Double.NEGATIVE_INFINITY
(表示负无穷大)
这设置一个Double.NaN
:
user.setaDouble(Double.NaN);
默认配置下,可以看到NaN
有双引号,被当做字符串输出:
{"id":1767798780627279333,"aDouble":"NaN","name":"老三","age":25,"org":null,"roleList":null}
禁用该特征:
JsonFactory jsonFactory = JsonFactory.builder()
.configure(JsonWriteFeature.WRITE_NAN_AS_STRINGS, fasle)// 配置特性
.build();
NaN
没有双引号:
{"id":1767798780627279333,"aDouble":NaN,"name":"老三","age":25,"org":null,"roleList":null}
2.3 WRITE_NUMBERS_AS_STRINGS
WRITE_NUMBERS_AS_STRINGS(false, Feature.WRITE_NUMBERS_AS_STRINGS),
WRITE_NUMBERS_AS_STRINGS
强制将所有常规的数值作为JSON
字符串输出,而不是作为JSON
数字。默认开启,Java
的数值类型(int
、long
、double
)会使用它们的基本数值表示进行序列化。一般在JavaScript
数值处理限制的情况下(long
精度丢失),启用这个特性来确保数值的准确性。
例如开启后,id
被当做字符串进行了输出:
{"id":"1767798780627279333","aDouble":"NaN","name":"老三","age":"25","org":null,"roleList":null}
2.4 ESCAPE_NON_ASCII
ESCAPE_NON_ASCII(false, Feature.ESCAPE_NON_ASCII),
ESCAPE_NON_ASCII
配置如何处理7
位ASCII
范围之外的字符(即Unicode
码点在128
及以上的字符)。
在ASCII
编码中,每个字符占用7
位,因此其范围是从0
到127
。超出这个范围的字符(即Unicode
码点从128
开始)在文本处理中通常需要特殊的编码方式,以便正确地传输和存储。
默认关闭,非ASCII
字符在输出时不会使用转义,开启时,所有7
位ASCII
范围之外的字符在输出时都需要使用特定于格式的转义序列。对于JSON
格式,这通常意味着使用反斜杠(\
)作为转义字符来表示这些特殊字符。
汉字是7
位ASCII
范围之外的字符,默认输出如下:
{"name":"Hello!!!老三"}
当启用该特征后,输出如下:
{"name":"Hello!!!\u8001\u4E09"}
2.5 WRITE_HEX_UPPER_CASE
WRITE_HEX_UPPER_CASE(true, Feature.WRITE_HEX_UPPER_CASE),
WRITE_HEX_UPPER_CASE
用于配置十六进制值在序列化时是否使用大写字母。在JSON
序列化过程中,当遇到需要转义的字节(比如不可打印的字符或控制字符)时,这些字节通常会被转换为十六进制格式,该特征默认开启,这些十六进制值会使用大写字母表示。
例如,字节值0x1F
会被转换为\u001F
而不是\u001f
。
2.6 ESCAPE_FORWARD_SLASHES
ESCAPE_FORWARD_SLASHES(false, Feature.ESCAPE_FORWARD_SLASHES);
ESCAPE_FORWARD_SLASHES
配置JsonGenerator
是否应该转义正斜杠(/
)。
例如网站是带正斜杠的,默认禁用,说明不会转义正斜杠,输出如下:
{"name":"https://www.baidu.com/","age":null,"org":null,"roleList":null}
{"name":"https:\/\/www.baidu.com\/","age":null,"org":null,"roleList":null}
3. JsonReadFeature
是一组特定于JSON
格式的解析器特性,确保正确且高效地解析JSON
文本,主要是提供了更多非标准JSON
的处理适配,适用于某些非标准的情境或旧系统中,
3.1 ALLOW_JAVA_COMMENTS
ALLOW_JAVA_COMMENTS(false, Feature.ALLOW_COMMENTS),
ALLOW_JAVA_COMMENTS
配置JSON
解析器是否允许在解析的内容中使用Java/C/C++
风格的注释(包括/*
和//
两种形式)。
默认开启,例如下方JSON
文本包含了注释:
String jsonWithComments = "{\"name\":\"John\", /* 多行注释 */ \"age\":30, // 单行注释\n\"addr\":\"长沙\"}";
User userByComments = jsonMapper.readValue(jsonWithComments, User.class);
System.out.println(userByComments);
直接解析会报错:
Exception in thread "main" com.fasterxml.jackson.core.JsonParseException: Unexpected character ('/' (code 47)): maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 17]
at com.fasterxml.jackson.core.JsonParser._constructReadException(JsonParser.java:2643)
启用后,可正常解析:
User{id=null, aByte=0, aDouble=null, name='John', age=30, addr='长沙', org=null, roleList=null}
JSON
规范并不支持注释,尽量避免在JSON
数据中使用注释。
3.2 ALLOW_YAML_COMMENTS
ALLOW_YAML_COMMENTS
用于配置JSON
解析器是否应该允许在解析的内容中使用YAML
风格的注释(即以#
开头的行)。
ALLOW_YAML_COMMENTS(false, JsonParser.Feature.ALLOW_YAML_COMMENTS),
和上面的类似,尽量避免使用。
3.3 ALLOW_SINGLE_QUOTES
ALLOW_SINGLE_QUOTES(false, JsonParser.Feature.ALLOW_SINGLE_QUOTES),
ALLOW_UNQUOTED_FIELD_NAMES
用于配置JSON
解析器是否应该允许在解析的内容中使用单引号('
)来替代双引号("
)作为字符串的界定符。
开启后输出如下:
User{id=null, aByte=0, aDouble=null, name='John', age=30, addr='长沙', org=null, roleList=null}
JSON
规范明确指定字符串应该由双引号包围,适用于某些非标准的情境或旧系统中,可能会遇到使用单引号的情况。
3.4 ALLOW_UNQUOTED_FIELD_NAMES
ALLOW_UNQUOTED_FIELD_NAMES(false, JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES),
ALLOW_UNQUOTED_FIELD_NAMES
用于配置允许JSON
解析器解析那些字段名没有用引号包围的JSON
字符串。
下方JSON
文本中,有的字段没有双引号:
String jsonWithComments = "{name:'John', age:30, city:'长沙'}";
默认关闭,直接解析会报异常:
Exception in thread "main" com.fasterxml.jackson.core.JsonParseException: Unexpected character ('i' (code 105)): was expecting double-quote to start field name
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 2]
at com.fasterxml.jackson.core.JsonParser._constructReadException(JsonParser.java:2643)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:685)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleOddName(ReaderBasedJsonParser.java:1910)
开启后,则正常解析:
User{id=1767798780627279333, aByte=0, aDouble=null, name='null', age=30, addr='null', org=null, roleList=null}
3.5 ALLOW_UNESCAPED_CONTROL_CHARS
ALLOW_UNESCAPED_CONTROL_CHARS(false, JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS),
ALLOW_UNESCAPED_CONTROL_CHARS
用于配置允许JSON
解析器解析包含未转义的控制字符的JSON
字符串。
控制字符(如换行符\n
、制表符\t
等)在标准的JSON
中通常需要转义,以确保数据的正确解析和跨平台的兼容性。然而,在某些情境下,可能会遇到包含未转义控制字符的JSON
数据。
下方JSON
文本中,包含没有转义的\n
:
String jsonWithUnescapedControlChars = "{\"name\":\"Hello, World!\nThis is a new line.\"}";
默认关闭,直接解析会报异常:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Illegal unquoted character ((CTRL-CHAR, code 10)): has to be escaped using backslash to be included in string value
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 23] (through reference chain: com.pearl.jacksoncore.demo.feature.User["name"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:402)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:361)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1937)
开启后,则正常解析:
User{id=null, aByte=0, aDouble=null, name='Hello, World!
This is a new line.', age=null, addr='null', org=null, roleList=null}
3.6 ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER
ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER(false, JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER),
在标准的JSON规范中,反斜杠\
用于转义一些特殊字符,如引号"
、反斜杠\\
、斜杠/
、退格符\b
、换行符\n
、回车符\r
和制表符\t
。ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER
用于配置允许JSON
解析器解析那些使用反斜杠\
来转义任意字符的JSON
字符串。
下方JSON
文本中,name
对应的值包含了使用\
转义的字符,这在标准的JSON
中是不允许的::
String jsonWithNonStandardEscaping = "{\"name\":\"value1 with \\escaped\\ chars\", \"addr\":\"value2\"}";
默认关闭,直接解析会报异常:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Unrecognized character escape 'e' (code 101)
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 23] (through reference chain: com.pearl.jacksoncore.demo.feature.User["name"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:402)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:361)
开启后,则正常解析:
User{id=null, aByte=0, aDouble=null, name='value1 with escaped chars', age=null, addr='value2', org=null, roleList=null}
3.7 ALLOW_LEADING_ZEROS_FOR_NUMBERS
ALLOW_LEADING_ZEROS_FOR_NUMBERS
用于配置允许JSON
解析器解析包含前导零的数字。
ALLOW_LEADING_ZEROS_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS),
下方JSON
文本中,age
对应的值包含了前导零,这在标准的JSON
中是不允许的::
String jsonWithLeadingZeros = "{\"age\": 0123, \"name\": \"张二码子\"}";
默认关闭,直接解析会报异常:
Exception in thread "main" com.fasterxml.jackson.core.JsonParseException: Invalid numeric value: Leading zeroes not allowed
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 10]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:2567)
at com.fasterxml.jackson.core.JsonParser._constructReadException(JsonParser.java:2593)
开启后,则正常解析:
User{id=null, aByte=0, aDouble=null, name='张二码子', age=123, addr='null', org=null, roleList=null}
3.8 ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS
ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS),
ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS
用于配置允许JSON
解析器解析包含前导加号+
的数字。
标准的JSON
规范中,数字不应该包含前导加号,因为加号通常用于表示正数,下方JSON
文本中,age
对应的值包含前导加号:
String jsonWithLeadingPlusSign = "{\"age\": +123, \"name\": \"空空\"}";
默认关闭,直接解析会报异常:
Exception in thread "main" com.fasterxml.jackson.core.JsonParseException: Unexpected character ('+' (code 43)) in numeric value: JSON spec does not allow numbers to have plus signs: enable `JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS` to allow
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 10]
at com.fasterxml.jackson.core.JsonParser._constructReadException(JsonParser.java:2643)
开启后,则正常解析:
User{id=null, aByte=0, aDouble=null, name='空空', age=123, addr='null', org=null, roleList=null}
3.9 ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS
ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS),
ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS
用于配置允许JSON
解析器解析包含前导小数点的数字,标准的JSON
格式中,数字不应该包含前导小数点,因为这样的表示方式通常用于表示浮点数,但前导小数点而没有整数部分是不合法的。
和上面的类似,可以自己试下:
String jsonWithLeadingPlusSign = "{\"age\": .123, \"name\": \"空空\"}";
3.10 ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS
ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS),
ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS
用于配置允许JSON
解析器解析包含尾随小数点的数字。
和上面的类似,可以自己试下:
String jsonWithLeadingPlusSign = "{\"age\": 123., \"name\": \"王大\"}";
3.11 ALLOW_NON_NUMERIC_NUMBERS
ALLOW_NON_NUMERIC_NUMBERS(false, JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS),
ALLOW_NON_NUMERIC_NUMBERS
用于配置允许解析器识别一组“非数字”(NaN
)标记作为合法的浮点数值。JSON
规范本身并不允许使用这些值,因此这是一个非标准的特性,默认是禁用的。
这个特性支持XML Schema
中定义的一组特定的NaN
值表示:
INF
:表示正无穷大,也可以使用别名Infinity
-INF
:表示负无穷大,别名可以是-Infinity
NaN
:表示非数字,比如除以零的结果
3.12 ALLOW_MISSING_VALUES
ALLOW_NON_NUMERIC_NUMBERS(false, JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS),
ALLOW_MISSING_VALUES
允许JSON
解析器在遇到缺失值(即逗号后没有跟随任何值的情况)时不会抛出异常,而是会将其视为一个有效的输入。
下方JSON
文本中,id
没有对应的值:
String jsonWithLeadingPlusSign = "{\"id\": ,\"name\": \"老八\"}";
默认关闭,直接解析会报异常:
Exception in thread "main" com.fasterxml.jackson.core.JsonParseException: Unexpected character (',' (code 44)): expected a valid value (JSON String, Number (or 'NaN'/'+INF'/'-INF'), Array, Object or token 'null', 'true' or 'false')
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 8]
at com.fasterxml.jackson.core.JsonParser._constructReadException(JsonParser.java:2643)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:685)
开启后,则正常解析:
User{id=null, aByte=0, aDouble=null, name='老八', age=null, addr='null', org=null, roleList=null}
3.13 ALLOW_TRAILING_COMMA
ALLOW_TRAILING_COMMA(false, JsonParser.Feature.ALLOW_TRAILING_COMMA),
ALLOW_TRAILING_COMMA
用于配置允许JSON
解析器在处理JSON
对象或数组时忽略尾随的逗号。
和上面的类似,可以自己试下:
String jsonWithLeadingPlusSign = "{\"id\": ,\"name\": \"老八\",}";