Jackson:Map键反序列化能否获取对象类型?是否有替代KeyDeserializer的类?
Map键反序列化相关问题解答
问题背景代码
1. Map字段定义
@JsonDeserialize(keyUsing = DomainInstanceDeserializer.class, contentUsing = FactDeserializer.class) private final Map<DomainInstance, Fact> facts;
2. DomainInstanceDeserializer 代码片段
public class DomainInstanceDeserializer extends KeyDeserializer { // ... 省略其他代码 @Override public Object deserializeKey(String domainInstanceAsString, DeserializationContext deserializationContext) { // ... 反序列化逻辑 } }
3. FactDeserializer 代码片段
public class FactDeserializer extends JsonDeserializer<Fact> { // ... 省略其他代码 @Override public Fact deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { ObjectCodec oc = jsonParser.getCodec(); JsonNode node = oc.readTree(jsonParser); JsonNodeType nodeType = node.getNodeType(); switch (nodeType) { // 根据节点类型处理不同的Fact子类 } } }
问题
可以看到,针对Fact我们可通过节点的对象类型判断其具体类型。那么针对作为Map键的DomainInstance,能否实现同样操作?我们使用keyUsing注解指定了KeyDeserializer类,是否还有其他类可用于Map的键反序列化?
解答
1. DomainInstance无法像Fact那样通过节点类型判断具体类型
这是由JSON的规范决定的:JSON中Map的键只能是字符串类型,不管你序列化时用的是什么对象类型,最终都会被序列化为字符串格式。因此在KeyDeserializer的deserializeKey方法中,你只能拿到字符串形式的键值,无法获取到JsonNode来判断节点类型。
如果要实现类似的多类型区分,只能在键的字符串中嵌入类型标识——比如采用[类型标识]:[实际值]的格式,然后在deserializeKey方法里解析这个字符串,根据类型标识创建对应的DomainInstance子类实例。
2. 除KeyDeserializer外的Map键反序列化方式
没有专门替代KeyDeserializer的类,但有两种更简洁的处理方式:
- 给DomainInstance添加@JsonCreator注解:在
DomainInstance类中定义一个接受字符串参数的构造方法或静态工厂方法,并标记@JsonCreator注解。Jackson会自动调用这个方法,将键字符串转换为DomainInstance对象,无需自定义KeyDeserializer。 - 通过Module注册全局KeyDeserializer:创建一个Jackson的
Module,在其中为DomainInstance类型绑定默认的KeyDeserializer并注册到ObjectMapper中。这样所有使用DomainInstance作为Map键的场景都会自动使用这个反序列化器,不用逐个字段添加@JsonDeserialize(keyUsing = ...)注解。
内容的提问来源于stack exchange,提问作者Andrei Mihuț
相关产品推荐
相关产品推荐

