jackson java用法_Jackson 使用方法总结

1. 工具简介

Jackson项目GitHub主页

Baeldung上关于JSON的使用

涉及到一些不常见的用法或功能,可以到以上两个地址查看,网上相关博客类的资料相对较少。

Jackson核心模块是所有扩展的基础。目前有3个核心模块(从Jackson 2.x开始):

Streaming:(jackson-core)定义了低级流API,包括JSON特性的实现。

Annotations:(jackson-annotations)包含标准的Jackson注解。

Databind:(jackson-databind)实现了数据绑定(和对象序列化)支持,它依赖于Streaming和Annotations包。

com.fasterxml.jackson.core

jackson-core

${jackson.version.core}

com.fasterxml.jackson.core

jackson-annotations

${jackson-annotations-version}

com.fasterxml.jackson.core

jackson-databind

${jackson.version}

SpringBoot中使用的话引入web依赖,就直接引入了Jackson:

org.springframework.boot

spring-boot-starter-web

依赖如下:

204f5fbd3363

2. 简单使用

Jackson提供了三种JSON的处理方式。分别是数据绑定,JSON树模型,流式API。下面分别介绍这三种方式。

2.1. 数据绑定

import lombok.Data;

@Data

public class Student {

private Long id;

private String name;

private Integer age;

private String sex;

private String[] interest;

}

public class Test {

public static void main(String[] args) throws IOException {

Student student = new Student();

student.setId(1L);

student.setName("zhangsan");

student.setAge(20);

student.setInterest(new String[]{"music", "coding"});

ObjectMapper mapper = new ObjectMapper();

//测试代码......

}

}

2.1.1. JavaBean转JSON字符串

String studentStr = mapper.writeValueAsString(student);

System.out.println(studentStr);

//{"id":1,"name":"zhangsan","age":20,"sex":null,"interest":["music","coding"]}

2.1.2. JSON字符串转JavaBean

Student stu = mapper.readValue(studentStr, Student.class);

System.out.println(stu);

//Student(id=1, name=zhangsan, age=20, sex=null, interest=[music, coding])

2.1.3. JSON字符串转Map集合

//对泛型的反序列化,使用TypeReference可以明确的指定反序列化的类型。

//import com.fasterxml.jackson.core.type.TypeReference;

Map map = mapper.readValue(studentStr, new TypeReference>(){});

System.out.println(map);

//{id=1, name=zhangsan, age=20, sex=null, interest=[music, coding]}

2.1.4. JavaBean转文件

//写到文件

mapper.writeValue(new File("/json.txt"), student);

//从文件中读取

Student student1 = mapper.readValue(new File("/json.txt"), Student.class);

System.out.println(student1);

//Student(id=1, name=zhangsan, age=20, sex=null, interest=[music, coding])

2.1.5. JavaBean转字节流

//写为字节流

byte[] bytes = mapper.writeValueAsBytes(student);

//从字节流读取

Student student2 = mapper.readValue(bytes, Student.class);

System.out.println(student2);

//Student(id=1, name=zhangsan, age=20, sex=null, interest=[music, coding])

2.2. JSON树模型

Jackson树模型结构,可以通过path,get,JsonPointer等进行操作,适合用来获取大JSON中的字段,比较灵活。缺点是如果需要获取的内容较多,会显得比较繁琐。

2.2.1. 构建JSON树模型

import com.fasterxml.jackson.core.JsonPointer;

import com.fasterxml.jackson.databind.JsonNode;

import com.fasterxml.jackson.databind.ObjectMapper;

import com.fasterxml.jackson.databind.node.ArrayNode;

import com.fasterxml.jackson.databind.node.NullNode;

import com.fasterxml.jackson.databind.node.ObjectNode;

import java.io.IOException;

public class Test {

public static void main(String[] args) throws IOException {

//构建JSON树

ObjectMapper mapper = new ObjectMapper();

ObjectNode root = mapper.createObjectNode();

root.put("id", 1L);

root.put("name", "zhangsan");

root.put("age", 20);

ArrayNode interest = root.putArray("interest");

interest.add("music");

interest.add("coding");

//测试代码......

}

}

2.2.2. JSON树转JSON字符串

String json = mapper.writeValueAsString(root);

System.out.println(json);

//{"id":1,"name":"zhangsan","age":20,"interest":["music","coding"]}

2.2.3. 解析JSON树模型

//将JSON字符串转为JSON树

JsonNode rootNode = mapper.readTree(json);

//解析值,使用path或者get

Long id = rootNode.path("id").asLong();

System.out.println(id);//1

String name = rootNode.path("name").asText();

System.out.println(name);//zhangsan

Integer age = rootNode.get("age").asInt();

System.out.println(age);//20

//解析数组

JsonNode arrayNode = rootNode.get("interest");

if (arrayNode.isArray()){

for (JsonNode jsonNode : arrayNode){

System.out.println(jsonNode.asText());

//music

//coding

}

}

path和get方法看起来很相似,其实它们的细节不同。

path方法会返回一个"missing node",该"missing node"的isMissingNode方法返回值为true,如果调用该node的asText方法的话,结果是一个空字符串。

System.out.println(rootNode.path("notExist").isMissingNode());//true

System.out.println(rootNode.path("notExist").asText());//空串

get方法取不存在的值的时候,直接会返回null。

System.out.println(rootNode.get("notExist") == null);//true

System.out.println(rootNode.get("notExist"));//null

当key存在,而value为null的时候,get和path都会返回一个NullNode节点。该节点的asText方法返回null字符串。

String s = "{\"nullNode\":null}";

JsonNode jsonNode = mapper.readTree(s);

System.out.println(jsonNode.get("nullNode") instanceof NullNode);//true

System.out.println(jsonNode.get("nullNode"));//null

System.out.println(jsonNode.path("nullNode") instanceof NullNode);//true

System.out.println(jsonNode.path("nullNode"));//null

使用JsonPointer解析JSON树。

String s1 = "{\"obj\": {\"name\": \"wang\",\"class\": \"3\"}}";

JsonNode jsonNode1 = mapper.readTree(s1);

JsonPointer jsonPointer = JsonPointer.valueOf("/obj/name");

JsonNode node = jsonNode1.at(jsonPointer);

System.out.println(node.asText());//wang

2.3. 流式API

参考地址:JackSon的几种用法

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

import com.fasterxml.jackson.core.*;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

public class Test {

public static void main(String[] args) throws IOException {

JsonFactory factory = new JsonFactory();

String s = "{\"id\": 1,\"name\": \"小明\",\"array\": [\"1\", \"2\"]," +

"\"test\":\"I'm test\",\"nullNode\":null,\"base\": {\"major\": \"物联网\",\"class\": \"3\"}}";

//这里就举一个比较简单的例子,Generator的用法就是一个一个write即可。

File file = new File("/json.txt");

JsonGenerator jsonGenerator = factory.createGenerator(file, JsonEncoding.UTF8);

//对象开始

jsonGenerator.writeStartObject();

//写入一个键值对

jsonGenerator.writeStringField("name", "小光");

//对象结束

jsonGenerator.writeEndObject();

//关闭jsonGenerator

jsonGenerator.close();

//读取刚刚写入的json

FileInputStream inputStream = new FileInputStream(file);

int i = 0;

final int SIZE = 1024;

byte[] buf = new byte[SIZE];

StringBuilder sb = new StringBuilder();

while ((i = inputStream.read(buf)) != -1) {

System.out.println(new String(buf,0,i));

}

inputStream.close();

//JsonParser解析的时候,思路是把json字符串根据边界符分割为若干个JsonToken,这个JsonToken是一个枚举类型。

//下面这个小例子,可以看出JsonToken是如何划分类型的。

JsonParser parser = factory.createParser(s);

while (!parser.isClosed()){

JsonToken token = parser.currentToken();

System.out.println(token);

parser.nextToken();

}

JsonParser jsonParser = factory.createParser(s);

//下面是一个解析的实例

while (!jsonParser.isClosed()) {

JsonToken token = jsonParser.nextToken();

if (JsonToken.FIELD_NAME.equals(token)) {

String currentName = jsonParser.currentName();

token = jsonParser.nextToken();

if ("id".equals(currentName)) {

System.out.println("id:" + jsonParser.getValueAsInt());

} else if ("name".equals(currentName)) {

System.out.println("name:" + jsonParser.getValueAsString());

} else if ("array".equals(currentName)) {

token = jsonParser.nextToken();

while (!JsonToken.END_ARRAY.equals(token)) {

System.out.println("array:" + jsonParser.getValueAsString());

token = jsonParser.nextToken();

}

}

}

}

}

}

3. 注解使用

3.1. @JsonProperty

使用在JavaBean的字段上,指定一个字段用于JSON映射,默认情况下映射的JSON字段与注解的字段名称相同。该注解有三个属性:

(1)value:用于指定映射的JSON的字段名称。常用。

(2)index:用于指定映射的JSON的字段顺序。

(3)defaultValue:定义为元数据的文本默认值。注意:core databind不使用该属性,它目前只公开给扩展模块使用。

@JsonProperty(value = “user_name”)

3.2. @JsonIgnore

可用于字段、getter/setter、构造函数参数上,作用相同,都会对相应的字段产生影响。使相应字段不参与序列化和反序列化。也就是说,向“getter”添加注释会禁用“setter”。除非setter有@JsonProperty注解,在这种情况下,这被认为是一个“分割属性”,启用了“setter”,但没有“getter”(“只读”,因此属性可以从输入读取,但不是写输出)。

3.3. @JsonIgnoreProperties

该注解是类注解。该注解在Java类和JSON不完全匹配的时候使用。

(1)在序列化为JSON的时候,@JsonIgnoreProperties({"prop1", "prop2"})会忽略pro1和pro2两个属性。

(2)在从JSON反序列化为Java类的时候,@JsonIgnoreProperties(ignoreUnknown=true)会忽略所有没有Getter和Setter的属性,也就是忽略类中不存在的字段。

3.4. @JsonIgnoreType

该注解是类注解,序列化为JSON的时候会排除所有指定类型的字段。

3.5. @JsonInclude

用于定义在序列化时是否不应包含某些“非值”(null值或空值)的注解。可以用于每个字段上,也可以用于类上(表示用于类的所有属性)。

//忽略类中值为null的字段

@JsonInclude(value = JsonInclude.Include.NON_NULL)

//忽略类中值为空的字段。对于字符串,即忽略null或空字符串

@JsonInclude(Include.NON_EMPTY)

3.6. @JsonFormat

用于字段上,预期类型行为的通用注释;例如,可以用来指定序列化日期/时间值时使用的格式。

java.util.Date使用如下,java.sql.Date类似。(注意时区问题,这里添加了timezone = "GMT+8")

import com.fasterxml.jackson.annotation.JsonFormat;

import java.util.Date;

public class DateModel {

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")

private Date date;

public Date getDate() {return date;}

public void setDate(Date date) {this.date = date;}

}

import com.fasterxml.jackson.core.JsonProcessingException;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Date;

public class Test {

public static void main(String[] args) throws JsonProcessingException {

DateModel dateModel = new DateModel();

dateModel.setDate(new Date());

ObjectMapper mapper = new ObjectMapper();

System.out.println(mapper.writeValueAsString(dateModel));

//{"date":"2020-01-01 12:16:54"}

}

}

但是注意如果JavaBean中的时间字段使用的是JDK8新增的时间日期(LocalDate / LocalTime / LocalDateTime)字段的话,直接这样使用是不起作用的。我们需要添加其他匹配,具体可参考GitHub上的说明:Jackson格式化JDK8日期

(1)添加jackson-datatype-jsr310的maven配置,SpringBoot的web模块会自动引入。

(2)需要进行模块注册。具体看下面的示例代码。

import com.fasterxml.jackson.annotation.JsonFormat;

import java.time.LocalDateTime;

public class DateModel {

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")

private LocalDateTime date;

public LocalDateTime getDate() {return date;}

public void setDate(LocalDateTime date) {this.date = date;}

}

import com.fasterxml.jackson.core.JsonProcessingException;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.time.LocalDateTime;

public class Test {

public static void main(String[] args) throws JsonProcessingException {

DateModel dateModel = new DateModel();

dateModel.setDate(LocalDateTime.now());

ObjectMapper mapper = new ObjectMapper();

//自动发现并注册模块

mapper.findAndRegisterModules();

System.out.println(mapper.writeValueAsString(dateModel));

//{"date":"2020-01-01 12:40:08"}

}

}

3.7. @JsonPropertyOrder

和@JsonProperty的index属性类似,指定属性序列化时的顺序。

3.8. @JsonRootName

类注解。用于指定JSON根属性的名称。生成的JSON如下所示:

{"Teacher":{"id":2,"name":"wangwu","age":35}}

示例代码:

@JsonRootName("Teacher")

public class Teacher {

private Long id;

private String name;

private Integer age;

@JsonIgnore//转换为JSON时不需要的字段,用在属性上。

private String sex;

//省略Setter/Getter方法

@Override

public String toString() {

return "Teacher{" +

"id=" + id +

", name='" + name + '\'' +

", age=" + age +

", sex='" + sex + '\'' +

'}';

}

}

Teacher teacher = new Teacher();

teacher.setId(2L);

teacher.setName("wangwu");

teacher.setAge(35);

teacher.setSex("男");

ObjectMapper mapper = new ObjectMapper();

//开启包装根植的配置

mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);

//将Java对象转换为JSON字符串

String teacherStr = mapper.writeValueAsString(teacher);

System.out.println(teacherStr);

//{"Teacher":{"id":2,"name":"wangwu","age":35}}

//开启了根包装之后,生成的json字符串和java类不对应了,

//所以在反序列化为java类的时候会报错,关闭该属性不会报错,但是值会为空

mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

//将JSON字符串转换为Java对象

Teacher tea = mapper.readValue(teacherStr, Teacher.class);

System.out.println(tea);

//Teacher{id=null, name='null', age=null, sex='null'}

3.9. @JsonAnySetter和@JsonAnyGetter

这两个属性是用来在序列化和反序列化的时候多余字段可以通过Map来回转换。也就是JSON中的字段比对应的JavaBean中的字段多,可以在JavaBean中使用一个Map字段来接收多余的JSON字段。

3.9.1. @JsonAnyGetter

(1)用在非静态方法上,没有参数,方法名随意(可以直接写在Getter方法上)。

(2)方法返回值必须是Map类型。

(3)在一个实体类中仅仅用在一个方法上。

(4)序列化的时候JSON字段的key就是返回Map的key,value就是Map的value。

3.9.2. @JsonAnySetter

(1)用在非静态方法上,注解的方法必须有两个参数,第一个是JSON字段中的key,第二个是value,方法名随意(注意这个方法不是Setter方法)。

(2)也可以用在Map对象属性上面,建议用在Map对象属性上面。

(3)反序列化的时候将对应不上的字段全部放到Map里面。

3.9.3. 示例代码

import com.fasterxml.jackson.annotation.*;

import lombok.Data;

import java.util.Arrays;

import java.util.HashMap;

import java.util.Map;

/**

* @author wangbo

* @date 2019/11/16 10:47

*/

@Data

public class Student {

private Long id;

private String name;

private Integer age;

//自定义字段

private Map other = new HashMap();

@JsonAnyGetter

public Map getOther() {

return other;

}

@JsonAnySetter

public void setOther(String key, Object value) {

this.other.put(key, value);

}

}

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

import java.util.HashMap;

import java.util.Map;

/**

* @author wangbo

* @date 2019/11/16 16:54

*/

public class Test {

public static void main(String[] args) throws IOException {

Map map = new HashMap<>();

map.put("id", 1L);

map.put("name", "菲菲");

map.put("age", 20);

map.put("score", 90);

map.put("sex", "女");

ObjectMapper mapper = new ObjectMapper();

String s = mapper.writeValueAsString(map);//序列化

System.out.println(s);

//{"score":90,"sex":"女","name":"菲菲","id":1,"age":20}

Student student = mapper.readValue(s, Student.class);//反序列化

System.out.println(student);

//Student(id=1, name=菲菲, age=20, other={score=90, sex=女})

String s1 = mapper.writeValueAsString(student);//序列化

System.out.println(s1);

//{"id":1,"name":"菲菲","age":20,"score":90,"sex":"女"}

}

}

3.10. @JsonNaming

该注解放在类上。序列化的时候该注解可将驼峰命名的字段名转换为下划线分隔的小写字母命名方式的key。反序列化的时候可以将下划线分隔的小写字母key转换为驼峰命名的字段名。

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)

代码示例:

import com.fasterxml.jackson.databind.PropertyNamingStrategy;

import com.fasterxml.jackson.databind.annotation.JsonNaming;

import lombok.Data;

/**

* @author wangbo

* @date 2019/11/16 10:47

*/

@Data

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)

public class Student {

private Long appId;

private String nickName;

private Integer nowAge;

}

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

/**

* @author wangbo

* @date 2019/11/16 16:54

*/

public class Test {

public static void main(String[] args) throws IOException {

Student student = new Student();

student.setAppId(1L);

student.setNickName("zhangsan");

student.setNowAge(20);

ObjectMapper mapper = new ObjectMapper();

String s = mapper.writeValueAsString(student);//序列化

System.out.println(s);

//{"app_id":1,"nick_name":"zhangsan","now_age":20}

Student student1 = mapper.readValue(s, Student.class);//反序列化

System.out.println(student1);

//Student(appId=1, nickName=zhangsan, nowAge=20)

}

}

4. Jackson配置

这里有三个方法,configure方法接受配置名和要设置的值,Jackson 2.5版本新加的enable和disable方法则直接启用和禁用相应属性,推荐使用后面两个方法。

// 美化输出

mapper.enable(SerializationFeature.INDENT_OUTPUT);

// 强制JSON空字符串("")转换为null对象值

mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

// 允许序列化空的POJO类(否则会抛出异常)

mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

// 把java.util.Date, Calendar输出为数字(时间戳)

mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

// 在遇到未知属性的时候不抛出异常

mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

// 在JSON中允许C/C++ 样式的注释(非标准,默认禁用)

mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);

// 允许没有引号的字段名(非标准)

mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

// 允许单引号(非标准)

mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

// 强制转义非ASCII字符

mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);

// 将内容包裹为一个JSON属性,属性名由@JsonRootName注解指定

mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
jackson所需要的所有jar jackson-all-1.6.2.jar jackson-core-asl-1.6.2.jar jackson-mapper-asl-1.6.2.jar jakarta-oro.jar 1. 背景 目前维护的产品使用jackson处理json,现整理一下jackson相关资料,希望对初次接触jackson的新手有所帮助。 jackson主页: http://jackson.codehaus.org/ jackson document: http://wiki.fasterxml.com/JacksonJavaDocs JacksonInFiveMinutes: http://wiki.fasterxml.com/JacksonInFiveMinutes 本文主要内容译自JacksonInFiveMinutes,增加了部分示例,转载请注明出处。 受java平台上各种处理xml的类库(StAX, JAXB等)启发,Jackson提供一种处理json的java类库。Jackson的目标是为开发者提供快速、准确、轻量级和用起来最爽的json处理类库。本文将概括介绍Jackson的主要功能和相关功能的使用示例。 2. 使用方式 Jackson提供三种可选的json处理方式: 1) Streaming API 又称Incremental parsing/generation, 受StAX API启发,以非关联递增方式读写json内容。 通过 org.codehaus.jackson.JsonParser读取,通过org.codehaus.jackson.JsonGenerator写入。 2) Tree Model 通过基于内存的树形结构来描述json数据,和 XML DOM类似。通过org.codehaus.jackson.map.ObjectMapper构建树,树由JsonNode节点组成。 3) Data Binding 基于属性访问或注解的方式将json和POJO对象互相转换, 受JAXB基于注解的处理方式启发。通过org.codehaus.jackson.map.ObjectMapper读写json数据。它包含两种类型: 3.1 Simple Data Binding 用于json和Java Maps, Lists, Strings, Numbers, Booleans and nulls的相互转换。 3.2 Full Data Binding 用于json和Java Bean的相互转换。 下面从使用的角度上比较三种处理方式: Streaming API 执行效率最高,读写速度最快,另外两种方式都基于它实现; Tree Model 是最灵活的; Data Binding 通常是最方便使用的;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值