Hướng dẫn sử dụng Java Json Processing API (JSONP)
Công ty Vĩnh Cửu tuyển dụng lập trình viên Java

1- JSON là gì?

JSON (JavaScript Object Notation) là một dữ liệu văn bản có cấu trúc, các phần tử của nó là một cặp khóa và giá trị, giá trị của nó cũng có thể là một phần tử (khóa & giá trị) khác, đôi khi giá trị cũng có thể là một mảng.
Đây là một cấu trúc dữ liệu JSON:
{
"name" : "Tran",
"address" : "Hai Duong, Vietnam",
"phones" : [0121111111, 012222222]
}
Ví dụ với các cặp khóa giá trị lồng nhau:
{
 "id": 111 ,
 "name":"Microsoft",
 "websites": [
    "http://microsoft.com",
    "http://msn.com",
    "http://hotmail.com"
 ],
 "address": {
    "street":"1 Microsoft Way",
    "city":"Redmond"
 }
}

2- Các thư viện phân tích Json

Có rất nhiều thư viện Java mã nguồn mở giúp bạn phân tích dữ liệu Json. Dưới đây là danh sách các thư viện như vậy:
  1. json.org
  2. Jackson
  3. Google GSON
  4. json-lib
  5. javax json
  6. json-simple
  7. json-smart
  8. flexjson
  9. fastjson

3- Json Processing API

JSON Processing (JSR-353) API được giới thiệu trong đặc tả của Java EE 7, điều đó có nghĩa là thư viện của nó sẵn có trên các Web Server tương thích Java EE 7. Bạn cũng có thể download các thư viện này hoặc sử dụng Maven.

Với Maven:
<!-- http://mvnrepository.com/artifact/org.glassfish/javax.json -->
<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.json</artifactId>
   <version>1.0.4</version>
</dependency>
JSON-P được phân chia thành hai API cốt lõi :
  1. API Streaming (javax.json.stream),
  2. JSON API Object Model (javax.json).

Streaming API được sử dụng để phân tích tài liệu JSON theo cách duyệt từ trên xuống dưới, và phát ra các sự kiện mỗi khi nó phân tích được một phần tử của tài liệu. API này thích hợp để phân tích các tài liệu JSON lớn, vì nó không lưu trữ dữ liệu trên bộ nhớ.

Các API Object Model, là API đơn giản và dễ sử dụng hơn, vì nó sử dụng API Streaming để đọc toàn bộ tài liệu JSON và tạo ra các đối tượng có cấu trúc cây trên bộ nhớ. API này thích hợp để phân tích các tài liệu JSON nhỏ.

4- Tạo Maven Project

Bạn có thể tạo nhanh một Maven project và khai báo sử dụng thư viện JSON-P
Thư viện maven:
<!-- http://mvnrepository.com/artifact/org.glassfish/javax.json -->
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.json</artifactId>
    <version>1.0.4</version>
</dependency>
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
 http://maven.apache.org/xsd/maven-4.0.0.xsd">

 <modelVersion>4.0.0</modelVersion>

 <groupId>org.o7planning</groupId>
 <artifactId>JSONPTutorial</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>JSONPTutorial</name>
 <url>http://maven.apache.org</url>

 <properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>


   <dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <version>3.8.1</version>
     <scope>test</scope>
   </dependency>
   
   <!-- http://mvnrepository.com/artifact/org.glassfish/javax.json -->
   <dependency>
       <groupId>org.glassfish</groupId>
       <artifactId>javax.json</artifactId>
       <version>1.0.4</version>
   </dependency>
   
   
 </dependencies>

</project>

5- Tổng quan về JSON-P

Một số Interface quan trọng của JSON API là:
Interface Description
javax.json.JsonReader Bạn có thể sử dụng nó để đọc đối tượng JSON hoặc một mảng và trả về JsonObject. Bạn có thể có được  JsonReader từ class Json hoặc JsonReaderFactory.
javax.json.JsonWriter Bạn có thể sử dụng class này để ghi đối tượng JSON vào luồng đầu ra.
javax.json.stream.JsonParser Nó làm việc như một bộ phân tích đầy đủ, và cung cấp hỗ trợ luồng đọc các đối tượng JSON.
javax.json.stream.JsonGenerator Bạn có thể sử dụng class này để ghi các đối tượng JSON vào các luồng đầu ra.
javax.json.Json Class này sử dụng để tạo ra các đối tượng sử lý JSON.

6- Ví dụ với JSON-P

Ví dụ dưới đây là một file dữ liệu JSON:
company.txt
{
  "id": 111 ,
  "name":"Microsoft",
  "websites": [
     "http://microsoft.com",
     "http://msn.com",
     "http://hotmail.com"
  ],
  "address":{
     "street":"1 Microsoft Way",
     "city":"Redmond"
  }
}

Chú ý: Tên của thuộc tính cần phải đặt trong dấu "" (Dấu nháy kép), chẳng hạn:

  • "id": 111

Đôi khi dữ liệu JSON có tên thuộc tính không nằm trong dấu ngặc kép và một bộ phân tích dữ liệu JSON vẫn hiểu và cho phép điều đó, tuy nhiên bộ phân tích JSON-P không cho phép điều này, nếu bạn sử dụng Java JSON-P phân tích một dữ liệu JSON có tên thuộc tính không nằm trong dấu ngặc kép, bạn sẽ nhận được một ngoại lệ:

  • javax.json.stream.JsonParsingException: Unexpected char 105 at (line no=xx, column no=xx, offset=xx)
Address.java
package org.o7planning.jsonptutorial.beans;

public class Address {
   
   private String street;
   private String city;

   public Address() {

   }

   public Address(String street, String city) {
       this.street = street;
       this.city = city;
   }

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

   @Override
   public String toString() {
       return street + ", " + city;
   }
   
}
Company.java
package org.o7planning.jsonptutorial.beans;

public class Company {

   private int id;
   private String name;
   private String[] websites;
   private Address address;

   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 String[] getWebsites() {
       return websites;
   }

   public void setWebsites(String[] websites) {
       this.websites = websites;
   }

   public Address getAddress() {
       return address;
   }

   public void setAddress(Address address) {
       this.address = address;
   }

   @Override
   public String toString() {
       StringBuilder sb = new StringBuilder();

       sb.append("\n id:" + this.id);
       sb.append("\n name:" + this.name);
       if (this.websites != null) {
           sb.append("\n website: ");
           for (String website : this.websites) {
               sb.append(website + ", ");
           }
       }
       if (this.address != null) {
           sb.append("\n address:" + this.address.toString());
       }
       return sb.toString();
   }

}
JsonReader là một đối tượng dùng để đọc dữ liệu JSON, bạn có thể có được đối tượng JsonReader từ class Json hoặc từ JsonReaderFactory.
 
InputStream input = new FileInputStream("company.txt");

 
// Lấy ra đối tượng JsonReader từ class Json
JsonReader jsonReader1 = Json.createReader(input);

 
// Hoặc từ Factory
JsonReaderFactory factory = Json.createReaderFactory(null);
JsonReader jsonReader2 = factory.createReader(input);
JsonReaderExample.java
package org.o7planning.jsonptutorial;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.JsonValue;

import org.o7planning.jsonptutorial.beans.Address;
import org.o7planning.jsonptutorial.beans.Company;

public class JsonReaderExample {
 
  public static void main(String[] args) throws IOException {
      InputStream input = new FileInputStream("company.txt");
     
      // Tạo đối tượng JsonReader từ class Json.
      JsonReader jsonReader = Json.createReader(input);
   
     
      // Lấy ra đối tượng JsonObject mô tả dữ liệu JSON.
      JsonObject rootJSON = jsonReader.readObject();
     
      // Close resources
      jsonReader.close();
      input.close();
     
      // Tạo đối tượng Company rỗng.
      Company company = new Company();
     
      company.setId(rootJSON.getInt("id"));
      company.setName(rootJSON.getString("name"));
     
     
      // Đọc thông tin mảng các website trong JSON.
      JsonArray jsonArray = rootJSON.getJsonArray("websites");
      String[] websites = new String[jsonArray.size()];
     
      int index = 0;
      for(JsonValue value : jsonArray){
          websites[index++] = value.toString() ;
      }
      company.setWebsites(websites);
     
      // Lấy ra đối tượng JsonObject nằm trong đối tượng json.
      JsonObject addressJSON = rootJSON.getJsonObject("address");
      Address address = new Address();
      address.setStreet(addressJSON.getString("street"));
      address.setCity(addressJSON.getString("city"));
   
      company.setAddress(address);
     
      // Ghi thông tin ra.
      System.out.println(company);
     
  }

}
Chạy ví dụ:

7- Ví dụ với JsonWriter

JsonWriterExample.java
package org.o7planning.jsonptutorial;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;

import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonWriter;

import org.o7planning.jsonptutorial.beans.Address;
import org.o7planning.jsonptutorial.beans.Company;

public class JsonWriterExample {

   public static void main(String[] args) throws FileNotFoundException {

       Company company = createCompany();

       // Object Builder
       JsonObjectBuilder companyBuilder = Json.createObjectBuilder();
       
       // Object Builder
       JsonObjectBuilder addressBuilder = Json.createObjectBuilder();
       
       // Array Builder
       JsonArrayBuilder websitesBuilder = Json.createArrayBuilder();

       for (String website : company.getWebsites()) {
           websitesBuilder.add(website);
       }

       Address address = company.getAddress();
       addressBuilder.add("street", address.getStreet()).add("city", address.getCity() );

       companyBuilder.add("id", company.getId()).add("name", company.getName() );

       companyBuilder.add("websites", websitesBuilder);
       companyBuilder.add("address", addressBuilder);

       // Đối tượng JsonObject gốc.
       JsonObject rootJSONObject = companyBuilder.build();

       System.out.println("Root JsonObject: " + rootJSONObject);

       // Ghi ra file.
       File outFile= new File("C:/test/company2.txt");
       outFile.getParentFile().mkdirs();
       
       OutputStream os = new FileOutputStream(outFile);
       JsonWriter jsonWriter = Json.createWriter(os);
       
       jsonWriter.writeObject(rootJSONObject);
       jsonWriter.close();
   }

   public static Company createCompany() {

       Company company = new Company();
       company.setId(123);
       company.setName("Apple");

       String[] websites = { "http://apple.com"};
       company.setWebsites(websites);

       Address address = new Address();
       address.setCity("Cupertino");
       address.setStreet("1 Infinite Loop");

       company.setAddress(address);

       return company;
   }
   
}
Chạy ví dụ:

8- Ví dụ với JsonParser

Ở trên bạn đã làm việc với JsonReader để đọc nội dung file json, toàn bộ nội dung Json được đối tượng hóa và lưu trữ trên bộ nhớ, cách này chỉ phù hợp khi bạn làm việc với các dữ liệu Json nhỏ. Trong trường hợp dữ liệu lớn bạn nên sử dụng JsonParser để phân tích dữ liệu Json. JsonParser làm việc gần giống với cách phân tích XML của SAX. JsonParser không lưu trữ dữ liệu đọc được trên bộ nhớ.

Trên code của bạn gọi các phương thức next() để JsonParser phân tích phần tử tiếp theo Json, nó sẽ phát sự kiện mỗi khi phân tích xong một phần tử. Bộ phân tích này có thể phát ra các sự kiện sau:
  •  START_OBJECT
  • END_OBJECT
  • START_ARRAY
  • END_ARRAY
  • KEY_NAME
  • VALUE_STRING
  • VALUE_NUMBER
  • VALUE_TRUE
  • VALUE_FALSE
  • VALUE_NULL.
Dựa vào tên sự kiện phát ra, tên của phần tử phân tích được bạn có thể biết được bộ phân tích đang phân tích tới đoạn nào của dữ liệu, và lấy ra các giá trị tại đó. Các phương thức có thể sử dụng:
  • getString()
  • getInt()
  • ....
     
Xem ví dụ:
JsonParserExample.java
package org.o7planning.jsonptutorial;

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

import javax.json.Json;
import javax.json.stream.JsonParser;

import org.o7planning.jsonptutorial.beans.Address;
import org.o7planning.jsonptutorial.beans.Company;

public class JsonParserExample {

   public static void main(String[] args) throws IOException {
       InputStream inputStream = new FileInputStream("company.txt");

       JsonParser jsonParser = Json.createParser(inputStream);

       // Tạo các đối tượng, các trường của nó sẽ được sét đặt giá trị
       // mỗi khi tìm thấy giá trị trong các sự kiện.
       Company company = new Company();
       Address address = new Address();
       
       List<String> websitesList = new ArrayList<String>();
       
       // Key name của JSON.
       String keyName = null;
       
       while (jsonParser.hasNext()) {
           JsonParser.Event event = jsonParser.next();
           switch (event) {
           case KEY_NAME:
               keyName = jsonParser.getString();
               break;
           case VALUE_STRING:
               setStringValues(company, address, keyName, jsonParser.getString(), websitesList);
               break;
           case VALUE_NUMBER:
               setNumberValues(company, address, keyName, jsonParser.getInt());
               break;
           default:
               // No need..
           }
       }
       company.setAddress(address);
       String[] websites = new String[websitesList.size()];
       websitesList.toArray(websites);
       company.setWebsites(websites);

       // Print out
       // Ghi ra màn hình
       System.out.println(company);        
       inputStream.close();
       jsonParser.close();
   }

   private static void setNumberValues(Company company, Address address, String keyName, int value) {
       if (keyName.equals("id")) {
           company.setId(value);
       } else {
           System.out.println("Unknown Key:" + keyName);
       }
   }

   private static void setStringValues(Company company, Address address, String keyName, String value,
           List<String> websiteList) {
       if (keyName.equals("name")) {
           company.setName(value);
       } else if (keyName.equals("street")) {
           address.setStreet(value);
       } else if (keyName.equals("city")) {
           address.setCity(value);
       } else if (keyName.equals("websites")) {
           websiteList.add(value);
       } else {
           System.out.println("Unknown Key=" + keyName);
       }
   }

}
Chạy ví dụ: