通过FasterXML-Jackson反序列化Code​​haus-Jackson注释的类实体?

时间:2019-04-14 09:56:20

标签: java jackson jackson-databind jackson2 fasterxml

我的应用程序有两个模块:API A 和可视化组件 V

某些API模型类通过org.codehaus.jackson.annotation进行注释(杰克逊1.9.13)。在一种逻辑流程中,基于这些模型的对象将进行JSON序列化,然后交付给 V

V 当前使用com.fasterxml.jackson.core.ObjectMapper(杰克逊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 的总体包装尺寸是一个主要问题;请切换为{{1 }}会将 A 的所有Jackson依赖项大小从980 KB增加到1.51 MB-这是不可接受的,因为完整的核心捆绑包(基于 A ;不包括 V )的大小目前不足8 MB。

1 个答案:

答案 0 :(得分:0)

您可以通过实现com.fasterxml.jackson.databind.AnnotationIntrospector类来自定义注释处理。例如,如果我们要允许在模型中使用org.codehaus.jackson.annotate.JsonCreator批注,则需要为其实现处理程序。在其他情况下,它将被忽略。简单的实现可能如下所示:

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;
    }
}

在使用org.codehaus.jackson.annotate.JsonCreator注释的情况下,我们只需启用DEFAULT模式。下面的代码显示了如何注册新的自省者:

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));
    }
}

上面的代码显示:

{"name":"Model1","size":"Extra Large"}
Model{name='Model1', size=XL}