将多态Json对象反序列化为POJO

时间:2020-08-13 02:41:47

标签: java json jackson polymorphism jackson-databind

我将Json Book请求定义为

{
  "book" : {
    "type" : "PRINT",
    "value" : {
      "weight" : "1lb"
    }
  }
}

{
  "book" : {
    "type" : "EBOOK",
    "value" : {
      "size" : "1MB"
    }
  }
}

值是一个多态对象。

我如下定义了Java POJO。我将value定义为多态对象。

@Getter
@Builder
@JsonDeserialize(builder = BookRequest.BookRequestBuilder.class)
public class BookRequest
{
    @NonNull
    private Book book;
}

书被定义为

@Builder
@Getter
@JsonDeserialize(builder = Book.BookBuilder.class)
public class Book
{
    @NonNull
    private BookType type;
    @NonNull
    private BookValue value;
}

BookValue被定义为多态对象。

public interface BookValue 
{
}

PrintBook是一种类型

@Getter
@Builder
@JsonDeserialize(builder = PrintBook.PrintBookBuilder.class)
public class PrintBook implements BookValue
{
    private String weight;
}

书籍类型定义为枚举

@Getter
public enum BookType
{
    EBOOK,
    PRINT
}

当我尝试使用以下代码反序列化PRINT book json时

public deserializePrintBook{
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

        try {
            JsonNode node = createJsonNodeFromFile("src/jacksonannotations/resources/sampleBook.json");

            BookRequest br = mapper.treeToValue(node, BookRequest.class);
            System.out.println(br);

        }
        catch (Exception e ) {
            e.printStackTrace();
        }
    }

 public static JsonNode createJsonNodeFromFile(final String filePath) throws Exception
    {
        ObjectMapper objectMapper = new ObjectMapper();
        File file = new File(filePath);

        JsonNode testMessageEnvelope = objectMapper.readValue(
            file,
            JsonNode.class);

        return testMessageEnvelope;
    }

但是,我收到此错误

com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法构造jacksonannotations.books.BookValue的实例(不存在创建者,例如默认构造函数):抽象类型要么需要映射到具体类型,要么具有自定义反序列化器,或包含其他类型信息 在[资料来源:未知;行:-1,列:-1](通过参考链:jacksonannotations.books.BookRequest $ BookRequestBuilder [“ book”]-> jacksonannotations.books.Book $ BookBuilder [“ value”])

我已经研究过Cannot construct instance of - Jackson,但这没有帮助。

有人可以帮助我了解我是否在上述示例中正确地对Java pojos建模?

谢谢, 帕万(Pavan)

2 个答案:

答案 0 :(得分:0)

从错误消息中,您可以看到Jackson试图构造BookValue的实例。由于BookValue是接口,因此失败。

因此,您需要告诉Jackson如何处理这种多态性。该页面提供了很好的概述: https://www.baeldung.com/jackson-inheritance

您没有提供BookBuilder实现的详细信息。我假设它遵循常规的构建器模式,以替代构造器。请注意,这无助于Jackson确定要实例化的子类。

答案 1 :(得分:0)

您可以使用unify-jdocs,这是我创建的用于在不使用任何POJO对象的情况下读写JSON文档的库。关于您的问题,这就像编写以下代码行一样简单:

Document d = new JDocument(s); // where s is a JSON string
String weight = d.getString("$.book.value.weight");
String size = d.getString("$.book.value.size");

您可以使用类似的方式这样写这些路径:

d.setString("$.book.value.weight", "1LB");
d.setString("$.book.value.size", "1MB");

此库提供了许多其他功能,可用于处理JSON文档。诸如将文档结构锁定到模板的模型文档,字段级验证,比较,合并文档等功能。

很显然,仅当您想在没有POJO对象的情况下工作时,才考虑使用它。另外,您也可以使用自己的方法使用它来读写POJO对象。

https://github.com/americanexpress/unify-jdocs上签出。

相关问题