当前位置: 首页 > 知识库问答 >
问题:

如何将JSON反序列化到接口?

江衡
2023-03-14

我很难将JSON反序列化到下面示例中实现基本接口的一些类ChildA、ChildB等。

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.PROPERTY,
        property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = InstagramUser.class, name = "ChildA")
})
public interface Basic {
    getName();
    getCount();
}

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeName("ChildA")
public class ChildA implements Basic { ... }

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeName("ChildB")
public class ChildB implements Basic { ... }
...

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class Response<E extends Basic> {
    @JsonProperty("data")
    private List<E> data;

    public List<E> getData() {
        return data;
    }

    public void setData(List<E> data) {
        this.data = data;
    }
}

// deserialization
HTTPClient.objectMapper.readValue(
    response, 
    (Class<Response<ChildA>>)(Class<?>) Response.class
)

异常是:com.fasterxml.jackson.databind.JsonMappingExc0019:意外令牌(END_OBJECT),预期FIELD_NAME:缺少包含类型id的属性type(对于类Basic)

预期的JSON如下所示:

{
    "data": [{ ... }, ...]
}

没有在所有类型对象中显示的属性,因此它们完全不同。但正如您在readValue行中看到的,我知道预期的类型。如何构造JsonTypeInfo和JsonSubTypes注释以按预期类反序列化JSON?

共有2个答案

姜玮
2023-03-14

我找不到确切的解决方案,但一个变通办法。我使用了自定义响应类ChildASolutions并将其传递给ObjectMapper.readValue()方法。

class ChildAResponse extends Response<ChildA> {}

// deserialization
HTTPClient.objectMapper.readValue(
    response, 
    ChildAResponse.class
)

因此,不再需要接口上的JsonTypeInfo和JsonSubTypes注释。

虞唯
2023-03-14

我有点像你一样的问题,基于这里的阅读:Jackson反序列化抽象类我创建了我自己的解决方案,它基本上包括创建我自己的反序列化程序,诀窍是使用/标识JSON中的特定属性来知道反序列化应返回哪种实例类型,示例如下:

public interface Basic {
}

第一个孩子:

public class ChildA implements Basic {
    private String propertyUniqueForThisClass;
    //constructor, getters and setters ommited
}

第二个孩子:

public class ChildB implements Basic {
    private String childBUniqueProperty;
    //constructor, getters and setters ommited
}

反序列化程序(BasicDeserializer.java)类似于:

public class BasicDeserializer extends StdDeserializer<Basic> {


    public BasicDeserializer() {
        this(null);
    }

    public BasicDeserializer(final Class<?> vc) {
        super(vc);
    }

    @Override
    public Basic deserialize(final JsonParser jsonParser,
                               final DeserializationContext deserializationContext)
            throws IOException {

        final JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        final ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec();

        // look for propertyUniqueForThisClass property to ensure the message is of type ChildA
        if (node.has("propertyUniqueForThisClass")) {
            return mapper.treeToValue(node, ChildA.class);
            // look for childBUniqueProperty property to ensure the message is of type ChildB
        } else if (node.has("childBUniqueProperty")) {
            return mapper.treeToValue(node, ChildB.class);
        } else {
            throw new UnsupportedOperationException(
                    "Not supported class type for Message implementation");
        }
    }
}

最后,您将拥有一个实用程序类(BasicUtils.java):

private static final ObjectMapper MAPPER;

// following good software practices, utils can not have constructors
private BasicUtils() {}

static {
    final SimpleModule module = new SimpleModule();
    MAPPER = new ObjectMapper();
    module.addDeserializer(Basic.class, new BasicDeserializer());
    MAPPER.registerModule(module);
}

public static String buildJSONFromMessage(final Basic message)
        throws JsonProcessingException {
    return MAPPER.writeValueAsString(message);
}

public static Basic buildMessageFromJSON(final String jsonMessage)
        throws IOException {
    return MAPPER.readValue(jsonMessage, Basic.class);
}

用于测试:

@Test
public void testJsonToChildA() throws IOException {
    String message = "{\"propertyUniqueForThisClass\": \"ChildAValue\"}";
    Basic basic = BasicUtils.buildMessageFromJSON(message);
    assertNotNull(basic);
    assertTrue(basic instanceof ChildA);
    System.out.println(basic);
}
@Test
public void testJsonToChildB() throws IOException {
    String message = "{\"childBUniqueProperty\": \"ChildBValue\"}";
    Basic basic = BasicUtils.buildMessageFromJSON(message);
    assertNotNull(basic);
    assertTrue(basic instanceof ChildB);
    System.out.println(basic);
}

源代码可以在:https://github.com/darkstar-mx/jsondeserializer

 类似资料:
  • 问题内容: 我很好奇序列化和反序列化的方式。我使用关键字“ json”和“ tuple”进行搜索,但找不到所需的内容。 问题答案: 我通过和Json.net进行测试,测试代码如下。结果显示可序列化和可反序列化。因此,我可以在应用程序中使用它们。 测试代码 注释 在将序列化到字符串{“项目1”:“一”,“项目2”:“嘻嘻”,“项目3”:真正},并且它可以被反序列化回类型。

  • 问题内容: 我正在尝试使用Northwind OData服务: http://services.odata.org/V3/OData/OData.svc/Products?$format=json 并将其反序列化为一系列产品: 但是序列化器似乎不喜欢该部分,并且事实是那里有2 条记录(不确定它们是什么)。 是否有捷径可寻? 问题答案: 使用Json.Net

  • 问题内容: 我正在使用大猩猩 websocket,并且正在计划使用json进行序列化/反序列化。 假设我有这样的结构来接收传入的消息: 和 大猩猩提供接收传入的消息。传入的消息可以是Foo或Bar,但是我不能使用和收听其他消息,这很混乱。我想要像javascript 这样的东西。如果接收到Foo,则如何处理传入消息,然后将其存储到结构中;如果接收到Bar,则将其存储到结构中? 我正在解决方案正在使

  • 我遇到了类似的问题:Kafka反序列化我的Kafka生产者中的嵌套泛型类型,我发送的对象如下所示: 其基石是:。 此界面如下所示: 添加字段@class是因为@JsonTypeInfo注释,我认为这足以让反序列化器“理解”在反序列化中使用什么类型的IExternalData。不幸的是,在Kafka的听众那边,我得到了一个例外: 无法构造的实例(不存在像default construct这样的创建者

  • 问题内容: 我只想要对象的第一个深度级别(我不需要任何子级)。我愿意使用任何可用的图书馆。大多数库仅在达到递归深度时才会抛出异常,而不仅仅是忽略。如果这不可能,是否有一种方法可以忽略给定特定数据类型的特定成员的序列化? 编辑:假设我有一个像这样的对象: 我想删除任何子级(甚至是复杂类型)以返回这样的对象: 问题答案: 在Json.NET中,可以使用和序列化程序之间的一些协调。 自定义在对象启动时增

  • 我们使用Google GSON反序列化JSON数据到Java对象。请参阅下面的示例JSON数据和相应的POJO类。我能够反序列化“name”和“phoneNumber”字段。但对于“Departments”字段,我看到NULL。您能帮助我如何反序列化“Departments”字段吗? 我的JSON: 类: customerDeserializer.java: