對Json進行處理的Google Gson API教程

jopen 9年前發布 | 19K 次閱讀 JSON Java開發

在上一篇文章中,我們已經接觸了針對JSON處理的Java API,你很容易就會發現,它并不容易使用,無論你是否必須將JSON轉換為Java對象,或者其他需求,你都需要寫上很多與目標JSON結構高度耦合的代碼。

這也是為什么我開始留意其他能做到自行轉換格式的API,Gson映入了我的眼簾。Gson是開源的,并已被廣泛應用于JSON和Java中,Gson使用Java反射API,提供了諸多易于使用的方式將JSON轉換為Java,反之亦然。

你可以從google的代碼站點下載到Gson的jar文件,或者如果你正在使用maven,那么你所需要做的所有事情僅僅是添加以下依賴。

<dependencies>
    <!--  Gson dependency -->
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.2.4</version>
    </dependency>
</dependencies>

Gson是非常強大的API,它支持Java泛型,支持現成的JSON與Java對象的轉換,只要對象的成員名稱與JSON中的一致即可。如果針對Java bean和JSON要使用不同的名稱,那么可以使用@SerializedName注解來映射JSON和Java類中的變量。

我們來看一個復雜示例,在JSON中含有嵌套對象以及數組,我們要將其映射到Java bean的屬性(List、Map、Array類型等)中。

</div>

{
  "empID": 100,
  "name": "David",
  "permanent": false,
  "address": {
    "street": "BTM 1st Stage",
    "city": "Bangalore",
    "zipcode": 560100
  },
  "phoneNumbers": [
    123456,
    987654
  ],
  "role": "Manager",
  "cities": [
    "Los Angeles",
    "New York"
  ],
  "properties": {
    "age": "28 years",
    "salary": "1000 Rs"
  }
}

建立Java bean類,將JSON轉換為Java對象。

Employee.java

package com.journaldev.json.model;

import java.util.Arrays; import java.util.List; import java.util.Map;

import com.google.gson.annotations.SerializedName;

public class Employee {

@SerializedName("empID")
private int id;
private String name;
private boolean permanent;
private Address address;
private long[] phoneNumbers;
private String role;
private List<String> cities;
private Map<String, String> properties;

public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public boolean isPermanent() {
    return permanent;
}
public void setPermanent(boolean permanent) {
    this.permanent = permanent;
}
public Address getAddress() {
    return address;
}
public void setAddress(Address address) {
    this.address = address;
}
public long[] getPhoneNumbers() {
    return phoneNumbers;
}
public void setPhoneNumbers(long[] phoneNumbers) {
    this.phoneNumbers = phoneNumbers;
}
public String getRole() {
    return role;
}
public void setRole(String role) {
    this.role = role;
}

@Override
public String toString(){
    StringBuilder sb = new StringBuilder();
    sb.append("***** Employee Details *****n");
    sb.append("ID="+getId()+"n");
    sb.append("Name="+getName()+"n");
    sb.append("Permanent="+isPermanent()+"n");
    sb.append("Role="+getRole()+"n");
    sb.append("Phone Numbers="+Arrays.toString(getPhoneNumbers())+"n");
    sb.append("Address="+getAddress()+"n");
    sb.append("Cities="+Arrays.toString(getCities().toArray())+"n");
    sb.append("Properties="+getProperties()+"n");
    sb.append("*****************************");

    return sb.toString();
}
public List<String> getCities() {
    return cities;
}
public void setCities(List<String> cities) {
    this.cities = cities;
}
public Map<String, String> getProperties() {
    return properties;
}
public void setProperties(Map<String, String> properties) {
    this.properties = properties;
}

}</pre>

Address.java

</div>

package com.journaldev.json.model;

public class Address {

private String street;
private String city;
private int zipcode;

public String getStreet() {
    return street;
}
public void setStreet(String street) {
    this.street = street;
}
public String getCity() {
    return city;
}
public void setCity(String city) {
    this.city = city;
}
public int getZipcode() {
    return zipcode;
}
public void setZipcode(int zipcode) {
    this.zipcode = zipcode;
}

@Override
public String toString(){
    return getStreet() + ", "+getCity()+", "+getZipcode();
}

}</pre></div>

下面是Java程序,展示了如何將JSON轉換為Java對象,反之亦然。

EmployeeGsonExample.java

package com.journaldev.json.gson;

import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;

import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.journaldev.json.model.Address; import com.journaldev.json.model.Employee;

public class EmployeeGsonExample {

public static void main(String[] args) throws IOException {
    Employee emp = createEmployee();

    // Get Gson object
    Gson gson = new GsonBuilder().setPrettyPrinting().create();

    // read JSON file data as String
    String fileData = new String(Files.readAllBytes(Paths
            .get("employee.txt")));

    // parse json string to object
    Employee emp1 = gson.fromJson(fileData, Employee.class);

    // print object data
    System.out.println("nnEmployee Objectnn" + emp1);

    // create JSON String from Object
    String jsonEmp = gson.toJson(emp);
    System.out.print(jsonEmp);

}

public static Employee createEmployee() {

    Employee emp = new Employee();
    emp.setId(100);
    emp.setName("David");
    emp.setPermanent(false);
    emp.setPhoneNumbers(new long[] { 123456, 987654 });
    emp.setRole("Manager");

    Address add = new Address();
    add.setCity("Bangalore");
    add.setStreet("BTM 1st Stage");
    add.setZipcode(560100);
    emp.setAddress(add);

    List<String> cities = new ArrayList<String>();
    cities.add("Los Angeles");
    cities.add("New York");
    emp.setCities(cities);

    Map<String, String> props = new HashMap<String, String>();
    props.put("salary", "1000 Rs");
    props.put("age", "28 years");
    emp.setProperties(props);

    return emp;
}

}</pre></div>

Gson是主類,它暴露出fromJson()和toJson()方法進行轉換工作,對于默認實現,可以直接創建對象,也可以使用GsonBuilder類提供的實用選項進行轉換,比如整齊打印,字段命名轉換,排除字段,日期格式化,等等。

當運行以上程序時,可以看到以下Java對象的輸出。

</div>

Employee Object

* Employee Details * ID=100 Name=David Permanent=false Role=Manager Phone Numbers=[123456, 987654] Address=BTM 1st Stage, Bangalore, 560100 Cities=[Los Angeles, New York] Properties={age=28 years, salary=1000 Rs} *</pre></div>

你可以看到,使用Gson是多么的容易,這就是為什么它在JSON處理方面如此風靡。

以上的JSON處理方式是我們所熟知的對象模型,因為整個JSON被一次性的轉換為對象了,在大多數情況下這足夠了,然而如果JSON確實非常龐大,我們不想將其全部一次性置入內存,Gson也提供了Streaming API。

我們來看一個例子,它展示了如何使用Streaming API進行JSON到Java對象的轉換。

</div>

EmployeeGsonReader.java

package com.journaldev.json.gson;

import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List;

import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.journaldev.json.model.Address; import com.journaldev.json.model.Employee;

public class EmployeeGsonReader {

public static void main(String[] args) throws IOException {
    InputStream is = new FileInputStream("employee.txt");
    InputStreamReader isr = new InputStreamReader(is);

    //create JsonReader object
    JsonReader reader = new JsonReader(isr);

    //create objects
    Employee emp = new Employee();
    Address add = new Address();
    emp.setAddress(add);
    List<Long> phoneNums = new ArrayList<Long>();
    emp.setCities(new ArrayList<String>());
    emp.setProperties(new HashMap<String, String>());
    String key = null;
    boolean insidePropertiesObj=false;

    key = parseJSON(reader, emp, phoneNums, key, insidePropertiesObj);

    long[] nums = new long[phoneNums.size()];
    int index = 0;
    for(Long l :phoneNums){
        nums[index++] = l;
    }
    emp.setPhoneNumbers(nums);

    reader.close();
    //print employee object
    System.out.println("Employee Objectnn"+emp);
}

private static String parseJSON(JsonReader reader, Employee emp,
        List<Long> phoneNums, String key, boolean insidePropertiesObj) throws IOException {

    //loop to read all tokens
            while(reader.hasNext()){
                //get next token
                JsonToken token = reader.peek();

                switch(token){
                case BEGIN_OBJECT:
                    reader.beginObject();
                    if("address".equals(key) || "properties".equals(key)){
                        while(reader.hasNext()){
                        parseJSON(reader, emp,phoneNums, key, insidePropertiesObj);
                        }
                        reader.endObject();
                    }
                    break;
                case END_OBJECT:
                    reader.endObject();
                    if(insidePropertiesObj) insidePropertiesObj=false;
                    break;
                case BEGIN_ARRAY:
                    reader.beginArray();
                    if("phoneNumbers".equals(key) || "cities".equals(key)){
                        while(reader.hasNext()){
                            parseJSON(reader, emp,phoneNums, key, insidePropertiesObj);
                            }
                        reader.endArray();
                    }
                    break;
                case END_ARRAY:
                    reader.endArray();
                    break;
                case NAME:
                    key = reader.nextName();
                    if("properties".equals(key)) insidePropertiesObj=true;
                    break;
                case BOOLEAN:
                    if("permanent".equals(key)) emp.setPermanent(reader.nextBoolean());
                    else{
                        System.out.println("Unknown item found with key="+key);
                        //skip value to ignore it
                        reader.skipValue();
                    }
                    break;
                case NUMBER:
                    if("empID".equals(key)) emp.setId(reader.nextInt());
                    else if("phoneNumbers".equals(key)) phoneNums.add(reader.nextLong());
                    else if("zipcode".equals(key)) emp.getAddress().setZipcode(reader.nextInt());
                    else {
                        System.out.println("Unknown item found with key="+key);
                        //skip value to ignore it
                        reader.skipValue();
                    }
                    break;
                case STRING:
                    setStringValues(emp, key, reader.nextString(), insidePropertiesObj);
                    break;
                case NULL:
                    System.out.println("Null value for key"+key);
                    reader.nextNull();
                    break;
                case END_DOCUMENT:
                    System.out.println("End of Document Reached");
                    break;
                default:
                    System.out.println("This part will never execute");
                    break;

                }
            }
            return key;
}

private static void setStringValues(Employee emp, String key,
        String value, boolean insidePropertiesObj) {
    if("name".equals(key)) emp.setName(value);
    else if("role".equals(key)) emp.setRole(value);
    else if("cities".equals(key)) emp.getCities().add(value);
    else if ("street".equals(key)) emp.getAddress().setStreet(value);
    else if("city".equals(key)) emp.getAddress().setCity(value);
    else{
        //add to emp properties map
        if(insidePropertiesObj){
            emp.getProperties().put(key, value);
        }else{
            System.out.println("Unknown data found with key="+key+" value="+value);
        }

    }
}

}</pre></div>

由于JSON是一個遞歸語言(譯注:JSON本身并不是“語言”,而是一種表示方法),我們也需要針對數組和嵌套對象遞歸地調用解析方法。JsonToken是JsonReader中next()方法所返回的Java枚舉類型,我們可以用其配合條件邏輯或switch case語句進行轉換工作。根據以上代碼,你應該能夠理解這不是一個簡單的實現,如果JSON確實非常復雜,那么代碼將會變得極難維護,所以要避免使用這種方式,除非沒有其他出路。

我們來看一下如何使用Gson Streaming API寫出Employee對象。

</div>

EmployeeGsonWriter.java

package com.journaldev.json.gson;

import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Set;

import com.google.gson.stream.JsonWriter; import com.journaldev.json.model.Employee;

public class EmployeeGsonWriter {

public static void main(String[] args) throws IOException {
    Employee emp = EmployeeGsonExample.createEmployee();

    //writing on console, we can initialize with FileOutputStream to write to file
    OutputStreamWriter out = new OutputStreamWriter(System.out);
    JsonWriter writer = new JsonWriter(out);
    //set indentation for pretty print
    writer.setIndent("t");
    //start writing
    writer.beginObject(); //{
    writer.name("id").value(emp.getId()); // "id": 123
    writer.name("name").value(emp.getName()); // "name": "David"
    writer.name("permanent").value(emp.isPermanent()); // "permanent": false
    writer.name("address").beginObject(); // "address": {
        writer.name("street").value(emp.getAddress().getStreet()); // "street": "BTM 1st Stage"
        writer.name("city").value(emp.getAddress().getCity()); // "city": "Bangalore"
        writer.name("zipcode").value(emp.getAddress().getZipcode()); // "zipcode": 560100
        writer.endObject(); // }
    writer.name("phoneNumbers").beginArray(); // "phoneNumbers": [
        for(long num : emp.getPhoneNumbers()) writer.value(num); //123456,987654
        writer.endArray(); // ]
    writer.name("role").value(emp.getRole()); // "role": "Manager"
    writer.name("cities").beginArray(); // "cities": [
        for(String c : emp.getCities()) writer.value(c); //"Los Angeles","New York"
        writer.endArray(); // ]
    writer.name("properties").beginObject(); //"properties": {
        Set<String> keySet = emp.getProperties().keySet();
        for(String key : keySet) writer.name("key").value(emp.getProperties().get(key));//"age": "28 years","salary": "1000 Rs"
        writer.endObject(); // }
    writer.endObject(); // }

    writer.flush();

    //close writer
    writer.close();

}

}</pre></div>

從Java對象到JSON的轉換,與使用streaming API解析相比,相對容易一些,默認情況下JsonWriter會以一種緊湊的格式寫入JSON,但也可以設置縮進進行整齊打印。

這就是Gson API演示教程的所有內容,如果你遇到任何問題,請告訴我。以下鏈接可以下載項目,你可以玩一玩Gson提供的多種選項。

</div>

原文鏈接: Pankaj Kumar 翻譯: ImportNew.com - Justin Wu
譯文鏈接: http://www.importnew.com/14509.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!