將 org.json.JSONObject 對應到 POJO
1. 引言
在使用 API 或設定檔時,JSON 通常是首選的資料交換格式。在 Java 中, org.json函式庫提供了一種解析和處理 JSON 資料的簡單方法。將 JSON 轉換為 Java POJO 非常重要,因為它使我們能夠處理類型化的對象,而不是原始文字或映射,從而提高程式碼的可讀性、可維護性和驗證性。
在本教程中,我們將學習如何將JSONObject轉換為 Java POJO。我們將使用一個簡單的範例來理解整個過程,包括轉換 JSON 字串、處理巢狀物件以及驗證映射結果。
2. 項目設定
在開始之前,讓我們先在專案中包含org.json庫,以便方便地解析和處理 JSON 資料:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version>
</dependency>
這個函式庫提供了JSONObject和JSONArray類,使得在 Java 中建立、讀取和操作 JSON 變得更加容易。
3. 定義 POJO 類
接下來,我們定義一個簡單的User類別來表示 JSON 資料的結構。該類別作為目標對象,JSON 資料將被映射到該對象:
class User {
private String name;
private int age;
private String email;
private Address address;
// Getters and setters
}
class Address {
private String city;
private String postalCode;
// Getters and setters
}
這些類別反映了 JSON 資料的結構,使得在 JSON 和 Java 物件之間進行轉換變得非常簡單。
4. 建立範例JSONObject
現在,我們建立一個範例字串並將其轉換為JSONObject 。
假設範例中的 JSON 字串模擬了一個典型場景,即應用程式從 API 或設定檔接收 JSON 資料:
String jsonString = """
{
"name": "Alice",
"age": 25,
"email": "[email protected]",
"address": {
"city": "Singapore",
"postalCode": "123456"
}
}
""";
JSONObject jsonObject = new JSONObject(jsonString);
因此, JSON 包含一個巢狀的address對象,反映了真實的 JSON 結構。
準備好User POJO 和JSONObject後,可以透過多種方式將此 JSON 資料轉換為 Java 對象,既可以手動轉換,也可以透過 Jackson 等函式庫進行轉換。
5. 使用手動地圖
手動映射涉及從JSONObject中提取每個值並將其設定到 POJO 的相應欄位中。
為此,讓我們建立一個方法,手動將JSONObject對應到 POJO:
public static User mapManually(JSONObject jsonObject) {
User user = new User();
user.setName(jsonObject.getString("name"));
user.setAge(jsonObject.getInt("age"));
user.setEmail(jsonObject.getString("email"));
JSONObject addressObject = jsonObject.getJSONObject("address");
Address address = new Address();
address.setCity(addressObject.getString("city"));
address.setPostalCode(addressObject.getString("postalCode"));
user.setAddress(address);
return user;
}
這種方法清晰明了,易於理解。當 JSON 結構較小且穩定時,這種方法通常效果很好。每個欄位都進行了明確映射,從而可以進行自訂處理,例如預設值或轉換。
不過,從測試結果來看,手動映射確實包含了正確的值:
User user = mapManually(jsonObject);
assertEquals("Alice", user.getName());
assertEquals(25, user.getAge());
assertEquals("[email protected]", user.getEmail());
assertEquals("Singapore", user.getAddress().getCity());
assertEquals("123456", user.getAddress().getPostalCode());
然而,對於大型或嵌套很深的 JSON 結構,手動映射會變得重複且容易出錯。
6. 使用 Jackson
Jackson 是一個流行的庫,它可以自動將 JSON 字串映射到 POJO。
6.1 基礎知識
要使用 Jackson,我們需要新增對應的pom.xml依賴項:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.0</version>
</dependency>
將JSONObject轉換為 JSON 字串後,Jackson 透過一次方法呼叫即可處理映射:
public static User mapWithJackson(JSONObject jsonObject) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(jsonObject.toString(), User.class);
} catch (Exception e) {
return null;
}
}
Jackson 消除了手動映射所需的大部分樣板程式碼,並自動管理複雜的 JSON 結構。當 POJO 結構與 JSON 層次結構匹配時,它還可以對應到巢狀對象,例如address欄位。
6.2. 收藏
無需額外設定即可支援清單和數組等集合。例如,假設 JSON 中包含一個電話號碼陣列:
{
"name": "Alice",
"age": 25,
"email": "[email protected]",
"address": {
"city": "Singapore",
"postalCode": "123456"
},
"phones": ["12345678", "87654321"]
}
可以在User類別中新增對應的List<String>欄位:
private List<String> phones;
Jackson 會自動將phones陣列對應到 Java List 。這適用於 JSON 資料經常包含巢狀物件和陣列的 API。
6.3 客製化
此外, Jackson**也支援透過註解進行自訂**。例如,如果 JSON 欄位名稱與 Java 屬性名稱不同,則可以使用@JsonProperty註解定義對應關係:
class User {
@JsonProperty("full_name")
private String name;
private int age;
private String email;
// Getters and setters
}
Jackson 會從 JSON 讀取full_name字段,並自動將其賦值給name屬性。這種靈活性在與使用不同命名約定的 API 整合時非常有用。
Jackson 也支援多型反序列化,使其能夠處理表示基底類別多個子類型的 JSON。例如,考慮一個基底類Animal和兩個子類Dog和Cat :
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
abstract class Animal {
private String name;
// Getter and setter
}
class Dog extends Animal {
private int barkVolume;
// Getter and setter
}
class Cat extends Animal {
private boolean likesFish;
// Getter and setter
}
透過這種設置, Jackson 會根據 JSON 中的type字段自動確定要實例化的子類別:
[
{ "type": "dog", "name": "Buddy", "barkVolume": 5 },
{ "type": "cat", "name": "Mimi", "likesFish": true }
]
可以使用 Jackson 的ObjectMapper將 JSON 映射到正確的子類別:
ObjectMapper mapper = new ObjectMapper();
List<Animal> animals = Arrays.asList(
mapper.readValue(jsonArrayString, Animal[].class)
);
Jackson 為第一個條目建立了一個Dog對象,為第二個條目建立了一個Cat對象,沒有使用額外的邏輯。
6.4 驗證
我們可以驗證 Jackson 映射是否正常運作:
User user = mapWithJackson(jsonObject);
assertEquals("Alice", user.getName());
assertEquals("Singapore", user.getAddress().getCity());
assertEquals("123456", user.getAddress().getPostalCode());
assertEquals(2, user.getPhones().size());
assertEquals("12345678", user.getPhones().get(0));
assertEquals("87654321", user.getPhones().get(1));
這些斷言驗證了映射關係。
7. 使用 Gson
Gson 是另一個用於將 JSON 對應到 Java 物件的流行函式庫。在使用之前,我們需要在pom.xml檔案中新增 Gson 依賴項:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
Gson 解析 JSON 字串並填入 POJO 的字段,包括巢狀物件和集合,無需額外配置。
因此,我們可以建立一個簡單的方法將JSONObject映射到User類別:
public static User mapWithGson(JSONObject jsonObject) {
Gson gson = new Gson();
return gson.fromJson(jsonObject.toString(), User.class);
}
我們使用斷言來驗證 Gson 映射是否正常運作:
User user = mapWithGson(jsonObject);
assertEquals("Alice", user.getName());
assertEquals(25, user.getAge());
assertEquals("Singapore", user.getAddress().getCity());
assertEquals(2, user.getPhones().size());
Gson 輕量且易於使用,適合快速轉換或小型應用程式。當我們需要簡單的 JSON 到 POJO 映射而無需額外配置時,它非常實用。
8. 結論
本文探討了使用手動映射、Jackson 和 Gson 將JSONObject轉換為 Java POJO 的幾種方法。手動映射提供了完全的控制權,適用於簡單的 JSON 結構;Jackson 提供了強大而靈活的選擇,支援註解和多態處理;Gson 則為輕量級用例提供了簡潔性。
和往常一樣,原始碼可以在 GitHub 上找到。