基于ObjectMapper装饰器的抽象层:如何实现泛型类型反序列化?
泛型反序列化的抽象层设计问题
我对ObjectMapper做了装饰,实现了一层抽象层来避免直接耦合ObjectMapper,相关代码如下:
class ClientServerCommunicator { private static final Serializer serializer = new JacksonSerializer(); // more code }
public interface Serializer { String serialize(Object object); <T> T deserialize(String serializedObject, Class<T> clazz); }
public class JacksonSerializer implements Serializer { private final ObjectMapper objectMapper = new ObjectMapper(); @Override @SneakyThrows public String serialize(Object object) { return objectMapper.writeValueAsString(object); } @Override @SneakyThrows public <T> T deserialize(String serializedObject, Class<T> clazz) { return objectMapper.readValue(serializedObject, clazz); } @SneakyThrows // 接口中没有定义这个方法! public <T> T deserialize(String serializedObject, TypeReference<T> typeReference) { return objectMapper.readValue(serializedObject, typeReference); } }
但处理泛型类型反序列化时,我不确定该如何在接口中定义相关方法。目前只能通过强制转换为JacksonSerializer来调用泛型反序列化方法:
ServerSocketMessage<ChatAuthentication> serverResponse = ((JacksonSerializer) serializer).deserialize(line, new TypeReference<>() { });
这种方式在更换其他序列化库时会失效。请问是否需要为TypeReference添加额外的抽象层?若其他库的处理方式不同(无需传入此类泛型占位类)该如何处理?寻求相关设计建议。
解决方案思路
1. 基于Java原生Type的极简方案
直接复用Java原生的Type作为泛型反序列化方法的参数,这是所有序列化库都兼容的底层类型,无需额外抽象:
修改Serializer接口,新增泛型反序列化方法:
public interface Serializer { String serialize(Object object); <T> T deserialize(String serializedObject, Class<T> clazz); <T> T deserialize(String serializedObject, Type type); }
更新Jackson实现:
public class JacksonSerializer implements Serializer { private final ObjectMapper objectMapper = new ObjectMapper(); // 原有serialize、Class参数的deserialize方法不变... @Override @SneakyThrows public <T> T deserialize(String serializedObject, Type type) { return objectMapper.readValue(serializedObject, objectMapper.getTypeFactory().constructType(type)); } }
调用时通过TypeReference获取Type(也可以用Gson的TypeToken或其他方式生成Type):
Type type = new TypeReference<ServerSocketMessage<ChatAuthentication>>() {}.getType(); ServerSocketMessage<ChatAuthentication> serverResponse = serializer.deserialize(line, type);
如果更换为Gson,实现起来同样简单:
public class GsonSerializer implements Serializer { private final Gson gson = new Gson(); // 实现serialize、Class参数的deserialize方法... @Override public <T> T deserialize(String serializedObject, Type type) { return gson.fromJson(serializedObject, type); } }
2. 自定义抽象TypeToken的解耦方案
如果希望完全隔离第三方库的类型API,可以自定义一个抽象的TypeToken接口:
- 定义通用
TypeToken接口
public interface TypeToken<T> {}
- 修改
Serializer接口
public interface Serializer { String serialize(Object object); <T> T deserialize(String serializedObject, Class<T> clazz); <T> T deserialize(String serializedObject, TypeToken<T> typeToken); }
- 为Jackson实现适配类
public class JacksonTypeToken<T> implements TypeToken<T> { private final TypeReference<T> typeReference; public JacksonTypeToken(TypeReference<T> typeReference) { this.typeReference = typeReference; } // 仅给JacksonSerializer内部访问的方法 public TypeReference<T> getTypeReference() { return typeReference; } }
- 更新JacksonSerializer实现
public class JacksonSerializer implements Serializer { private final ObjectMapper objectMapper = new ObjectMapper(); // 原有方法不变... @Override @SneakyThrows public <T> T deserialize(String serializedObject, TypeToken<T> typeToken) { if (!(typeToken instanceof JacksonTypeToken)) { throw new IllegalArgumentException("JacksonSerializer仅支持JacksonTypeToken"); } return objectMapper.readValue(serializedObject, ((JacksonTypeToken<T>) typeToken).getTypeReference()); } }
调用时使用抽象TypeToken:
TypeToken<ServerSocketMessage<ChatAuthentication>> typeToken = new JacksonTypeToken<>(new TypeReference<>() {}); ServerSocketMessage<ChatAuthentication> serverResponse = serializer.deserialize(line, typeToken);
更换为其他库时,只需要实现对应的TypeToken子类和Serializer即可,比如Gson的GsonTypeToken和GsonSerializer,完全隔离不同库的API差异。
3. 推荐选型建议
- 如果项目中序列化库切换频率低,优先选方案1:代码简洁,无需额外抽象,利用Java原生API即可满足需求。
- 如果需要严格隔离第三方库依赖、保证未来切换序列化库时的零侵入,选方案2:通过自定义抽象层完全解耦,代价是多一层代码封装。
内容的提问来源于stack exchange,提问作者Sergey Zolotarev
相关产品推荐
相关产品推荐

