在上一篇文章中,我们已经接触了针对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提供的多种选项。
http://www.journaldev.com/?wpdmact=process&did=MzAuaG90bGluaw==
原文链接: Pankaj Kumar 翻译: ImportNew.com - Justin Wu
译文链接: http://www.importnew.com/14509.html |