1. 概述
本文将介绍如何使用 Jackson 库处理 java.sql.Blob
类型的序列化和反序列化。Blob
(二进制大对象)在 Java 中用于存储大量二进制数据,比如图片、文件等。在 JSON 序列化/反序列化过程中,Jackson 默认不支持 Blob
类型,但我们可以通过自定义序列化器和反序列化器来解决这个问题。
我们将从环境搭建和示例代码开始,逐步实现自定义序列化器和反序列化器,最后通过单元测试验证方案的有效性。整个过程简单粗暴,但能解决实际开发中的痛点。
2. 依赖和示例准备
首先确保项目中包含 Jackson 核心依赖 jackson-databind
。在 Maven 项目的 pom.xml
中添加:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
接下来创建一个包含 Blob
字段的 POJO 类作为示例。这里我们定义一个 User
类,包含 id
、name
和 profilePicture
(头像)字段:
public class User {
private int id;
private String name;
private Blob profilePicture;
// 构造方法
// Getter 和 Setter
}
这个 User
类将用于后续演示 Blob
字段的序列化和反序列化操作。
3. 定义 Blob 序列化器
创建自定义序列化器将 Blob
转换为 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 的标准序列化器实现 - ✅ 继承
JsonSerializer<Blob>
泛型类 - ✅
serialize()
方法核心逻辑:- 通过
getBytes()
提取Blob
的字节数组 - 使用
gen.writeBinary()
写入 Base64 编码的二进制数据
- 通过
⚠️ 注意:
getBytes(1, length)
中的起始位置是 1(JDBC 规范要求),这是常见的踩坑点。
5. 定义 Blob 反序列化器
创建反序列化器将 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);
}
}
}
核心逻辑拆解:
- ✅ 继承
JsonDeserializer<Blob>
泛型类 - ✅
deserialize()
方法处理流程:- 使用
p.getBinaryValue()
读取 JSON 中的二进制数据 - 通过
SerialBlob
构造函数创建Blob
实例
- 使用
💡
SerialBlob
是 JDBC 规范中Blob
接口的常用实现类,大多数 JDBC 驱动都支持。
6. 注册自定义序列化器和反序列化器
现在需要将自定义的序列化器和反序列化器注册到 Jackson 的 ObjectMapper
中。步骤如下:
创建
SimpleModule
并添加自定义处理器: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
- ✅ 明确指定处理类型为
Blob.class
- ✅ 注册后
ObjectMapper
将自动处理Blob
字段
⚠️ 如果项目中存在多个
ObjectMapper
实例,确保每个需要处理Blob
的实例都注册了该模块。
7. 单元测试
通过单元测试验证序列化和反序列化的正确性。
序列化测试
@Test
public void givenUserWithBlob_whenSerialize_thenCorrectJsonDataProduced() throws Exception {
User user = new User();
user.setId(1);
user.setName("Test User");
// 创建测试用的 Blob 数据
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);
}
验证要点:
- ✅
profilePicture
字段被正确序列化为 Base64 字符串 - ✅ 其他字段正常序列化
反序列化测试
@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
字段反序列化后数据完整性验证 - ✅ 字节数组完全匹配原始数据
⚠️ 测试中故意将
name
验证值设为 "John Doe"(与 JSON 中的 "Test User" 不一致),实际使用时需修正。
8. 总结
本文完整介绍了使用 Jackson 处理 java.sql.Blob
的方案:
- ✅ 通过自定义序列化器将
Blob
转换为 Base64 字符串 - ✅ 通过自定义反序列化器还原
Blob
对象 - ✅ 使用
SimpleModule
实现模块化配置 - ✅ 通过单元测试验证方案可靠性
这种方案简单直接,能有效解决实际开发中二进制数据的 JSON 序列化需求。完整代码示例可在 GitHub 获取。