JSON(JavaScript Object Notation)是一种基于文本的数据交换格式。几乎所有的编程语言都有很好的库或第三方工具来提供基于 JSON 的 API 支持,因此你可以非常方便地使用任何自己喜欢的编程语言来处理 JSON 数据。
JSON 起源于 1999 年的 JS 语言规范 ECMA262 的一个子集,后来 2003 年作为一个数据格式ECMA404(404???)发布。
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": "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png","Height": 125,"Width": "100"},"IDs": [116, 943, 234, 38793]}
}
优点:
缺点:
使用 JSON 实现 path 查询操作(类似 XML-PATH):JsonPATH
在线查询工具:JsonPATH、 json.cn
格式化工具:jsbeautifier
chrome 插件:5 个 Json View 插件
Java 中比较流行的 JSON 库有:
从性能上来看,一般情况下:Fastjson > Jackson > Gson
遵循好的设计与编码风格,能提前解决 80%的问题,推荐 Google JSON 风格指南。
- 英文版Google JSON Style Guide:https://google.github.io/styleguide/jsoncstyleguide.xml
- 中文版Google JSON 风格指南:https://github.com/darcyliu/google-styleguide/blob/master/JSONStyleGuide.md
简单摘录如下:
JSON API与 Google JSON 风格指南有很多可以相互参照之处。
JSON API是数据交互规范,用以定义客户端如何获取与修改资源,以及服务器如何响应对应请求。
JSON API 设计用来最小化请求的数量,以及客户端与服务器间传输的数据量。在高效实现的同时,无需牺牲可读性、灵活性和可发现性。
com.alibaba fastjson x.x.x
Group.java
public class Group {private Long id;private String name;private List users = new ArrayList();
}
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)和字段(若属性是私有的,必须有set*方法。否则无法反序列化)上。
@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 官方说明
com.fasterxml.jackson.core jackson-databind 2.9.8
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 persons = new LinkedList<>();
persons.add(p);
persons.add(p2);
persons.add(p3);Map 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 herepublic 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:@JsonIgnorepublic String internal;// no annotation, public field is read/written normallypublic String external;@JsonIgnorepublic 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, whateverprivate 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 用户指南
com.google.code.gson gson 2.8.6
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;}
}