1、简介 {#1简介}
本文将带你了解如何使用 Jackson 序列化和反序列化 java.sql.Blob
对象。
java.sql.Blob
表示 Java 中的二进制大对象(Binary Large Object,Blob),可以存储大量二进制数据。在使用 Jackson 处理 JSON 序列化和反序列化时,处理 Blob 对象可能比较棘手,因为 Jackson 并不直接支持它们。不过,我们可以创建自定义的序列化器(Serializer)和反序列化器(Deserializer)来处理 Blob
对象。
2、依赖和示例项目 {#2依赖和示例项目}
首先,在 pom.xml
中添加 jackson-databind 依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
然后,创建一个简单的 User
POJO,其中包含 id
、name
和 Blob
类型的 profilePicture
(图片数据):
public class User {
private int id;
private String name;
private Blob profilePicture;
// 构造函数,Getter/Setter 省略
}
3、定义 Blob 序列化器 {#3定义-blob-序列化器}
定义一个序列化器(Serializer),将 User
的 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("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 反序列化器 {#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>
,JsonDeserializer
是 Jackson
提供的用于定义自定义反序列化器的通用类。然后,覆写 JsonDeserializer
中的 deserialize
方法,并传递 JsonParser
(用于读取 JSON 内容的解析器)。
本质上,SqlBlobDeserializer
会使用 getBinaryValue()
从 JSON 中检索二进制数据并将其转换为 byte[]
。然后,它将字节数组转换为 SerialBlob
对象,该对象是 java.sql.Blob
的一个实现。
6、注册自定义序列化器和解序列化器 {#6注册自定义序列化器和解序列化器}
现在,有了 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
注册特定模块,可以确保 ObjectMapper
知道如何处理非 JSON 标准类型的对象,如本例中的 Blob
类型。
7、单元测试 {#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、总结 {#8总结}
本文介绍了如何使用 Jackson 库有效地序列化和反序列化 Java 中的 java.sql.Blob
对象,主要是通过创建自定义的序列化器和反序列化器来处理 Blob
对象中的二进制数据,并将它们转换为 JSON 格式的 base64 编码字符串。
Ref:https://www.baeldung.com/java-sql-blob-jackson-serialize-deserialize