1. 簡介
在本文中,我們將學習如何使用 Jackson 對 java.sql.Blob 進行序列化和反序列化。 java.sql.Blob 代表 Java 中的 Binary Large Object (Blob),它可以存儲大量的二進制數據。 在使用 Jackson 進行 JSON 序列化和反序列化時,處理 Blob 對象可能比較棘手,因為 Jackson 不直接支持它們。 但是,我們可以創建自定義序列化器和反序列器來處理 Blob 對象。
我們將從設置環境和簡單的示例開始。 稍後,我們將快速展示如何實現自定義序列化器和反序列器以處理 Blob 數據類型。 最後,我們將使用我們的簡單用例測試來驗證我們的方法。
2. 依賴與示例設置
首先,請確保我們已在 jackson-databind 中添加了必要的依賴:pom.xml 中應包含:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>我們接下來將演示如何在典型的POJO中集成Blob字段,並強調自定義序列化和反序列化的必要性。讓我們創建一個簡單的User POJO,其中包含ID, name, 和 profilePicture,其類型為Blob:。
public class User {
private int id;
private String name;
private Blob profilePicture;
//Constructor
// Getters and setters
}
我們稍後將使用這個 User 類來演示涉及 Blob 字段的自定義序列化和反序列化。
3. 定義 Blob 序列化器
以下定義一個序列化器,用於將 profilePicture 屬性從 User 對象轉換為 Base64 編碼的二進制字符串:
@JacksonStdImpl
public class SqlBlobSerializer extends JsonSerializer<Blob> {
@Override
public void serialize(Blob value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
try {
byte[] blobBytes = value.getBytes(1, (int) value.length());
gen.writeBinary(blobBytes);
} catch (Exception e) {
throw new IOException("Failed to serialize Blob", e);
}
}
}重要的是,@JacksonStdImpl 表示該類是 Jackson 可以使用的標準序列化器實現。它通常用於 Jackson 中的內置序列化器和反序列器。
我們的 SqlBlobSerializer 繼承了 JsonSerialzier<Blob>,這是一個 Jackson 提供的用於定義自定義序列化的泛型類。我們覆蓋了 `serialize` 方法,將要序列化的 Blob 對象以及 JsonGenerator 和 SerializerProvider 傳遞進去。 JsonGenerator 用於生成最終的 JSON 內容,而 SerializerProvider 用於提供用於序列化對象的序列化器。
本質上,serialize 方法使用 getBytes() 將 Blob 轉換為字節數組。然後,它使用 gen.writeBinary() 將字節數組寫入為 Base64 編碼的二進制字符串。
5. 定義 Blob 解序列化器
現在,我們將定義一個解序列化器,該解序列化器可以使用 Jackson 將 Base64 編碼的字符串轉換為 Blob:
@JacksonStdImpl
public class SqlBlobDeserializer extends JsonDeserializer<Blob> {
@Override
public Blob deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
try {
byte[] blobBytes = p.getBinaryValue();
return new SerialBlob(blobBytes);
} catch (Exception e) {
throw new IOException("Failed to deserialize Blob", e);
}
}
}這裏,SqlBlobDeserializer 繼承了 JsonDeserializer<Blob>,這是一個由 Jackson 提供的泛型類,用於定義自定義的反序列化器。我們隨後覆蓋了 JsonDeserializer 中的 `deserialize` 方法,傳入了 JsonParser,該解析器用於讀取 JSON 內容。 此外,我們還傳入了 DeserializationContext,該對象可用於訪問反序列化過程的信息。
本質上,SqlBlobDeserializer 通過 getBinaryValue() 從 JSON 中檢索二進制數據到 byte[] 中。 然後,它將字節數組轉換為一個 SerialBlob 對象,該對象是 java.sql.Blob 的實現。
6. 註冊自定義序列化器和反序列器
現在我們已經擁有一個 <em>BlobSerializer</em> 和 <em>BlobDeserializer</em>,下一步是使用 Jackson 註冊它們。<strong>使用 Jackson 註冊自定義序列化器和反序列器意味着配置 Jackson 的 <em>ObjectMapper</em>,以便使用特定類將某些 Java 對象轉換為 JSON 格式以及反向轉換</strong>。 讓我們創建一個SimpleModule,並將我們的blobSerializer和blobDeserializer` 添加到該模塊中:
SimpleModule module = new SimpleModule();
module.addSerializer(Blob.class, new SqlBlobSerializer());
module.addDeserializer(Blob.class, new SqlBlobDeserializer());接下來,讓我們創建一個 ObjectMapper,並將其註冊到其中:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);本質上,通過將特定模塊註冊到ObjectMapper中,我們確保它知道如何在 JSON 處理過程中處理非標準類型。在這種情況下,我們確保我們的 ObjectMapper 知道如何使用自定義序列化器和反序列器處理 Blob 類型。
7. 單元測試
最後,讓我們通過編寫單元測試來觀察我們的註冊序列化器和反序列器在實際中的表現。首先,讓我們測試 <em BlobSerializer </em>。
@Test
public void givenUserWithBlob_whenSerialize_thenCorrectJsonDataProduced() throws Exception {
User user = new User();
user.setId(1);
user.setName("Test User");
//sample blob data from byte[]
byte[] profilePictureData = "example data".getBytes();
Blob profilePictureBlob = new SerialBlob(profilePictureData);
user.setProfilePicture(profilePictureBlob);
String json = mapper.writeValueAsString(user);
String expectedJson = "{\"id\":1,\"name\":\"Test User\",\"profilePicture\":\"ZXhhbXBsZSBkYXRh\"}";
assertEquals(expectedJson, json);
}該測試驗證序列化的 JSON 字符串與預期 JSON 格式是否匹配。具體來説,JSON 中的 profilePicture 字段應為 base64 編碼的字符串,表示 Blob 數據。
接下來,我們為 BlobDeserializer 編寫一個測試。
@Test
public void givenUserJsonWithBlob_whenDeserialize_thenCorrectDataRecieved() throws Exception {
String json = "{\"id\":1,\"name\":\"Test User\",\"profilePicture\":\"ZXhhbXBsZSBkYXRh\"}";
User deserializedUser = mapper.readValue(json, User.class);
assertEquals(1, deserializedUser.getId());
assertEquals("John Doe", deserializedUser.getName());
byte[] expectedProfilePictureData = "example data".getBytes();
Blob deserializedProfilePictureBlob = deserializedUser.getProfilePicture();
byte[] deserializedData = deserializedProfilePictureBlob.getBytes(1, (int) deserializedProfilePictureBlob.length());
assertArrayEquals(expectedProfilePictureData, deserializedData);
}此處,Blob數據應與原始字節數據對應字符串“example data”。該測試確保自定義SqlBlobDeserialiser能夠將base64編碼的字符串正確轉換回Blob對象,並在User對象中保留原始二進制數據。
8. 結論
在本文中,我們演示瞭如何有效地使用 Jackson 庫在 Java 中序列化和反序列化 java.sql.Blob 對象的方法。我們創建了自定義的序列化器和反序列器,以處理 Blob 對象中的二進制數據,並將它們轉換為和從 JSON 格式中的 base64 編碼字符串。