Java中JSON解析
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-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);
}
}