1. 背景
Jackson 是一個流行的 Java 庫,用於將 Java 對象序列化為 JSON 和反序列化為 JSON。在某些情況下,Java 對象可以被定義為具有泛型類型。
在本教程中,我們將演示如何使用 Jackson 將 JSON 字符串反序列化為泛型類型。
2. 模型準備
對於提供的JSON字符串進行反序列化:
{"result":{"id":1,"firstName":"John","lastName":"Lewis"}}
我們需要定義一個具有泛型類型參數和常規POJO對象來存儲數據:
public class JsonResponse<T> {
private T result;
// getters and setters...
}
public class User {
private Long id;
private String firstName;
private String lastName;
// getters and setters...
}
3. Deserialize Generic Type
在 Jackson 中,ObjectMapper 提供了三個用於 JSON 反序列化的 readValue 方法集,它們接受:
- Class<T> 作為參數,傳遞信息類型
- TypeReference,傳遞類型信息
- JavaType 作為參數
我們不能使用 JsonResponse<User>.class 傳遞給第一個 bullet point 中的方法,讓我們看看如何使用 TypeReference 和 JavaType 進行泛型反序列化。
3.1. TypeReference
如我們所知,Java 在編譯時擦除泛型類型信息,但我們可以利用匿名內部類來在編譯期間保留類型信息。 Jackson 提供了抽象類 TypeReference,用於從派生子類獲取類型信息:
public abstract class TypeReference<T> {
protected final Type _type;
protected TypeReference() {
Type superClass = this.getClass().getGenericSuperclass();
this._type = ((ParameterizedType)superClass).getActualTypeArguments()[0];
}
}
使用 TypeReference,我們可以按照以下方式創建匿名內部類用於泛型類型 JsonResponse<User>:
TypeReference<JsonResponse<User>> typeRef = new TypeReference<JsonResponse<User>>() {};
這種保留泛型類型信息的做法被稱為超類型標記。 通過使用超類型標記,Jackson 將知道容器類型是 JsonResponse 及其類型參數是 User。
這是反序列化的完整測試用例:
@Test
void givenJsonObject_whenDeserializeIntoGenericTypeByTypeReference_thenCorrect() throws JsonProcessingException {
String json = "{\"result\":{\"id\":1,\"firstName\":\"John\",\"lastName\":\"Lewis\"}}";
TypeReference<JsonResponse<User>> typeRef = new TypeReference<JsonResponse<User>>() {};
JsonResponse<User> jsonResponse = objectMapper.readValue(json, typeRef);
User user = jsonResponse.getResult();
assertThat(user.getId()).isEqualTo(1);
assertThat(user.getFirstName()).isEqualTo("John");
assertThat(user.getLastName()).isEqualTo("Lewis");
}
3.2. JavaType
如果類型參數 T 不是靜態的,則需要選擇 JavaType 而不是 TypeReference 來傳遞類型信息進行反序列化。 ObjectMapper 提供了此類方法,現在從 Jackson 2.5 開始推薦使用,並且我們可以使用 TypeFactory 來構造 JavaType 對象,其中包含我們的類型參數:
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(JsonResponse.class, User.class);
JsonResponse<User> jsonResponse = objectMapper.readValue(json, javaType);
這裏 User.class 作為第二個參數傳遞給 constructParametricType 方法,可以輕鬆地更改為其他參數化類型。
4. 結論
在本文中,我們介紹了兩種將 JSON 字符串反序列化為具有泛型類型的對象的簡單方法。