java – 使用类型信息优雅地忽略Jackson JSON反序列化中的未知类?

使用jackson JSON库,我能够生成带有类型字段信息的JSON并将其读回.但是,我的JSON对象的某些客户端可能无法访问特定的类.我希望他们将JSON属性序列化为Map.这似乎不起作用,如下面的代码所示.怎么做这招?

static class Foo {
    @JsonProperty
    private String x;
    @JsonProperty
    @JsonTypeInfo(use= JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
    private Object o;

    public String getX() {
        return x;
    }

    public void setX(String x) {
        this.x = x;
    }

    public Object getO() {
        return o;
    }

    public void setO(Object o) {
        this.o = o;
    }
}

@Test
public void testJacksonTypedSerialization() throws Exception {
    Foo foo = new Foo();
    foo.setX("hello world!");
    Foo foo2 = new Foo();
    foo2.setX("inner");
    foo.setO(foo2);

    ObjectMapper mapper = new ObjectMapper();

    String str = mapper.writeValueAsString(foo);
    System.out.println("foo is written as " + str);
    assertTrue(str.contains("Foo"));
    assertTrue(str.contains("@class"));

    Foo read = mapper.readValue(str, Foo.class);
    assertEquals(read.getX(), foo.getX());
    assertNotNull(read.getO());
    assertTrue(read.getO() instanceof Foo);

    String str2 = str.replace("Foo", "NoSuchType");
    Foo read2 = mapper.readValue(str2, Foo.class);
    assertEquals(read2.getX(), foo.getX());
    assertNotNull(read2.getO());
    // in this case, I want Jackson to read 'o' as Java Map/List
    assertTrue(read.getO() instanceof Map);
    // !!! encountered error
    //com.fasterxml.jackson.databind.JsonMappingException: Invalid type id 'com.mycorp.NoSuchType' (for id type 'Id.class'): no such class found
}
最佳答案
好吧,我认为随着你付出更多的努力,你可以逐渐获得更接近的解决方案.理论上,你应该能够编写一个自定义类型的解析器,如果该类不存在则返回unknown(默认的Id.CLASS解析器从不这样做) .不过,当我尝试时,这很快变成了比我有时间深入的东西.

更简单的解决方案是配置标准名称解析器(可以返回“type unknown”)并指定defaultImpl.就像是:

    @JsonProperty
    @JsonTypeInfo(defaultImpl=JsonNode.class, use= JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
    @JsonSubTypes({ @JsonSubTypes.Type(name="foo-type", value=Foo.class) })
    public Object o;

我发现的一件事是你将defaultImpl指定为Map,然后它不会像地图一样序列化,而是尝试将Map类视为bean(因此找不到属性).您可以保留JsonNode或使用对象映射器将其正确转换为Map.

我真的不确定那种交换是否可行 – 一旦你在类型层次结构中进行反序列化,你可能已经承诺反序列化为bean?在这种情况下,您将进入自定义反序列化器领域.

我调整了一下测试,以便在’o’上传递这些注释:

@Test
public void testJacksonTypedSerialization() throws Exception {
    Foo foo = new Foo();
    foo.setX("hello world!");
    Foo foo2 = new Foo();
    foo2.setX("inner");
    foo.setO(foo2);

    String str = mapper.writeValueAsString(foo);
    System.out.println("foo is written as " + str);
    assertThat(str, both(containsString("foo-type")).and(containsString("@type")));

    Foo read = mapper.readValue(str, Foo.class);
    assertThat(read.getX(), equalTo(foo.getX()));
    assertThat(read.getO(), instanceOf(Foo.class));

    String str2 = str.replace("foo-type", "NoSuchType");
    Foo read2 = mapper.readValue(str2, Foo.class);
    assertThat(read2.getX(), equalTo(foo.getX()));
    assertThat(read2.getO(), instanceOf(ObjectNode.class));
}

转载注明原文:java – 使用类型信息优雅地忽略Jackson JSON反序列化中的未知类? - 代码日志