1. 簡介
在處理 API 或配置文件時,JSON 通常是首選的數據交換格式。在 Java 中,<em >org.json</em> 庫提供了一種簡單的方法來解析和處理 JSON 數據。將 JSON 轉換為 Java POJO 至關重要,因為它使我們能夠使用類型化的對象而不是原始文本或映射,從而提高可讀性、可維護性和驗證能力。
在本教程中,我們將學習如何將 <em >JSONObject</em> 轉換為 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類
接下來,我們定義一個簡單的<em >User</em>類來表示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 包含一個嵌套的 地址 對象,反映了真實的 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 層次結構匹配時。
6.2. 集合 (Collections)
集合,如列表和數組,無需額外設置即可支持。例如,假設 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
}傑克遜會從JSON中讀取 full_name 字段並自動將其賦值給 name 屬性。 這種靈活性在與使用不同命名規範的API進行集成時非常有用。
傑克遜還支持多態反序列化,使其能夠處理表示基本類多個子類型的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)
);
傑克遜在第一條記錄中創建了一個 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 上找到:https://github.com/eugenp/tutorials/tree/master/json-modules/json-3。