Java与JSON
1、JSON 简介
JSON即JavaScript Object Notation(JS对象简谱),是一种轻量级的数据交换格式。XML虽然可以作为跨平台的数据交换格式,但在JS(JavaScript)中处理XML非常不方便,同时XML标记比数据多,增加了交换产生的流量。JSON没有任何标记,在JS中可作为对象处理。
故,在进行客户端与服务端交换数据的时候,会用JSON来进行数据的传输。用转化成字符串类型的json数据来进行数据交换。
2、JSON对象格式
JSONObject(对象)和JSONArray(数组),其中对象是无序的,而数据是有序的,看需求使用选择使用。
对象:JSONObject
json对象的格式:{“id”:“1”,“age”:“13”,“name”:“yang”}。
格式说明:
以“{”(左❀括号)开始,“}”(右花括号)结束。中间内容部分:由0个或多个以“,”(逗号)分隔的"key-value"键值对,key与value之间用“:”(冒号)分隔。
key应使用引号引住 (通常Java解析时,键不使用引号会报错。而JS能正确解析);value可以是JS中的任意类型的数据。
数组:JSONArray
json数组的格式:[“yang”,“li”,“zhang”]
格式说明:中括号框住内容,内容以逗号分隔。
3、Java与JSON
1、将Java中不同类型的对象(Bean、List、Map) 快速的转换为 JSON格式的字符串.
2、将JSON格式的字符串, 转换为各种类型的Java对象(Bean、List、Map)
4、GSON(com.google.gson)
Gson是google提供的用来操作json数据的一个非常好用的类库 gson 在 github 上开源地址:https://github.com/google/gson,其提供了序列化和反序列化的功能。序列化的前提是实现Serializable接口和序列化版本号
引入依赖
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
创建Gson对象
//第一种方式
Gson firstWayGson = new Gson();
//第二种方式
Gson secondWayGson = new GsonBuilder().create();
//方式二除了可以创建一个Gson对象以外还可以进行多项配置,例如,设置日期的格式化
// 例如: new GsonBuilder().setDateFormat("yyyy-MM-dd");
创建JsonObject
// 创建Json对象jsonObj1
JsonObject jsonObj1 = new JsonObject();
jsonObj1.addProperty("id", "1");//给jsonObject创建一个id属性值为1
jsonObj1.addProperty("bookName", "《深入Java虚拟机》");
jsonObj1.addProperty("bookPrice", 36.8);
log.info("jsonObj1:"+jsonObj1.toString());
// 创建Json对象jsonObj2
JsonObject jsonObj2 = new JsonObject();
jsonObj2.addProperty("chapterId", "1");
jsonObj2.addProperty("chapterName", "第一章");
// jsonObj1中添加进jsonObj2
jsonObj1.add("chapter", jsonObj2);
log.info("jsonObj1:"+jsonObj1.toString());
结果:
jsonObj1:{“id”:“1”,“bookName”:“《深入Java虚拟机》”,“bookPrice”:36.8}
添加jsonObj2的jsonObj1:{“id”:“1”,“bookName”:“《深入Java虚拟机》”,“bookPrice”:36.8,“chapter”:{“chapterId”:“1”,“chapterName”:“第一章”}}
注意:
这里的JsonObject表示我们一样可以创建一个json对象。我们后面一般使用的是Java对象跟json字符串的转换,可以用创建好的gson对象来操作。
API
1、反序列化 toJson(Java对象=转换==>Json字符串)
2、序列化 fromJson(Json字符串Java对象类型)
一、数组的序列化与反序列化
(一)、数组 ===> Json字符串
toJson(array)
// toJson(array)
String[] str = new String[]{"《深入Java虚拟机》", "《Android插件编程》", "《OpenCV全解》"};
Gson gson = new Gson();
//返回一个Json字符串
String jsonStr = gson.toJson(str);
log.info("Json字符串:"+jsonStr);
结果:Json字符串:[“《深入Java虚拟机》”,“《Android插件编程》”,“《OpenCV全解》”]
(二)、Json字符串 ===> 数组
fromJson(jsonStr, T)
// fromJson(jsonStr, T)
String[] strArray = gson.fromJson(jsonStr, String[].class);
for (String s : strArray) {
System.out.println(s);
}
结果:
《深入Java虚拟机》
《Android插件编程》
《OpenCV全解》
二、List的序列化与反序列化
(一)、List集合 ===> Json字符串
toJson(list)
List<Book> books = new ArrayList<>();
books.add(new Book("1", "《深入Java虚拟机》"));
books.add(new Book("2", "《OpenCV进阶》"));
Gson gson = new Gson();
String jsonListStr = gson.toJson(books);
log.info("jsonListStr:"+jsonListStr);
结果:
jsonListStr:[{“id”:“1”,“name”:“《深入Java虚拟机》”},{“id”:“2”,“name”:“《OpenCV进阶》”}]
(二)、Json字符串 ===> List集合
fromJson(jsonStr, T)
//获取泛型的类型
Type type = new TypeToken<List<Book>>() {}.getType();
//使用gson将字符串转换为泛型集合,即List<Book>
List<Book> books1 = gson.fromJson(jsonListStr, type);
for (Book book : books1) {
System.out.println(book.getName());
}
结果:
《深入Java虚拟机》
《OpenCV进阶》
三、对象 的序列化与反序列化
Gson gson = new Gson();
Book book = new Book("1", "《深入Java虚拟机》");
//将book类序列化成json字符串
String bookStr = gson.toJson(book);
log.info("Json字符串:"+bookStr);
//将bookStr反序列化成为Book类(已重写toString()方法)
Book b = gson.fromJson(bookStr, Book.class);
log.info("book类:"+b);
结果:
Json字符串:{“id”:“1”,“name”:“《深入Java虚拟机》”}
book类:Book(id=1, name=《深入Java虚拟机》)
5、fastjson(com.alibaba.fastjson)
fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean,其源码地址为:https://github.com/alibaba/fastjson。
引入依赖
<!-- 阿里fastjson包JSON转换-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
创建JSONObject对象
// 创建 JSONObject 对象
JSONObject jsonObj = new JSONObject();
jsonObj.put("name","《JUC并发编程》");
jsonObj.put("id",2);
JSONObject jsonObj2 = new JSONObject();
jsonObj2.put("id",3);
jsonObj2.put("name", "《Spring全家桶》");
System.out.println("jsonObj:"+jsonObj);
System.out.println("jsonObj2:"+jsonObj2);
结果:
jsonObj:{“name”:“《JUC并发编程》”,“id”:2}
jsonObj2:{“name”:“《Spring全家桶》”,“id”:3}
创建JSONArray对象
// 创建 JSONArray 对象
JSONArray jsonArray = new JSONArray();
jsonArray.add(100);
jsonArray.add(200);
jsonArray.add(300);
JSONArray jsonArray2 = new JSONArray();
jsonArray2.add("1班");
jsonArray2.add("2班");
jsonArray2.add("3班");
JSONArray jsonArray3 = new JSONArray();
jsonArray3.add(jsonObj);
jsonArray3.add(jsonObj2);
System.out.println("jsonArray:"+jsonArray);
System.out.println("jsonArray2:"+jsonArray2);
System.out.println("jsonArray3:"+jsonArray3);
结果:
jsonArray:[100,200,300]
jsonArray2:[“1班”,“2班”,“3班”]
jsonArray3:[{“name”:“《JUC并发编程》”,“id”:2},{“name”:“《Spring全家桶》”,“id”:3}]
常用API
1、对象 ===> json字符串
JSON.toJSONString(Object)
Book book = new Book(1, "《深入Java虚拟机》");
// Book对象转化为JSON字符串
String fastJsonStr = JSON.toJSONString(book);
System.out.println(fastJsonStr);
结果:{“id”:1,“name”:“《深入Java虚拟机》”}
2、json字符串 ===> Java对象
JSON.parseObject(jsonStr,Object)
// 转换成Book对象
Book jsonBook = JSON.parseObject(String.valueOf(jsonObj),Book.class);
Book jsonBook2 = JSON.parseObject(jsonObj2.toJSONString(),Book.class);
System.out.println("jsonBook:"+jsonBook);
System.out.println("jsonBook2:"+jsonBook2);
结果:
jsonBook:Book{id=2, name=‘《JUC并发编程》’}
jsonBook2:Book{id=3, name=‘《Spring全家桶》’}
注意:
1、已经重写了Book类的toString()方法
2、public static <T> T parseObject(String text, Class clazz){…}第一个形参是String,第二个是目标类。
3、json字符串 ===> 数组
JSON.parseArray(jsonStr,T.class)
// 转换成数组
List<Integer> integerList = JSON.parseArray(jsonArray.toJSONString(),Integer.class);
List<Book> bookList = JSON.parseArray(jsonArray3.toJSONString(), Book.class);
System.out.println("integerList:"+integerList);
System.out.println("bookList"+bookList);
结果:
integerList:[100, 200, 300]
bookList:[Book{id=2, name=‘《JUC并发编程》’}, Book{id=3, name=‘《Spring全家桶》’}]
注意:
1、parseArray()方法在fastjson库中用于将JSON数组字符串解析为Java的集合,但默认情况下,它返回的是一个List<Object>,其中Object是JSON数组中的元素类型。
2、Book类已经重写了toString()方法(方便显示)
3、public static <T> List<T> parseArray(String text, Class clazz) {…}
4、List(数组) ===> json字符串
JSON.toJSONString(list)
List<String> list1 = new ArrayList<>();
list1.add("《Java》");
list1.add("《Linux》");
list1.add("《Python》");
List<Book> bookList = new ArrayList<>();
bookList.add(new Book("book-cs-001","《数据库系统设计》"));
bookList.add(new Book("book-cs-002","《Linux系统基础》"));
bookList.add(new Book("book-cs-003","《深入浅出计算机操作系统》"));
String jsonStr = JSON.toJSONString(list1);
String jsonStr2 = JSON.toJSONString(bookList);
System.out.println("jsonStr:"+jsonStr);
System.out.println("jsonStr2:"+jsonStr2);
结果:
jsonStr:[“《Java》”,“《Linux》”,“《Python》”]
jsonStr2:[{“id”:“book-cs-001”,“name”:“《数据库系统设计》”},{“id”:“book-cs-002”,“name”:“《Linux系统基础》”},{“id”:“book-cs-003”,“name”:“《深入浅出计算机操作系统》”}]
5、几种json字符串转Map的方式
(一)、第1种方式:用 JSON类的parse(String str) 来解析JSON字符串
// 自定义的json字符串(后续不在展示)
String jsonStr = "{'0':'《深入浅出Java》','1':'《Linux基础》','2':'《计算机操作系统》'}";
// 第一种方式 用JSON类的parse(String str)来解析JSON字符串
Map mapType1 = (Map) JSON.parse(jsonStr);
for (Object map : mapType1.entrySet()){
System.out.println(((Map.Entry)map).getKey()+" " + ((Map.Entry)map).getValue());
}
结果:
0 《深入浅出Java》
1 《Linux基础》
2 《计算机操作系统》
(二)、第2种方式:用 JSON类的parseObject(String str) 来解析JSON字符串
// 第二种方式 用JSON类的parseObject(String str)来解析JSON字符串
Map mapType2 = JSON.parseObject(jsonStr);
for (Object obj : mapType2.keySet()){
System.out.println("key为:"+obj+",值为:"+mapType2.get(obj));
}
结果:
key为:0,值为:《深入浅出Java》
key为:1,值为:《Linux基础》
key为:2,值为:《计算机操作系统》
(三)、第3种方式:用 JSON类的parseObject(String str, T.class) 来解析JSON字符串
// 第三种方式 用JSON类的parseObject(String str, T.class)来解析JSON字符串
Map mapType3 = JSON.parseObject(jsonStr,Map.class);
for (Object obj : mapType3.keySet()) {
System.out.println("key:" + obj + ",value:" + mapType3.get(obj));
}
结果:
key:0,value:《深入浅出Java》
key:1,value:《Linux基础》
key:2,value:《计算机操作系统》
(四)、第4种方式:用 JSONObject类的parse(String str) 来解析JSON字符串
// 自定义的json字符串(后续不在展示)
String jsonStr = "{'0':'《计算机网络》','1':'《计算机组成原理》','2':'《Shell编程入门》'}";
// 第四种方式 用JSONObject类的parse(String str)来解析JSON字符串
Map jsonMap1 = (Map) JSONObject.parse(jsonStr);
for (Object map : jsonMap1.entrySet()) {
System.out.println(((Map.Entry) map).getKey() + " " + ((Map.Entry) map).getValue());
}
结果:
0 《计算机网络》
1 《计算机组成原理》
2 《Shell编程入门》
(五)、第5种方式:用 JSONObject类的parse(String str) 来解析JSON字符串
JSONObject是Map接口的一个实现类
// 第五种方式
JSONObject jsonObject = JSONObject.parseObject(jsonStr);
for (Object map : jsonObject.entrySet()){
System.out.println("key为:"+ ((Map.Entry)map).getKey()+",Value为:"+((Map.Entry)map).getValue());
}
结果:
key为:0,Value为:《计算机网络》
key为:1,Value为:《计算机组成原理》
key为:2,Value为:《Shell编程入门》
(六)、第6种方式:用 JSONObject类的parse(String str, T.class) 来解析JSON字符串
//第六种方式 用JSONObject类的parse(String str, T.class)来解析JSON字符串
Map mapObj = JSONObject.parseObject(jsonStr,Map.class);
for (Object map: mapObj.entrySet()){
System.out.println("key:"+((Map.Entry)map).getKey()+",Value:"+((Map.Entry)map).getValue());
}
结果:
key:0,Value:《计算机网络》
key:1,Value:《计算机组成原理》
key:2,Value:《Shell编程入门》
6、jackson(com.fasterxml.jackson)
简单介绍
Jackson是一个用于处理JSON数据的开源Java库,它提供了丰富的功能,包括将Java对象转换为JSON字符串(序列化)以及将JSON字符串转换为Java对象(反序列化)。Spring MVC 的默认 json 解析器便是 Jackson。与其他 Java 的 json 的框架 Gson 等相比, Jackson 解析大的 json 文件速度比较快;Jackson 运行时占用内存比较低,性能比较好;Jackson 有灵活的 API,可以很容易进行扩展和定制。
引入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
Jackson 的核心模块由三部分组成:
jackson-core,核心包,提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator。Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
jackson-annotations,注解包,提供标准注解功能;
jackson-databind,数据绑定包, 提供基于"对象绑定" 解析的相关 API (ObjectMapper) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API。
案例
使用ObjectMapper进行序列化和反序列化
try {
ObjectMapper mapper = new ObjectMapper();
// 造数据
Person person = new Person();
person.setName("Tom");
person.setAge(40);
person.setDate(new Date());
System.out.println("序列化");
String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(person);
System.out.println(jsonString);
System.out.println("反序列化");
Person deserializedPerson = mapper.readValue(jsonString, Person.class);
System.out.println(deserializedPerson);
} catch (IOException e) {
e.printStackTrace();
}
结果:
序列化
{
“name” : “Tom”,
“age” : 40,
“date” : 1718109663893,
“height” : 0
}
反序列化
Person{name=Tom, age=‘40’, date=‘Tue Jun 11 20:41:03 CST 2024’, height=‘0’}
注意:
Jackson 最常用的 API 就是基于"对象绑定" 的 ObjectMapper。
ObjectMapper 通过 writeValue 系列方法将 java 对象序列化为 json,并将 json 存储成不同的格式,String(writeValueAsString),Byte Array(writeValueAsString),Writer, File,OutStream 和 DataOutput。
ObjectMapper 通过 readValue 系列方法 从不同的数据源像 String , Byte Array, Reader,File,URL, InputStream 将 json 反序列化为 java 对象。
配置ObjectMapper
在调用 writeValue 或调用 readValue 方法之前,往往需要设置 ObjectMapper 的相关配置信息,这些配置信息应用 java 对象的所有属性上。
// 在反序列化时忽略在 json 中存在但 Java 对象不存在的属性
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 在序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// 在序列化时自定义时间日期格式
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 在序列化时忽略值为 null 的属性
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 在序列化时忽略值为默认值的属性
mapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_DEFAULT);
配置了 mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
之后,上面测试代码的输出结果为:
序列化
{
“name” : “Tom”,
“age” : 40,
“date” : “2024-06-12 09:49:35”,
“height” : 0
}
反序列化
Person{name=‘Tom’, age=40, date=Wed Jun 12 09:49:35 GMT+08:00 2024, height=0}
使用注解
可以使用注解灵活调整Jackson默认方式序列化和反序列化java对象
注解 | 用法 |
---|---|
@JsonProperty | 用于属性,把属性的名称序列化时转换为另外一个名称。示例:@JsonProperty(“birth_date”) private Date birthDate |
@JsonIgnore | 可用于字段、getter/setter、构造函数参数上,作用相同,都会对相应的字段产生影响。使相应字段不参与序列化和反序列化。 |
@JsonIgnoreProperties | 该注解是类注解。该注解在Java类和JSON不完全匹配的时候使用。 |
@JsonFormat | 用于属性或者方法,把属性的格式序列化时转换成指定的格式。示例:@JsonFormat(timezone = “GMT+8”, pattern = “yyyy-MM-dd HH:mm”) public Date getBirthDate() |
@JsonPropertyOrder | 用于类, 和 @JsonProperty 的index属性类似,指定属性在序列化时 json 中的顺序 , 示例:@JsonPropertyOrder({ “birth_Date”, “name” }) public class Person |
@JsonCreator | 用于构造方法,和 @JsonProperty 配合使用,适用有参数的构造方法。示例:@JsonCreator public Person(@JsonProperty(“name”)String name) {…} |
@JsonAnySetter | 用于属性或者方法,设置未反序列化的属性名和值作为键值存储到 map 中 @JsonAnySetter public void set(String key, Object value) { map.put(key, value); } |
@JsonAnyGetter | 用于方法 ,获取所有未序列化的属性 public Map<String, Object> any() { return map; } |
@JsonNaming | 类注解。序列化的时候该注解可将驼峰命名的字段名转换为下划线分隔的小写字母命名方式。反序列化的时候可以将下划线分隔的小写字母转换为驼峰命名的字段名。示例:@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) |
@JsonNaming | 类注解。需开启mapper.enable(SerializationFeature.WRAP_ROOT_VALUE),用于序列化时输出带有根属性名称的 JSON 串,形式如 {“root_name”:{“id”:1,“name”:“zhangsan”}}。但不支持该 JSON 串反序列化。 |
测试实体类
// 用于类,指定属性在序列化时 json 中的顺序
@JsonPropertyOrder({"date", "user_name"})
// 批量忽略属性,不进行序列化
@JsonIgnoreProperties(value = {"other"})
// 用于序列化与反序列化时的驼峰命名与小写字母命名转换
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class User {
@JsonIgnore
private Map<String, Object> other = new HashMap<>();
// 正常case
@JsonProperty("user_name")
private String userName;
// 空对象case
private Integer age;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
// 日期转换case
private Date date;
// 默认值case
private int height;
public User() {
}
// 反序列化执行构造方法
@JsonCreator
public User(@JsonProperty("user_name") String userName) {
System.out.println("@JsonCreator 注解使得反序列化自动执行该构造方法 " + userName);
// 反序列化需要手动赋值
this.userName = userName;
}
@JsonAnySetter
public void set(String key, Object value) {
other.put(key, value);
}
@JsonAnyGetter
public Map<String, Object> any() {
return other;
}
// 默认省略getter、setter方法、重写的toString方法
测试代码
@Test
public void testNote() throws IOException{
ObjectMapper mapper = new ObjectMapper();
// 造数据
Map<String, Object> map = new HashMap<>();
map.put("user_name", "Tom");
map.put("date", "2020-07-26 19:28:44");
map.put("age", 100);
map.put("demoKey", "demoValue");
String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);
System.out.println(jsonString);
System.out.println("反序列化");
User user = mapper.readValue(jsonString, User.class);
System.out.println(user);
System.out.println("序列化");
jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(user);
System.out.println(jsonString);
}
结果:
{
“date” : “2020-07-26 19:28:44”,
“demoKey” : “demoValue”,
“user_name” : “Tom”,
“age” : 100
}
反序列化
@JsonCreator 注解使得反序列化自动执行该构造方法 Tom
User{other={demoKey=demoValue}, userName=‘Tom’, age=100, date=Sun Jul 26 19:28:44 GMT+08:00 2020, height=0}
序列化
{
“date” : “2020-07-26 19:28:44”,
“user_name” : “Tom”,
“age” : 100,
“height” : 0,
“demoKey” : “demoValue”
}
日期处理
不同类型的日期类型,JackSon 的处理方式也不同。
(一)、普通日期
日期类型为:
java.util.Calendar,
java.util.GregorianCalendar,
java.sql.Date,
java.util.Date,
java.sql.Timestamp,
若不指定格式,在 json 文件中将序列化为 long 类型的数据("使用ObjectMapper进行序列化和反序列化"中的结果就可以看出)。
JackSon 有很多方式转换日期格式。
1、注解方式,使用 @JsonFormat 注解指定日期格式。
2、ObjectMapper 方式,调用 ObjectMapper 的方法 setDateFormat,将序列化为指定格式的 string 类型的数据。
(二)、Local日期
日期类型为:
java.time.LocalDate,
java.time.LocalDateTime,
还需要配置ObjectMapper,mapper.registerModule(new JavaTimeModule())
。
同时导入依赖
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.9.1</version>
</dependency>
对于Jackson 2.5 以下版本,需要添加代码 mapper.registerModule(new JSR310Module ())
。
测试实体类
@Data
public class Student {
private String name;
private LocalDateTime date;
}
测试代码
@Test
public void testJacksonTimeUtils() throws IOException {
ObjectMapper mapper = new ObjectMapper();
// 必须添加对LocalDate的支持
mapper.registerModule(JavaTimeModule());
Student student = new Student();
student.setName("Tom");
student.setDate(LocalDateTime.now());
System.out.println("序列化");
String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(student);
System.out.println(jsonString);
System.out.println("反序列化");
Student deserializedPerson = mapper.readValue(jsonString, Student.class);
System.out.println(deserializedPerson);
}
自定义日期序列化与反序列化器(在ObjectMapper上)
private Module JavaTimeModule() {
JavaTimeModule module = new JavaTimeModule();
String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
String DATE_FORMAT = "yyyy-MM-dd";
String TIME_FORMAT = "HH:mm:ss";
module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
module.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
module.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern((TIME_FORMAT))));
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(TIME_FORMAT)));
return module;
}
结果:
序列化
{
“name” : “Tom”,
“date” : “2024-06-12 11:03:07”
}
反序列化
Student(name=Tom, date=2024-06-12T11:03:07)
注意:小节“自定义序列化类”中有较为详细介绍,除了通过自定义序列化和反序列化类,然后注册到ObjectMapper中的方式。还可以通过注解的方式在类上注册序列化程序
(三)、Joda日期
日期类型为:
org.joda.time.DateTime
还需要添加代码mapper.registerModule(new JodaModule())
,导入依赖:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>2.9.1</version>
</dependency>
对象集合
Jackson 对泛型反序列化也提供很好的支持。
(一)、List
对于 List 类型 ,可以调用 constructCollectionType() 方法来序列化,也可以构造TypeReference 来序列化。
@Test
public void test5() throws IOException {
ObjectMapper mapper = new ObjectMapper();
CollectionType javaType = mapper.getTypeFactory().constructCollectionType(List.class, Person.class);
//在序列化时自定义时间日期格式
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
List<Person> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Person person = new Person();
person.setName("Tom");
person.setAge(new Random().nextInt(100));
person.setDate(new Date());
list.add(person);
}
System.out.println("序列化");
String jsonInString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(list);
System.out.println(jsonInString);
System.out.println("反序列化:使用 javaType");
List<Person> personList = mapper.readValue(jsonInString, javaType);
System.out.println(personList);
System.out.println("反序列化:使用 TypeReference");
List<Person> personList2 = mapper.readValue(jsonInString, new TypeReference<List<Person>>() {});
System.out.println(personList2);
}
结果:
序列化
[ {
“name” : “Tom”,
“age” : 65,
“date” : “2024-06-12 11:25:35”,
“height” : 0
}, {
“name” : “Tom”,
“age” : 52,
“date” : “2024-06-12 11:25:35”,
“height” : 0
}, {
“name” : “Tom”,
“age” : 22,
“date” : “2024-06-12 11:25:35”,
“height” : 0
} ]
反序列化:使用 javaType
[Person{name=‘Tom’, age=65, date=Wed Jun 12 11:25:35 GMT+08:00 2024, height=0}, Person{name=‘Tom’, age=52, date=Wed Jun 12 11:25:35 GMT+08:00 2024, height=0}, Person{name=‘Tom’, age=22, date=Wed Jun 12 11:25:35 GMT+08:00 2024, height=0}]
反序列化:使用 TypeReference
[Person{name=‘Tom’, age=65, date=Wed Jun 12 11:25:35 GMT+08:00 2024, height=0}, Person{name=‘Tom’, age=52, date=Wed Jun 12 11:25:35 GMT+08:00 2024, height=0}, Person{name=‘Tom’, age=22, date=Wed Jun 12 11:25:35 GMT+08:00 2024, height=0}]
注意:对于 map 类型, 与 List 的实现方式相似。
//第二参数是 map 的 key 的类型,第三参数是 map 的 value 的类型
MapType javaType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, Person.class);
Array 和 Collection 的处理与 List,Map 相似。
属性可视化(可序列和可反序列)
JackSon 不是所有的属性都可以被序列化和反序列化(可视化)。默认的属性可视化的规则如下:
1、若该属性修饰符是 public,该属性可序列化和反序列化。
2、若属性的修饰符不是 public,但是它的 getter 方法(用于序列化)和 setter 方法(用于反序列化)是 public,该属性可序列化和反序列化。
3、若属性只有 public 的 setter 方法,而无 public 的 getter 方 法,该属性只能用于反序列化。
若想更改默认的属性可视化的规则,需要调用 ObjectMapper 的方法 setVisibility。
ObjectMapper mapper = new ObjectMapper();
// PropertyAccessor 支持的类型有 ALL,CREATOR,FIELD,GETTER,IS_GETTER,NONE,SETTER
// Visibility 支持的类型有 ANY,DEFAULT,NON_PRIVATE,NONE,PROTECTED_AND_PUBLIC,PUBLIC_ONLY
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
属性过滤
属性过滤掉,不需要显示在json字符串中。除了使用 @JsonIgnore 过滤单个属性或用 @JsonIgnoreProperties 过滤多个属性之外, Jackson 还有通过代码控制的方式。
@JsonFilter("myFilter")
public interface MyFilter {
}
ObjectMapper mapper = new ObjectMapper();
//设置 addMixIn
mapper.addMixIn(Person.class, MyFilter.class);
//调用 SimpleBeanPropertyFilter 的 serializeAllExcept 方法
SimpleBeanPropertyFilter newFilter = SimpleBeanPropertyFilter.serializeAllExcept("age");
//设置 FilterProvider
FilterProvider filterProvider = new SimpleFilterProvider().addFilter("myFilter", newFilter);
// 序列化
String jsonString = mapper.setFilterProvider(filterProvider).writeValueAsString(person);
自定义序列化类
自定义序列化类:自定义的序列化类需要直接或间接继承 StdSerializer 或 JsonSerializer,同时需要利用 JsonGenerator 生成 json,重写方法 serialize。
public static class CustomSerializer extends StdSerializer<Person> {
protected CustomSerializer() {
super(Person.class);
}
@Override
public void serialize(Person person, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartObject();
jgen.writeNumberField("age", person.getAge());
jgen.writeStringField("name", person.getName());
jgen.writeStringField("msg", "已被自定义序列化");
jgen.writeEndObject();
}
}
JsonGenerator 有多种 write 方法以支持生成复杂的类型的 json,比如 writeArray,writeTree 等 。
自定义反序列化类:自定义的反序列化类需要直接或间接继承 StdDeserializer 或 JsonDeserializer,同时需要利用 JsonParser 读取 json,重写方法 deserialize
public static class CustomDeserializer extends StdDeserializer<Person> {
protected CustomDeserializer() {
super(Person.class);
}
@Override
public Person deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
Person person = new Person();
int age = (Integer) ((IntNode) node.get("age")).numberValue();
String name = node.get("name").asText();
person.setAge(age);
person.setName(name);
return person;
}
}
JsonParser 提供很多方法来读取 json 信息, 如 isClosed(), nextToken(), getValueAsString()等。
定义好自定义序列化类和自定义反序列化类,若想在程序中调用它们,还需要注册到 ObjectMapper 的 Module。
ObjectMapper mapper = new ObjectMapper();
// 生成 module
SimpleModule module = new SimpleModule("myModule");
module.addSerializer(new CustomSerializer());
module.addDeserializer(Person.class, new CustomDeserializer());
// 注册 module
mapper.registerModule(module);
或者可以通过注解方式在java对象的属性、方法或类上来调用它们:
@JsonSerialize(using = CustomSerializer.class)
@JsonDeserialize(using = CustomDeserializer.class)
树模型处理
Jackson 也提供了树模型(tree model)来生成和解析 json。树模型由 JsonNode 节点组成。程序中常常使用 ObjectNode,ObjectNode 继承于 JsonNode。
@Test
public void testNode() throws IOException {
ObjectMapper mapper = new ObjectMapper();
//构建 ObjectNode
ObjectNode personNode = mapper.createObjectNode();
//添加/更改属性
personNode.put("name", "Tom");
personNode.put("age", 40);
ObjectNode addressNode = mapper.createObjectNode();
addressNode.put("zip", "000000");
addressNode.put("street", "Road NanJing");
//设置子节点
personNode.set("address", addressNode);
System.out.println("构建 ObjectNode:" + personNode.toString());
//通过 path 查找节点
JsonNode searchNode = personNode.path("name");
System.out.println("查找子节点 name:" + searchNode.asText());
//删除属性
((ObjectNode) personNode).remove("address");
System.out.println("删除后的 ObjectNode:" + personNode.toString());
//读取 json
JsonNode rootNode = mapper.readTree(personNode.toString());
System.out.println("Json 转 JsonNode:" + rootNode);
//JsonNode 转换成 java 对象
Person person = mapper.treeToValue(personNode, Person.class);
System.out.println("JsonNode 转对象:" + person);
//java 对象转换成 JsonNode
JsonNode node = mapper.valueToTree(person);
System.out.println("对象转 JsonNode:" + node);
}
结果:
构建 ObjectNode:{“name”:“Tom”,“age”:40,“address”:{“zip”:“000000”,“street”:“Road NanJing”}}
查找子节点 name:Tom
删除后的 ObjectNode:{“name”:“Tom”,“age”:40}
Json 转 JsonNode:{“name”:“Tom”,“age”:40}
JsonNode 转对象:Person{name=‘Tom’, age=40, date=null, height=0}
对象转 JsonNode:{“name”:“Tom”,“age”:40,“date”:null,“height”:0}
7、JSONObject(org.json.JSONObject)
引入依赖
<!-- 引入org.json所需依赖 -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20160810</version>
</dependency>
构建JSONObject
(一)、直接使用 new 关键字实例化一个JSONObject对象
调用它的 put() 方法对其字段值进行设置。
JSONObject jsonObj = new JSONObject();
jsonObj.put("female", true);
jsonObj.put("hobbies", Arrays.asList(new String[] { "yoga", "swimming" }));
jsonObj.put("discount", 9.5);
jsonObj.put("age", "26");
jsonObj.put("features", new HashMap<String, Integer>() {
private static final long serialVersionUID = 1L;
{
put("height", 175);
put("weight", 70);
}
});
System.out.println(jsonObj);
结果:
{
“features”: {
“weight”: 70,
“height”: 175
},
“hobbies”: [“yoga”, “swimming”],
“discount”: 9.5,
“female”: true,
“age”: 26
}
(二)、使用Map构建
Map<String, Object> map = new HashMap<String, Object>();
map.put("female", true);
map.put("hobbies", Arrays.asList(new String[] { "yoga", "swimming" }));
map.put("discount", 9.5);
map.put("age", "26");
map.put("features", new HashMap<String, Integer>() {
private static final long serialVersionUID = 1L;
{
put("height", 175);
put("weight", 70);
}
});
JSONObject jsonObj = new JSONObject(map);
System.out.println(jsonObj);
(三)、使用JavaBean构建
实体类
@Data
public class UserInfo {
private Boolean female;
private String[] hobbies;
private Double discount;
private Integer age;
private Map<String, Integer> features;
}
测试代码
UserInfo userInfo = new UserInfo();
userInfo.setFemale(true);
userInfo.setHobbies(new String[] { "yoga", "swimming" });
userInfo.setDiscount(9.5);
userInfo.setAge(26);
userInfo.setFeatures(new HashMap<String, Integer>() {
private static final long serialVersionUID = 1L;
{
put("height", 175);
put("weight", 70);
}
});
JSONObject jsonObj = new JSONObject(userInfo);
System.out.println(jsonObj);
解析JSONObject
JSONObject为每一种数据类型都提供了一个getXXX(key)方法
例如:获取字符串类型的字段值就使用getString()方法,获取数组类型的字段值就使用getJSONArray()方法。
(一)、获取基本类型数据
System.out.println("Female: " + jsonObj.getBoolean("female"));
System.out.println("Discount: " + jsonObj.getDouble("discount"));
System.out.println("Age: " + jsonObj.getLong("age"));
(二)、获取JSONObject类型数据
getJSONObject()
JSONObject features = jsonObj.getJSONObject("features");
String[] names = JSONObject.getNames(features);
System.out.println("Features: ");
for (int i = 0; i < names.length; i++) {
System.out.println("\t"+features.get(names[i]));
}
(三)、获取数组类型数据
getJSONArray()
JSONArray hobbies = jsonObj.getJSONArray("hobbies");
System.out.println("Hobbies: ");
for (int i = 0; i < hobbies.length(); i++) {
System.out.println("\t"+hobbies.get(i));
}
8、json-lib(net.sf.json)
引入依赖
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>net.sf.ezmorph</groupId>
<artifactId>ezmorph</artifactId>
<version>1.0.6</version>
</dependency>
常用的API
import net.sf.json.JSONArray; //用于集合或数组
import net.sf.json.JSONObject; //用于对象
JSONObject object = new JSONObject();
(一)、把java 对象列表转换为json对象数组,并转为字符串
JSONArray array = JSONArray.fromObject(userlist);
String jsonstr = array.toString();
(二)、把java对象转换成json对象,并转化为字符串(好像是map)
JSONObject object = JSONObject.fromObject(invite);
String str=object.toString();
(三)、把JSON字符串转换为JAVA 对象数组
JSONObject object = JSONObject.fromObject(invite);
String str=object.toString();
(四)、把JSON字符串转换为JAVA 对象
JSONObject jsonobject = JSONObject.fromObject(str);
PassportLendsEntity passportlends = null;
try {
//获取一个json数组
JSONArray array = jsonobject.getJSONArray("passports");
//将json数组 转换成 List<PassPortForLendsEntity>泛型
List<PassPortForLendsEntity> list = new ArrayList<PassPortForLendsEntity>();
for (int i = 0; i < array.size(); i++) {
JSONObject object = (JSONObject)array.get(i);
PassPortForLendsEntity passport = (PassPortForLendsEntity)JSONObject.toBean(object,
PassPortForLendsEntity.class);
if(passport != null){
list.add(passport);
}
}