title: Java 和 JSON 序列化
date: 2022-02-17 22:34:30
categories:
- Java
- 工具
- IO
tags:
- Java
- IO
- 序列化
- JSON
permalink: /pages/4622a6/
JSON(JavaScript Object Notation)是一种基于文本的数据交换格式。几乎所有的编程语言都有很好的库或第三方工具来提供基于 JSON 的 API 支持,因此你可以非常方便地使用任何自己喜欢的编程语言来处理 JSON 数据。
本文主要从 Java 语言的角度来讲解 JSON 的应用。
JSON 起源于 1999 年的 JS 语言规范 ECMA262 的一个子集(即 15.12 章节描述了格式与解析),后来 2003 年作为一个数据格式ECMA404(很囧的序号有不有?)发布。 2006 年,作为 rfc4627 发布,这时规范增加到 18 页,去掉没用的部分,十页不到。
JSON 的应用很广泛,这里有超过 100 种语言下的 JSON 库:json.org。
更多的可以参考这里,关于 json 的一切。
这估计是最简单标准规范之一:
{}
表示、内部是 "key":"value"
,数组用 []
表示,不同值用逗号分开false
/ null
/ true
/ object
/ array
/ number
/ string
{
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http://www.example.com/image/481989943",
"Height": 125,
"Width": "100"
},
"IDs": [116, 943, 234, 38793]
}
}
扩展阅读:
http://www.json.org/json-zh.html - 图文并茂介绍 json 数据形式
优点:
缺点:
使用 JSON 实现 RPC(类似 XML-RPC):JSON-RPC
使用 JSON 实现 path 查询操作(类似 XML-PATH):JsonPATH
在线查询工具:JsonPATH
格式化工具:jsbeautifier
chrome 插件:5 个 Json View 插件
在线 Mock: 在线 mock
Java 中比较流行的 JSON 库有:
从性能上来看,一般情况下:Fastjson > Jackson > Gson
遵循好的设计与编码风格,能提前解决 80%的问题,个人推荐 Google JSON 风格指南。
简单摘录如下:
JSON API与 Google JSON 风格指南有很多可以相互参照之处。
JSON API是数据交互规范,用以定义客户端如何获取与修改资源,以及服务器如何响应对应请求。
JSON API 设计用来最小化请求的数量,以及客户端与服务器间传输的数据量。在高效实现的同时,无需牺牲可读性、灵活性和可发现性。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>x.x.x</version>
</dependency>
Group.java
public class Group {
private Long id;
private String name;
private List<User> users = new ArrayList<User>();
}
User.java
public class User {
private Long id;
private String name;
}
初始化 Bean
Group group = new Group();
group.setId(0L);
group.setName("admin");
User guestUser = new User();
guestUser.setId(2L);
guestUser.setName("guest");
User rootUser = new User();
rootUser.setId(3L);
rootUser.setName("root");
group.addUser(guestUser);
group.addUser(rootUser);
String jsonString = JSON.toJSONString(group);
System.out.println(jsonString);
Group bean = JSON.parseObject(jsonString, Group.class);
@JSONField
扩展阅读:更多 API 使用细节可以参考:JSONField 用法,这里介绍基本用法。
可以配置在属性(setter、getter)和字段(必须是 public field)上。
@JSONField(name="ID")
public int getId() {return id;}
// 配置date序列化和反序列使用yyyyMMdd日期格式
@JSONField(format="yyyyMMdd")
public Date date1;
// 不序列化
@JSONField(serialize=false)
public Date date2;
// 不反序列化
@JSONField(deserialize=false)
public Date date3;
// 按ordinal排序
@JSONField(ordinal = 2)
private int f1;
@JSONField(ordinal = 1)
private int f2;
@JSONType
JSONType.alphabetic 属性: fastjson 缺省时会使用字母序序列化,如果你是希望按照 java fields/getters 的自然顺序序列化,可以配置 JSONType.alphabetic,使用方法如下:
@JSONType(alphabetic = false)
public static class B {
public int f2;
public int f1;
public int f0;
}
扩展阅读:更多 API 使用细节可以参考 jackson-databind 官方说明
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(new File("result.json"), myResultObject);
// or:
byte[] jsonBytes = mapper.writeValueAsBytes(myResultObject);
// or:
String jsonString = mapper.writeValueAsString(myResultObject);
ObjectMapper mapper = new ObjectMapper();
MyValue value = mapper.readValue(new File("data.json"), MyValue.class);
// or:
value = mapper.readValue(new URL("http://some.com/api/entry.json"), MyValue.class);
// or:
value = mapper.readValue("{\"name\":\"Bob\", \"age\":13}", MyValue.class);
Person p = new Person("Tom", 20);
Person p2 = new Person("Jack", 22);
Person p3 = new Person("Mary", 18);
List<Person> persons = new LinkedList<>();
persons.add(p);
persons.add(p2);
persons.add(p3);
Map<String, List> map = new HashMap<>();
map.put("persons", persons);
String json = null;
try {
json = mapper.writeValueAsString(map);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
扩展阅读:更多注解使用细节可以参考 jackson-annotations 官方说明
@JsonProperty
public class MyBean {
private String _name;
// without annotation, we'd get "theName", but we want "name":
@JsonProperty("name")
public String getTheName() { return _name; }
// note: it is enough to add annotation on just getter OR setter;
// so we can omit it here
public void setTheName(String n) { _name = n; }
}
@JsonIgnoreProperties
和 @JsonIgnore
// means that if we see "foo" or "bar" in JSON, they will be quietly skipped
// regardless of whether POJO has such properties
@JsonIgnoreProperties({ "foo", "bar" })
public class MyBean {
// will not be written as JSON; nor assigned from JSON:
@JsonIgnore
public String internal;
// no annotation, public field is read/written normally
public String external;
@JsonIgnore
public void setCode(int c) { _code = c; }
// note: will also be ignored because setter has annotation!
public int getCode() { return _code; }
}
@JsonCreator
public class CtorBean {
public final String name;
public final int age;
@JsonCreator // constructor can be public, private, whatever
private CtorBean(@JsonProperty("name") String name,
@JsonProperty("age") int age)
{
this.name = name;
this.age = age;
}
}
@JsonPropertyOrder
alphabetic 设为 true 表示,json 字段按自然顺序排列,默认为 false。
@JsonPropertyOrder(alphabetic = true)
public class JacksonAnnotationBean {}
详细内容可以参考官方文档:Gson 用户指南
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
Gson gson = new Gson();
gson.toJson(1); // ==> 1
gson.toJson("abcd"); // ==> "abcd"
gson.toJson(10L); // ==> 10
int[] values = { 1 };
gson.toJson(values); // ==> [1]
int i1 = gson.fromJson("1", int.class);
Integer i2 = gson.fromJson("1", Integer.class);
Long l1 = gson.fromJson("1", Long.class);
Boolean b1 = gson.fromJson("false", Boolean.class);
String str = gson.fromJson("\"abc\"", String.class);
String[] anotherStr = gson.fromJson("[\"abc\"]", String[].class);
Gson
实例可以通过 GsonBuilder
来定制实例化,以控制其序列化、反序列化行为。
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT, Modifier.VOLATILE)
.create();
@Since
@Since
用于控制对象的序列化版本。示例:
public class VersionedClass {
@Since(1.1) private final String newerField;
@Since(1.0) private final String newField;
private final String field;
public VersionedClass() {
this.newerField = "newer";
this.newField = "new";
this.field = "old";
}
}
VersionedClass versionedObject = new VersionedClass();
Gson gson = new GsonBuilder().setVersion(1.0).create();
String jsonOutput = gson.toJson(versionedObject);
System.out.println(jsonOutput);
System.out.println();
gson = new Gson();
jsonOutput = gson.toJson(versionedObject);
System.out.println(jsonOutput);
@SerializedName
@SerializedName
用于将类成员按照指定名称序列化、反序列化。示例:
private class SomeObject {
@SerializedName("custom_naming") private final String someField;
private final String someOtherField;
public SomeObject(String a, String b) {
this.someField = a;
this.someOtherField = b;
}
}
示例源码:javalib-io-json
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。