使用 Jackson 序列化和反序列化 java.sql.Blob

banq發表於2024-06-14

在本文中,我們將瞭解如何使用 Jackson 序列化和反序列化java.sql.Blob。

java.sql.Blob表示Java中的二進位制大物件(Blob),它可以儲存大量二進位制資料。使用 Jackson 進行 JSON 序列化和反序列化時, 處理Blob物件可能很 棘手,因為 Jackson 不直接支援它們。但是,我們可以建立自定義序列化器和反序列化器來處理Blob 物件。

我們將從設定環境和一個簡單的示例開始。接下來,我們將快速展示如何實現自定義序列化程式並反序列化Blob資料型別。最後,我們將使用簡單的示例用例透過測試驗證我們的方法。

依賴項和示例設定
首先,讓我們確保我們的pom.xml中具有必要的jackson-databind 依賴項:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.3</version>
</dependency>

接下來,我們將演示如何在典型的 POJO 中整合Blob 欄位,重點介紹自定義序列化和反序列化的需求。讓我們建立一個簡單的User POJO,其中包含ID、name和Blob型別的 profilePicture :

public class User {
    private int id;
    private String name;
    private Blob profilePicture;
    <font>//Constructor <i>
   
// Getters and setters<i>
}

稍後我們將使用這個User類來演示涉及Blob欄位的自定義序列化和反序列化。

定義Blob序列化器
讓我們定義一個序列化器,將使用者的profilePicture屬性轉換為 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(<font>"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 編碼的二進位制字串

定義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(<font>"Failed to deserialize Blob", e);
        }
    }
}

這裡,SqlBlobDeserializer 擴充套件了JsonDeserializer<Blob>,這是 Jackson 提供的用於定義自定義反序列化器的通用類。然後,我們從JsonDeserializer中重寫反序列化方法,並傳遞JsonParser,它是用於讀取 JSON 內容的解析器。此外,我們傳遞了可用於訪問有關反序列化過程的資訊的DeserializationContext 。

本質上,SqlBlobDeserializer使用getBinaryValue()從 JSON 中檢索二進位制資料並將其放入byte[]中。 然後,它將位元組陣列轉換為SerialBlob 物件,該物件是 java.sql.Blob 的實現。

註冊自定義序列化器和反序列化器
現在我們有了BlobSerializer和BlobDeserializer,下一步就是將它們都註冊到 Jackson 中。使用 Jackson 註冊自定義序列化器和反序列化器意味著配置 Jackson ObjectMapper 以使用特定類將某些型別的 Java 物件轉換為 JSON 或從 JSON 轉換為 Java 物件。接下來讓我們建立一個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型別。

單元測試
最後,讓我們透過編寫一些單元測試來檢視我們註冊的序列化器和反序列化器的實際執行情況。我們先測試一下BlobSerializer :

@Test
public void givenUserWithBlob_whenSerialize_thenCorrectJsonDataProduced() throws Exception {
    User user = new User();
    user.setId(1);
    user.setName(<font>"Test User");
   
//sample blob data from byte[] <i>
    byte[] profilePictureData =
"example data".getBytes();
    Blob profilePictureBlob = new SerialBlob(profilePictureData);
    user.setProfilePicture(profilePictureBlob);
    String json = mapper.writeValueAsString(user);
    String expectedJson =
"{\&#34id\&#34:1,\&#34name\&#34:\&#34Test User\&#34,\&#34profilePicture\&#34:\&#34ZXhhbXBsZSBkYXRh\&#34}";
    assertEquals(expectedJson, json);
}

該測試驗證序列化的 JSON 字串是否符合預期的 JSON 格式。具體來說, JSON 中的profilePicture 欄位應為表示Blob 資料的 base64 編碼字串。

接下來我們來為BlobDeserializer編寫一個測試:

@Test
public void givenUserJsonWithBlob_whenDeserialize_thenCorrectDataRecieved() throws Exception {
    String json = <font>"{\&#34id\&#34:1,\&#34name\&#34:\&#34Test User\&#34,\&#34profilePicture\&#34:\&#34ZXhhbXBsZSBkYXRh\&#34}";
    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物件 內的原始二進位制資料。

相關文章