Gson 解析JSON示例
在上一篇文章中,我们研究了Java JSON API,您可以很容易地看出使用它并不方便。
无论您是否必须将JSON转换为Java Object,都需要编写大量与JSON结构紧密结合的代码。
Gson
我开始寻找其他可以自行完成转换的JSON解析器API,并找到了有关Google Gson的信息。
Gson是开放源代码,在处理JSON和Java方面非常常用。
Gson使用Java Reflection提供简单的方法来将JSON转换为Java,反之亦然。
Gson Maven
您可以从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中的相同,则Gson API还支持将JSON转换为Java Object。
如果要为Java bean和json使用不同的名称,则可以使用@SerializedName java批注并在JSON和Java类中映射变量。
Gson例子
让我们看一个复杂的Gson示例,该示例涉及JSON中的嵌套对象和数组,并将其映射到类型为List,Map,Array等的Java bean属性。
employee.txt
{
"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 Object。
Employee.java
package com.theitroad.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.theitroad.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();
}
}
这是显示Gson示例以解析JSON的Java程序。
EmployeeGsonExample.java
package com.theitroad.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.theitroad.json.model.Address;
import com.theitroad.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("\n\nEmployee Object\n\n" + 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是公开用于转换的方法fromfromJson()和toJson()的主要类。
对于默认实现,我们可以直接创建此对象,也可以使用GsonBuilder类提供转换的有用选项,例如漂亮的打印,字段命名约定,排除字段,日期格式等。
当您在gson示例程序上方运行时,我们将为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多么容易,这就是为什么Gson是用于JSON解析的非常流行的Java API的原因。
上面的JSON解析的Gson示例被称为对象模型,因为整个JSON会立即转换为对象。
在大多数情况下,这对我们来说已经足够了,但是如果JSON确实非常庞大并且我们不想一次将所有内容都存储在内存中,那么Gson也会提供Streaming API。
Gson示例使用流API解析JSON
让我们看一下Gson示例,在该示例中,我们将使用Streaming API将json转换为java对象。
EmployeeGsonReader.java
package com.theitroad.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.theitroad.json.model.Address;
import com.theitroad.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 Object\n\n"+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是一种递归语言,因此我们需要为数组和嵌套对象递归调用解析方法。
JsonToken是JsonReadernext()方法返回的Java枚举,我们可以将其与条件逻辑一起使用或者切换case语句进行转换。
从上面的代码中,您可以了解到这不是一个简单的实现,并且如果JSON确实很复杂,那么此代码将很难维护。
除非没有办法使用基于对象的模型,否则请避免使用它。
将对象写入文件的Gson示例
让我们看看如何使用Gson Streaming API编写Employee对象。
EmployeeGsonWriter.java
package com.theitroad.json.gson;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Set;
import com.google.gson.stream.JsonWriter;
import com.theitroad.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();
}
}
与使用Gson流API进行解析相比,将Java对象转换为JSON相对容易。
默认情况下,JsonWriter以紧凑形式编写json,但我们可以设置缩进以进行漂亮的打印。

