对Json进行处理的Google Gson API教程

jopen 9年前

在上一篇文章中,我们已经接触了针对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类型等)中。

{    "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;      }  }

Address.java

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();      }  }

下面是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;      }  }

Gson是主类,它暴露出fromJson()和toJson()方法进行转换工作,对于默认实现,可以直接创建对象,也可以使用GsonBuilder类提供的实用选项进行转换,比如整齐打印,字段命名转换,排除字段,日期格式化,等等。

当运行以上程序时,可以看到以下Java对象的输出。

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}  *****************************

你可以看到,使用Gson是多么的容易,这就是为什么它在JSON处理方面如此风靡。

以上的JSON处理方式是我们所熟知的对象模型,因为整个JSON被一次性的转换为对象了,在大多数情况下这足够了,然而如果JSON确实非常庞大,我们不想将其全部一次性置入内存,Gson也提供了Streaming API。

我们来看一个例子,它展示了如何使用Streaming API进行JSON到Java对象的转换。

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);              }            }      }    }

由于JSON是一个递归语言(译注:JSON本身并不是“语言”,而是一种表示方法),我们也需要针对数组和嵌套对象递归地调用解析方法。JsonToken是JsonReader中next()方法所返回的Java枚举类型,我们可以用其配合条件逻辑或switch case语句进行转换工作。根据以上代码,你应该能够理解这不是一个简单的实现,如果JSON确实非常复杂,那么代码将会变得极难维护,所以要避免使用这种方式,除非没有其他出路。

我们来看一下如何使用Gson Streaming API写出Employee对象。

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();        }    }

从Java对象到JSON的转换,与使用streaming API解析相比,相对容易一些,默认情况下JsonWriter会以一种紧凑的格式写入JSON,但也可以设置缩进进行整齐打印。

这就是Gson API演示教程的所有内容,如果你遇到任何问题,请告诉我。以下链接可以下载项目,你可以玩一玩Gson提供的多种选项。

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