重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
众所周知 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
以最简方式演示:
io.github.black-06.jackson jackson-modules-dynamic-subtype2.14.0
@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 仍必须有
@AutoService 注解是谷歌 auto 的, 用来自动生成 SPI 所需的 META-INF/services/package.Parent 文件, 具体可见 auto/service at main · google/auto (github.com)
@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~
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧