转载

Java的最佳JSON解析器-FasterXML/jackson

Java(或JVM平台)的标准JSON库,或者被称为“ Java的最佳JSON解析器”。

Jackson提供了一套用于Java(和JVM平台)的数据处理工具,包括旗舰级流JSON解析器/生成器库,匹配的数据绑定库(与JSON之间的POJO)和附加的数据格式模块。以Avro, BSON, CBOR, CSV, Smile, (Java)Properties, Protobuf, XML 或YAML编码的处理数据 ; 甚至还有大量的数据格式模块,以支持广泛使用的数据类型的数据类型,例如 Guava, Joda, PCollections 等等。

实际的核心组件位于他们自己的项目下-包括两个核心软件包: jackson-core、 jackson-databind。

jackson-core项目包含Jackson数据处理器使用的抽象核心流式解析器和生成器,还包括处理JSON格式的解析器、生成器的默认实现。jackson-databind包含用于Jackson数据处理器的通用数据绑定功能和树模型。它基于StreamingAPI(流解析器、生成器)包构建,并使用Jackson注释进行配置。

1 Streaming API 核心流式API

流式API是一套比较底层的API,速度快,但是使用起来特别麻烦。它主要是有两个核心类,一个是JsonGenerator,用来生成json,另一个是JsonParser,用来读取json内容。

使用通常从创建可重用(并且在配置后是线程安全的)JsonFactory实例开始:

JsonFactory factory =  new JsonFactory();
// 配置(如有必要): 
factory.enable(JsonParser.Feature.ALLOW_COMMENTS);
// 另外,您也可以方便地ObjectMapper(从Jackson-Databind软件包中获得)。如果是这样,您可以执行以下操作:
JsonFactory factory = objectMapper.getFactory();
复制代码

官方使用示例: Reading and Writing Event Streams

JsonFactory f = mapper.getFactory();
// 也可以直接构造 JsonFactory factory = new JsonFactory();

// 首先写入
File jsonFile = new File("test.json");
JsonGenerator g = f.createGenerator(jsonFile);
// 写入 JSON: { "message" : "Hello world!" }
g.writeStartObject();
g.writeStringField("message", "Hello world!");
g.writeEndObject();
g.close();

// 然后读取
JsonParser p = f.createParser(jsonFile);

JsonToken t = p.nextToken(); 
t = p.nextToken(); 
if ((t != JsonToken.FIELD_NAME) || !"message".equals(p.getCurrentName())) {
   // handle error
}
t = p.nextToken();
if (t != JsonToken.VALUE_STRING) {
   // similarly
}
String msg = p.getText();
System.out.printf("My message to you is: %s!/n", msg);
p.close();
复制代码

2 Data Binding 数据绑定

jackson-databind软件包依赖于jackson-core和jackson-annotations软件包,但是当使用Maven或Gradle之类的构建工具时,依赖项会自动包括在内。基本使用:

//创建一个com.fasterxml.jackson.databind.ObjectMapper用于所有数据绑定的实例,ObjectMapper是线程安全的,应该尽量的重用。
ObjectMapper mapper = new ObjectMapper();
//  字符串反序列化为对象
Grade grade = mapper.readValue(jsonStr, Grade.class);
//  Jackson是基于JavaBean来序列化属性的,属性要有GETTER方法,才会输出该属性
Map<String, ResultValue> results = mapper.readValue(jsonSource, new TypeReference<Map<String, ResultValue>>() { } );

// 对象序列号化为json字符串
String gradeStr = mapper.writeValueAsString(grade);
// 对象序列号化为byte数组
byte[] jsonBytes = mapper.writeValueAsBytes(grade);
// 写入文件
mapper.writeValue(new File("result.json"), grade);
复制代码

3 Tree Model 树模型

在调用了某个api后,需要解析返回的json数据获取信息,这种情况下为json创建一个对应的类是很不方便的。此时使用Tree Model来解析json就比较方便了

JsonNode root = mapper.readTree(rerenjson);
JsonNode user = root.get("user");
root.with("other").put("type", "student");
int id = user.get("id").asInt();
String name = user.get("name").asText();
JsonNode avators = user.get("avatar");
if (avators.isArray()) {
    for (Iterator it = avators.getElements(); it.hasNext(); ){
        JsonNode avator = it.next();
        if ("tiny".equals(avator.get("type").asText())) {
            String ava = avator.get("url").asText();
            break;
        }
    }
}
复制代码

4 类型转换

Jackson的一项有用(但不是很广为人知)的功能是它能够进行任意的POJO到POJO转换。一般做法,首先将POJO编写为JSON,其次将JSON绑定到另一种POJO中。Jackson实现跳过JSON的实际生成,并使用更高效的中间实现。

// 基本使用
ResultType result = mapper.convertValue(sourceObject, ResultType.class);

// List<Integer> 转 int[]
List<Integer> sourceList = ...;
int[] ints = mapper.convertValue(sourceList, int[].class);
// POJO 转 Map!
Map<String,Object> propertyMap = mapper.convertValue(pojoValue, Map.class);
// POJO 转 back
PojoType pojo = mapper.convertValue(propertyMap, PojoType.class);
// 解码Base64!(缺省字节[]表示是base64编码字串)
String base64 = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz";
byte[] binary = mapper.convertValue(base64, byte[].class);
复制代码

5 常用注解与配置

1、常用注解:

@JsonIgnore 此注解用于属性上,作用是进行JSON操作时忽略该属性。

@JsonFormat 此注解用于属性上,作用是把Date类型直接转化为想要的格式,如@JsonFormat(pattern = “yyyy-MM-dd HH-mm-ss”)。

@JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name,@JsonProperty(“name”)。也可以直接在类上添加注解 @JsonIgnoreProperties({ "a", "b" }),跳过a、b属性。

@JsonCreator构造函数可以是公共的,也可以是私有的。Jackson不需要定义“默认构造函数”(不带参数的构造函数)。

2、Mapper的一些实用配置:(其他配置可见上述jackson-databind官方链接)

// (空对象是否抛出异常)
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// (日期改为时间戳)
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// (特殊字符和打印符,这在FastJson曾是个bug)
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// (单引号)
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
复制代码

6 SpringBoot中使用Jackson

SpringMVC内置json解析器就是Jackson,以SpringBoot技术栈开发的话,用默认的Jackson是最好的。

spring:
    jackson:
      # 设置属性命名策略,对应jackson下PropertyNamingStrategy中的常量值,SNAKE_CASE-返回的json驼峰式转下划线,json body下划线传到后端自动转驼峰式
      property-naming-strategy: SNAKE_CASE
      # 全局设置@JsonFormat的格式pattern
      date-format: yyyy-MM-dd HH:mm:ss
      # 当地时区
      locale: zh
      # 设置全局时区
      time-zone: GMT+8
      # 常用,全局设置pojo或被@JsonInclude注解的属性的序列化方式
      default-property-inclusion: NON_NULL #不为空的属性才会序列化,具体属性可看JsonInclude.Include
      # 常规默认,枚举类SerializationFeature中的枚举属性为key,值为boolean设置jackson序列化特性,具体key请看SerializationFeature源码
      serialization:
        WRITE_DATES_AS_TIMESTAMPS: true # 返回的java.util.date转换成timestamp
        FAIL_ON_EMPTY_BEANS: true # 对象为空时是否报错,默认true
      # 枚举类DeserializationFeature中的枚举属性为key,值为boolean设置jackson反序列化特性,具体key请看DeserializationFeature源码
      deserialization:
        # 常用,json中含pojo不存在属性时是否失败报错,默认true
        FAIL_ON_UNKNOWN_PROPERTIES: false
      # 枚举类MapperFeature中的枚举属性为key,值为boolean设置jackson ObjectMapper特性
      # ObjectMapper在jackson中负责json的读写、json与pojo的互转、json tree的互转,具体特性请看MapperFeature,常规默认即可
      mapper:
        # 使用getter取代setter探测属性,如类中含getName()但不包含name属性与setName(),传输的vo json格式模板中依旧含name属性
        USE_GETTERS_AS_SETTERS: true #默认false
      # 枚举类JsonParser.Feature枚举类中的枚举属性为key,值为boolean设置jackson JsonParser特性
      # JsonParser在jackson中负责json内容的读取,具体特性请看JsonParser.Feature,一般无需设置默认即可
      parser:
        ALLOW_SINGLE_QUOTES: true # 是否允许出现单引号,默认false
      # 枚举类JsonGenerator.Feature枚举类中的枚举属性为key,值为boolean设置jackson JsonGenerator特性,一般无需设置默认即可
      # JsonGenerator在jackson中负责编写json内容,具体特性请看JsonGenerator.Feature
复制代码

默认配置(配置文件配置JacksonAutoConfiguration)和用户自定义Java代码配置只需要一种即可。

总结

jackson

jackson-core

jackson-databind

平时我们使用最多的就是数据绑定吧,配置好之后真让人省心,树模型和类型转换也能为我们的工作带来便利,流式API日常使用不是太方便。希望这篇文章能对你们有帮助。欢迎大家一起学习,有误之处烦请大家指正。

原文  https://juejin.im/post/5e0f3a81f265da5d314935a7
正文到此结束
Loading...