JSON数据解析
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。 这些特性使JSON成为理想的数据交换语言。
JSON建构于两种结构:
“名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。
这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。
JSON具有以下这些形式:
- 对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。
值的有序列表(An ordered list of values)。在大部分语言中,它被实现为数组(array),矢量(vector),列表(list),序列(sequence)。
这些都是常见的数据结构。目前,绝大部分编程语言都以某种形式支持它们。这使得在各种编程语言之间交换同样格式的数据成为可能。
JSON具有以下这些形式:
注:
JSONObject是无序的
JSONArray是有序的
详见: JSON中国
JSON的生成和解析
JSON生成和解析通常使用三方库, 这里推荐三种方案 :
官方解析: Json-Java
阿里巴巴 : fastjson
Google : gson
接下来就通过案例去介绍各个方案的解析和生成的方法:
在解析之前呢, 需要大家将各个解析的三方包从github上下载下来, 直接搜索后面的英文就好, 但是必须要找对相应的提供商
在解析前先列出一个JSON串, 方便后续调用
public static void main(String[] args) {
String src = "{\n" +
" \"firstName\": \"John\",\n" +
" \"lastName\": \"Smith\",\n" +
" \"sex\": \"male\",\n" +
" \"age\": 25,\n" +
" \"address\": \n" +
" {\n" +
" \"streetAddress\": \"21 2nd Street\",\n" +
" \"city\": \"New York\",\n" +
" \"state\": \"NY\",\n" +
" \"postalCode\": \"10021\"\n" +
" },\n" +
" \"phoneNumber\": \n" +
" [\n" +
" {\n" +
" \"type\": \"home\",\n" +
" \"number\": \"212 555-1234\"\n" +
" },\n" +
" {\n" +
" \"type\": \"fax\",\n" +
" \"number\": \"646 555-4567\"\n" +
" }\n" +
" ]\n" +
" }";
}
1, 官方解析
官方解析是最灵活的一种方案, 但是同样带来了令人困扰的代码量多的问题 , 接下来通过案例来进行解析
/*
将JSON字符串转换为实体类对象(User)
*/
public static User parserJSON(String str){
JSONObject userObj = new JSONObject(str);
User user = new User();
user.setFirstName(userObj.optString("firstName"));
user.setLastName(userObj.optString("lastName"));
user.setSex(userObj.optString("sex"));
user.setAge(userObj.optInt("age"));
JSONObject addressObj = userObj.optJSONObject("address");
Address address = new Address();
address.setStreetAddress(addressObj.optString("streetAddress"));
address.setCity(addressObj.optString("city"));
address.setState(addressObj.optString("state"));
address.setPostalCode(addressObj.optString("postalCode"));
user.setAddress(address);
JSONArray phoneNumber = userObj.optJSONArray("phoneNumber");
List<Phone> phones = new ArrayList<>();
for (int i = 0; i < phoneNumber.length(); i++) {
Phone phone = new Phone();
JSONObject phoneObj = phoneNumber.optJSONObject(i);
phone.setType(phoneObj.optString("type"));
phone.setNumber(phoneObj.optString("number"));
phones.add(phone);
}
user.setPhoneNumber(phones);
return user;
}
/**
* 实体类对象 --> JSON
* @param user
* @return
*/
public static String toJSON(User user){
JSONObject userObj = new JSONObject();
userObj.put("firstName", user.getFirstName());
userObj.put("lastName", user.getLastName());
userObj.put("sex", user.getSex());
userObj.put("age", user.getAge());
JSONObject addressObj = new JSONObject();
Address address = user.getAddress();
addressObj.put("streetAddress", address.getStreetAddress());
addressObj.put("city", address.getCity());
addressObj.put("state", address.getState());
addressObj.put("postalCode", address.getPostalCode());
userObj.put("address", addressObj);
List<Phone> phoneNumber = user.getPhoneNumber();
JSONArray phoneArrayObj = new JSONArray();
for (int i = 0; i < phoneNumber.size(); i++) {
JSONObject phoneObj = new JSONObject();
phoneObj.put("type", phoneNumber.get(i).getType());
phoneObj.put("number", phoneNumber.get(i).getNumber());
phoneArrayObj.put(phoneObj);
}
userObj.put("phoneNumber", phoneArrayObj);
return userObj.toString();
}
}
各个JavaBean对象的写法比较简单, 这里就不列出来了
2, FastJSON解析
JSON –> 对象
//fast静态工具类 parser: 转换
//默认情况下, 必须要有无参构造方法,
//若要使用带参数的构造方法, 就需要在构造方法和所有的字段上加注解, 但是此时只会初始化构造方法包含的属性, 其他的属性值为空
User user = JSON.parseObject(str, User.class);
System.out.println(user.getFirstName());
....
对象 –> JSON
//对象 --> JSON
String s = JSON.toJSONString(user);
System.out.println(JSON.toJSONString(s));
注意 :
以上在不加注解的情况下, 各JavaBean必须使用无参的构造参数, 若要使用带参数的构造方法, 就需要在构造方法和所有的字段上加注解, 但是此时只会初始化构造方法包含的属性, 其他的属性值为空.
由于JSON字符串的属性值理论上可以为任何值, 这其中就包括数字, 例如: 10000: 一万, 但是我们的Java属性有自己的规范, 所以不能有private String 10000; 这样的属性. 为了解决这些情况我们引入注解的方式来指向这个”10000”
@JSONField(name = "123")
private String text;
还有一种特殊情况就是, JSON和实体类的类型不一致的时, 下面代码就是解决办法
JSON串
location:[50, 100]
@JSONField(serialize = false)
private int y;
@JSONField(serialize = false)
private int x;
//JSON解析成对象时调用
JSONField(name = "location")
public void setLocation(List<Integer> location){
x = location.get(0);
y = location.get(1);
}
//对象生成JSON时调用
@JSONField(name = "location")
public List<Integer> getLocation(){
List<Integer> list = new ArrayList<>();
list.add(x);
list.add(y);
return list;
}
3, GSON解析
GSON解析是谷歌发布的在Android中自带的JSON解析工具
// JSON --> 对象
//GSON解析: 非静态的解析方式, 有版本控制
//Gson gson = new Gson();
//User user = gson.fromJson(src, User.class);
//System.out.println(user.toString());
//System.out.println(user.getText());
Gson gson = new GsonBuilder().setVersion(1.1).create();
User user = gson.fromJson(src, User.class);
System.out.println(user.getText());
System.out.println(user.getX());
// JSON --> 对象
//GSON解析: 非静态的解析方式, 有版本控制
//Gson gson = new Gson();
//User user = gson.fromJson(src, User.class);
//System.out.println(user.toString());
//System.out.println(user.getText());
Gson gson = new GsonBuilder().setVersion(1.1).create();
User user = gson.fromJson(src, User.class);
System.out.println(user.getText());
System.out.println(user.getX());
谷歌解决类型不匹配的问题:
//谷歌官方文档
public class PointAdapter extends TypeAdapter<Point> {
public Point read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
String xy = reader.nextString();
String[] parts = xy.split(",");
int x = Integer.parseInt(parts[0]);
int y = Integer.parseInt(parts[1]);
return new Point(x, y);
}
public void write(JsonWriter writer, Point value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
String xy = value.getX() + "," + value.getY();
writer.value(xy);
}
}