0

I have Json Book requests defined as

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

or

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

Value is a polymorphic object.

I defined my Java POJOs as below. I am defining value as polymorphic object.

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

Book is defined as

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

BookValue is defined as a polymorphic object.

public interface BookValue 
{
}

For which PrintBook is a type

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

Book type is defines as an enum

@Getter
public enum BookType
{
    EBOOK,
    PRINT
}

When I am trying to deserialize a PRINT book json with the below code

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

But, I am getting this error

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of jacksonannotations.books.BookValue (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: jacksonannotations.books.BookRequest$BookRequestBuilder["book"]->jacksonannotations.books.Book$BookBuilder["value"])

I already looked into Cannot construct instance of - Jackson, but that didn't help.

Can someone help me understand if I am modeling the Java pojos in the above example correctly?

Thanks, Pavan

Pavan_k_k
  • 309
  • 1
  • 5
  • 11

2 Answers2

0

From the error message, you can see that Jackson tries to construct an instance of BookValue. This fails, since BookValue is an interface.

So you need to tell Jackson how this polymorphism is supposed to be handled. This page gives a nice overview: https://www.baeldung.com/jackson-inheritance

You didn't provide details of your BookBuilder implementation. I assume it follows a regular builder pattern as an alternative to a constructor. Note that this does not help Jackson to determine which subclass to instantiate.

aeberhart
  • 744
  • 1
  • 4
  • 15
0

You could use unify-jdocs, a library which I created to read and write JSON documents without using any POJO objects. With respect to your problem, it would be as simple as writing the following lines of codes:

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

You could use a similar way to write to these paths as so:

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

This library offers a whole lot of other features which can be used to manipulate JSON documents. Features like model documents which lock the structure of documents to a template, field level validations, comparisons, merging documents etc.

Obviously, you would consider it only if you wanted to work without POJO objects. Alternatively, you could use it to read and write a POJO object using your own method.

Check it out on https://github.com/americanexpress/unify-jdocs.