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

1、简介

本文将带你了解如何使用 Jackson 序列化和反序列化 java.sql.Blob 对象。

java.sql.Blob 表示 Java 中的二进制大对象(Binary Large Object,Blob),可以存储大量二进制数据。在使用 Jackson 处理 JSON 序列化和反序列化时,处理 Blob 对象可能比较棘手,因为 Jackson 并不直接支持它们。不过,我们可以创建自定义的序列化器(Serializer)和反序列化器(Deserializer)来处理 Blob 对象。

2、依赖和示例项目

首先,在 pom.xml 中添加 jackson-databind 依赖:

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

然后,创建一个简单的 User POJO,其中包含 idnameBlob 类型的 profilePicture(图片数据):

public class User {
    private int id;
    private String name;
    private Blob profilePicture;
    // 构造函数,Getter/Setter 省略
}

3、定义 Blob 序列化器

定义一个序列化器(Serializer),将 UserprofilePicture 属性转换为 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 对象以及 JsonGeneratorSerializerProviderJsonGenerator 用于生成 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>JsonDeserializerJackson 提供的用于定义自定义反序列化器的通用类。然后,覆写 JsonDeserializer 中的 deserialize 方法,并传递 JsonParser(用于读取 JSON 内容的解析器)。

本质上,SqlBlobDeserializer 会使用 getBinaryValue() 从 JSON 中检索二进制数据并将其转换为 byte[]。然后,它将字节数组转换为 SerialBlob 对象,该对象是 java.sql.Blob 的一个实现。

6、注册自定义序列化器和解序列化器

现在,有了 BlobSerializerBlobDeserializer 后,下一步就是将它们注册到 Jackson 中。向 Jackson 注册自定义序列化器和反序列化器意味着要配置 Jackson ObjectMapper,使其将特定类型的 Java 对象转换为 JSON 或从 JSON 转换为 Java 对象。

接下来,创建一个 SimpleModule,并将 blobSerializerblobDeserializer 添加到该模块中:

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 注册特定模块,可以确保 ObjectMapper 知道如何处理非 JSON 标准类型的对象,如本例中的 Blob 类型。

7、单元测试

先测试 BlobSerializer

@Test
public void givenUserWithBlob_whenSerialize_thenCorrectJsonDataProduced() throws Exception {
    User user = new User();
    user.setId(1);
    user.setName("Test User");
    // 简单的示例数据
    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 字段应是一个表示 Blob 数据的 base64 编码字符串。

最后,测试 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 编码字符串。


Ref:https://www.baeldung.com/java-sql-blob-jackson-serialize-deserialize