Jackson
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();
        //测试代码......
    }
}

JavaBean转JSON字符串

String studentStr = mapper.writeValueAsString(student);
System.out.println(studentStr);
//{"id":1,"name":"zhangsan","age":20,"sex":null,"interest":["music","coding"]}

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])

JSON字符串转Map集合

//对泛型的反序列化,使用TypeReference可以明确的指定反序列化的类型。
//import com.fasterxml.jackson.core.type.TypeReference;
Mapmap = mapper.readValue(studentStr, new TypeReference<Map>(){});
System.out.println(map);
//{id=1, name=zhangsan, age=20, sex=null, interest=[music, coding]}

注解使用

@JsonProperty

使用在JavaBean的字段上,指定一个字段用于JSON映射,默认情况下映射的JSON字段与注解的字段名称相同。该注解有三个属性:
(1)value:用于指定映射的JSON的字段名称。常用。
(2)index:用于指定映射的JSON的字段顺序。
(3)defaultValue:定义为元数据的文本默认值。注意:core databind不使用该属性,它目前只公开给扩展模块使用。

@JsonProperty(value = “user_name”)

@JsonIgnore

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

@JsonIgnoreProperties

该注解是类注解。该注解在Java类和JSON不完全匹配的时候使用。
(1)在序列化为JSON的时候,@JsonIgnoreProperties({"prop1", "prop2"})会忽略pro1和pro2两个属性。
(2)在从JSON反序列化为Java类的时候,@JsonIgnoreProperties(ignoreUnknown=true)会忽略所有没有Getter和Setter的属性,也就是忽略类中不存在的字段。

@JsonIgnoreType

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

@JsonInclude

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

//忽略类中值为null的字段
@JsonInclude(value = JsonInclude.Include.NON_NULL)
//忽略类中值为空的字段。对于字符串,即忽略null或空字符串
@JsonInclude(Include.NON_EMPTY)

@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"}
    }
}

@JsonPropertyOrder

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

@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'}

@JsonAnySetter和@JsonAnyGetter

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

@JsonAnyGetter

(1)用在非静态方法上,没有参数,方法名随意(可以直接写在Getter方法上)。
(2)方法返回值必须是Map类型。
(3)在一个实体类中仅仅用在一个方法上。
(4)序列化的时候JSON字段的key就是返回Map的key,value就是Map的value。

@JsonAnySetter

(1)用在非静态方法上,注解的方法必须有两个参数,第一个是JSON字段中的key,第二个是value,方法名随意(注意这个方法不是Setter方法)。
(2)也可以用在Map对象属性上面,建议用在Map对象属性上面。
(3)反序列化的时候将对应不上的字段全部放到Map里面。

示例代码

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 Mapother = new HashMap();

    @JsonAnyGetter
    public MapgetOther() {
        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 {
        Mapmap = 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":"女"}
    }
}

@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)
    }
}

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);
fastJson
package test;
 
import java.util.ArrayList;
import java.util.List;
 
import com.alibaba.fastjson.JSON;
 
class User {
	private String name;
	private int age;
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public int getAge() {
		return age;
	}
 
	public void setAge(int age) {
		this.age = age;
	}
 
	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + "]";
	}
};
 
class UserGroup {
	private String name;
	private Listusers = new ArrayList();
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public ListgetUsers() {
		return users;
	}
 
	public void setUsers(Listusers) {
		this.users = users;
	}
 
	@Override
	public String toString() {
		return "UserGroup [name=" + name + ", users=" + users + "]";
	}
}
 
class FastJsonTest {
	public static void main(String[] args) {
		// 构建用户geust
		User guestUser = new User();
		guestUser.setName("guest");
		guestUser.setAge(28);
		// 构建用户root
		User rootUser = new User();
		rootUser.setName("root");
		guestUser.setAge(35);
		// 构建用户组对象
		UserGroup group = new UserGroup();
		group.setName("admin");
		group.getUsers().add(guestUser);
		group.getUsers().add(rootUser);
		// 用户组对象转JSON串
		String jsonString = JSON.toJSONString(group);
		System.out.println("jsonString:" + jsonString);
		// JSON串转用户组对象
		UserGroup group2 = JSON.parseObject(jsonString, UserGroup.class);
		System.out.println("group2:" + group2);
 
		// 构建用户对象数组
		User[] users = new User[2];
		users[0] = guestUser;
		users[1] = rootUser;
		// 用户对象数组转JSON串
		String jsonString2 = JSON.toJSONString(users);
		System.out.println("jsonString2:" + jsonString2);
		// JSON串转用户对象列表
		Listusers2 = JSON.parseArray(jsonString2, User.class);
		System.out.println("users2:" + users2);
	}
}

输出结果如下:

jsonString:{"name":"admin","users":[{"age":35,"name":"guest"},{"age":0,"name":"root"}]}
group2:UserGroup [name=admin, users=[User [name=guest, age=35], User [name=root, age=0]]]
jsonString2:[{"age":35,"name":"guest"},{"age":0,"name":"root"}]
users2:[User [name=guest, age=35], User [name=root, age=0]]

参考文档1