使用 Jackson 对 JSON 字段进行自定义反序列化

Custom deserialisation of JSON field using Jackson

我正在使用 Jackson 反序列化某些 JSON,但我 运行 在尝试对其中一个字段使用自定义反序列化程序时遇到了一些麻烦。

class MyClass
{
    private static class SpecialPropertyDeserializer extends JsonDeserializer<SpecialProperty>
    {
        @Override
        public SpecialProperty deserialize(JsonParser jsonParser,
                                           DeserializationContext deserializationContext) throws IOException, JsonProcessingException
        {
            // do some custom deserialisation
        }
    }

    private static class SpecialProperty
    {
        private String m_foo;

        private String m_bar;

        @JsonCreator
        SpecialProperty(@JsonProperty("foo") String foo,
                        @JsonProperty("bar") String bar)
        {
            m_foo = foo;
            m_bar = bar;
        }
    }

    private String m_identifier;

    private String m_version;

    @JsonDeserialize(using = SpecialPropertyDeseializer.class)
    private SpecialProperty m_specialProperty;

    @JsonCreator
    MyClass(@JsonProperty("identifier") String identifier,
            @JsonProperty("version") String version,
            @JsonProperty("specialProperty") SpecialProperty specialProperty)
    {
        m_identifier = identifier;
        m_version = version;
        m_specialProperty = specialProperty;
    }
}

这是我要反序列化的JSON:

{
    "identifier" : "some-id",
    "version"    : "1.7",
    "specialProperty"    : {
        "foo" : "str1",
        "bar" : "str2"
    },
}

我调用映射器如下:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);   
return objectMapper.readValue(input, MyClass.class);

我观察到以下行为:

  1. 没有特殊的 属性 一切正常 - 即删除所有 从代码和 JSON.
  2. 中引用 SpecialProperty
  3. 如果我在 JSON 中包含 SpecialProperty 但删除自定义 它的反序列化器然后它也可以正常工作。的ctor SpecialProperty 被调用。
  4. 自定义解串器不起作用。调用了 SpecialProperty 的构造函数,但未调用自定义反序列化器。

我做错了什么?

@JsonDeserialize 注释可以放在字段上,setter 或 class。如果注释的是它用来设置值的内容,杰克逊将考虑它。

E.g.1 如果它使用 setter 来设置字段的值,它会注意到 @JsonDeserialize 而不是 setter。

E.g.2 如果不使用 setter 或构造函数直接设置该字段,它将注意到该字段 @JsonDeserialize

如果它在 class 上,它将倾向于考虑它,除非它被字段上更具体的注释或 setter docs 覆盖。我认为文档在上述细节上可能会更清楚。

在你的例子中,你在 SpecialProperty 字段上有注释,但你在 MyClass 构造函数中设置了这个字段,所以它被忽略了。

在这种情况下,您可以将 @JsonDeserialize 移动到 class 上,而不是移动到字段上。在您的情况下,这可能是最简单的解决方案。例如

@JsonDeserialize(using = MyClass.SpecialPropertyDeserializer.class)
private static class SpecialProperty {

或者您可以完全跳过注释并在映射器上注册反序列化器。首先在 MyClass 中使 SpecialPropertySpecialPropertyDeserializer 非私有,然后:

ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(MyClass.SpecialProperty.class, new MyClass.SpecialPropertyDeserializer());
objectMapper.registerModule(module);

您也可以删除 MyClass 的构造函数,并且将考虑 SpecialProperty 字段上的当前注释。