Jackson 不修改父类而实现多态解析

前言

众所周知 jackson 可以如下进行多态处理

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes(value = {
        @JsonSubTypes.Type(value = FirstChild.class, name = "first-child"),
        @JsonSubTypes.Type(value = SecondChild.class, name = "second-child"),
})
public interface Parent {
}

@Data
public static class FirstChild implements Parent {
    private String foo;
}

@Data
public static class SecondChild implements Parent {
    private String bar;
}

序列化时 jackson 会读取 @JsonSubTypes 的属性, 最终输出如:

{
    "type": "first-child",
    "foo": "hello, world"
}

反序列化时 jackson 通过 JSON 中的 "type" 属性知道该使用哪一个子类.

问题

当新增一个子类型时, 必须修改父类型的 @JsonSubTypes 注解, 否则不生效

首先是 不够优雅,

更严重的是 如果父类是外部依赖, 我们根本不能修改, 怎么办?

这个问题在 GitHub 中也有讨论, 不过最终没有下文.

解决方案

既然没有现成的方案, 而且 Jackson 的模块化做的很好, 不如自己造个轮子, 其实实际很简单: 通过 SPI 把子类注册进 Jackson 就行. 当然不一定是 SPI, 也可以是 classgraph 等.

今天就厚着脸皮分享一下自己造的轮子: jackson-modules-dynamic-subtype

以最简方式演示:

<dependency>
    <groupId>io.github.black-06.jackson</groupId>
    <artifactId>jackson-modules-dynamic-subtype</artifactId>
    <version>2.14.0</version>
</dependency>
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
public interface Parent {
}

@Data
@AutoService(Parent.class)
@JsonSubType("first-child")
public static class FirstChild implements Parent {
    private String foo;
}
  • 父类上的 @JsonTypeInfo 仍必须有

  • @JsonSubType 是轮子里头发明的, 与 @JsonSubTypes 的区别是, 它注解在子类型上.

然后注册模块:

PS. 在 Spring Boot 中它会自动注册, 可以跳过这一步

import io.github.black.jackson.DynamicSubtypeModule;

ObjectMapper mapper = new ObjectMapper().registerModule(new DynamicSubtypeModule());

简简单单.

其他:

  • 轮子里面的 ServiceLoad 是我根据 JDK 8 重写的, 只返回 Class 而不返回 Instance. 如果它工作的不是很正常, 考虑调用 module.setUseStandardServiceLoader(true) 使用标准库的 Loader.

  • 如果你不喜欢 SPI, 可以自行想办法获取所有字类, 并手动调用 module.registerTypes 将其注册进去.

最后, 如果这个轮子帮到了你, 求一个 star~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值