java - 通过 FasterXML-Jackson 反序列化 Codehaus-Jackson 注释的类实体?
问题描述
我的应用程序有两个模块:一个 API A和一个可视化组件V。
一些 API 模型类通过org.codehaus.jackson.annotation
(Jackson 1.9.13) 进行注释。在一个逻辑流程中,基于这些模型的对象被 JSON 序列化并交付给V。
V目前使用com.fasterxml.jackson.core.ObjectMapper
(Jackson 2.9.1) 来反序列化接收到的对象。(V确实有A作为依赖项,因此 Jackson 1.9.13 也可传递地存在于类路径中。)
由于 Jackson 2.9.1 试图将数据反序列化为 Jackson 1.9.13 带注释的类,因此自定义枚举名称映射等某些功能不起作用。例如:
enum Size {
XL("Extra Large"),
L("Large"),
M("Medium"),
S("Small"),
XS("Extra Small");
private String name;
Size(String name) {
this.name = name;
}
public String getName() {
return name;
}
@org.codehaus.jackson.annotate.JsonCreator
public static Size forValue(String value) {
for (Size size : Size.values()) {
if (size.getName().equals(value)) {
return size;
}
}
return null;
}
}
class Model {
String name;
Size size;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSize() {
return size.getName();
}
public void setSize(Size size) {
this.size = size;
}
}
V无法反序列化上述Model
类中的对象,出现以下错误:
com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `Size` from String "Medium": value not one of declared Enum instance names: [S, XL, M, XS, L]
at [Source: (String)"{"name":"foo","size":"Medium"}"; line: 1, column: 22] (through reference chain: Model["size"])
这一切都说得通(因为从 1.9.13 到 2.9.1 是向后不兼容的更改),但我有什么选择呢?我是否必须将V的反序列化逻辑降级为 Jackson 1.9.13?或者,是否有任何“适配器”或配置可以“插入”以使 1.9.13 注释在 2.9.1 下工作?
(此时我宁愿不将A升级到 2.9.1,因为A的整体包大小是一个主要问题;切换到A的整体 Jackson 依赖项大小将从 980 KB 增加到 1.51 MB - 不可接受,因为com.fasterxml.jackson.core:jackson-databind
完整核心捆绑包(基于A;不包括V)目前的大小远低于 8 MB。)
解决方案
You can customise annotation handling by implementing com.fasterxml.jackson.databind.AnnotationIntrospector
class. For example, if we want to allow to use org.codehaus.jackson.annotate.JsonCreator
annotation in our model we need to implement handler for it. In other case it will be ignored. Simple implementation could look like below:
class CodehausAnnotationIntrospector extends JacksonAnnotationIntrospector {
@Override
public JsonCreator.Mode findCreatorAnnotation(MapperConfig<?> config, Annotated a) {
JsonCreator.Mode mode = super.findCreatorAnnotation(config, a);
if (mode != null) {
return mode;
}
org.codehaus.jackson.annotate.JsonCreator ann = _findAnnotation(a, org.codehaus.jackson.annotate.JsonCreator.class);
if (ann != null) {
return JsonCreator.Mode.DEFAULT;
}
return null;
}
}
We just simply enable DEFAULT mode in case org.codehaus.jackson.annotate.JsonCreator
annotation is used. Below code shows how to register new introspector:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new CodehausAnnotationIntrospector());
Model model = new Model();
model.setName("Model1");
model.setSize(Size.XL);
String json = mapper.writeValueAsString(model);
System.out.println(json);
System.out.println(mapper.readValue(json, Model.class));
}
}
Above code prints:
{"name":"Model1","size":"Extra Large"}
Model{name='Model1', size=XL}
推荐阅读
- r - 根据另一列的值分配给一列的非循环方式
- r - 单变量和多变量正态图/图表不显示
- c# - 如何从设置对话框访问复选框状态
- html - 如何将 Json 内容类型作为 HTML 标头
- objective-c - 如何将 NSError.code 与 Swift 5 中的#defined 错误号进行比较
- powershell - 比较本地文本文件和在线文件
- c# - 尝试通过 FindObjectByType 获取集合时找不到对象集合
- java - 如何获取我的应用程序以日志记录格式运行的端口号?
- c++ - 从保存 double 和 string 的二进制文件中读取
- reactjs - 运行所有测试后开玩笑不停止