Is it possible to de-serialize a card polymorphic in jackson?

I searched a lot and just find questions about polymorphic deserialization on the content inside the map. Is polymorphic deserialization of the card itself possible?

For example, I have a Book class containing Map as a member variable.

public class Book {
    @JsonProperty
    private Map<String, Object> reviews;

    @JsonCreator
    public Book(Map<String, Object> map) {
        this.reviews = map;
    }
}

Another class has a list of the class Book.

public class Shelf {

    @JsonProperty
    private List<Book> books = new LinkedList<>();

    public void setBooks(List<Book> books) {
        this.books = books;
    }

    public List<Book> getBooks() {
       return this.books;
    }
}

And a test class. One book review map is a Hashtable, and another book review map is a HashMap.

public class Test {

    private Shelf shelf;

    @BeforeClass
    public void init() {
        Map<String, Object> review1 = new Hashtable<>(); // Hashtable here
        review1.put("test1", "review1");
        Map<String, Object> review2 = new HashMap<>(); // HashMap here
        review2.put("test2", "review2");

        List<Book> books = new LinkedList<>();
        books.add(new Book(review1));
        books.add(new Book(review2));
        shelf = new Shelf();
        shelf.setBooks(books);
    }

    @Test
    public void test() throws IOException{
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
//        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        String json = mapper.writeValueAsString(shelf);
        System.out.println(json);

        Shelf sh = mapper.readValue(json, Shelf.class);
        for (Book b : sh.getBooks()) {
            System.out.println(b.getReviews().getClass());
        }
    }
}

Test output

{
  "name" : "TestShelf",
  "books" : [ {
    "reviews" : {
      "test1" : "review1"
    }
  }, {
    "reviews" : {
      "test2" : "review2"
    }
  } ]
}
class java.util.LinkedHashMap
class java.util.LinkedHashMap

Serialization works fine. But after deserialization, both overview1 and review2 are LinkedHashMap. I want review1 and review2 to be their real types, which are Hashtable for viewing1 and HashMap for viewing2. Is there any way to achieve this?

mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);, json json. , . .

+4
2

Jackson, TypeResolverBuilder ObjectMapper.

ObjectMapper.setDefaultTyping(...)

TypeResolverBuilder , .

public class MapTypeIdResolverBuilder extends StdTypeResolverBuilder {

    public MapTypeIdResolverBuilder() {
    }

    @Override
    public TypeDeserializer buildTypeDeserializer(DeserializationConfig config,
                                                  JavaType baseType, Collection<NamedType> subtypes) {
        return useForType(baseType) ? super.buildTypeDeserializer(config, baseType, subtypes) : null;
    }

    @Override
    public TypeSerializer buildTypeSerializer(SerializationConfig config,
                                              JavaType baseType, Collection<namedtype> subtypes) {
        return useForType(baseType) ? super.buildTypeSerializer(config, baseType, subtypes) : null;
    }

    /**
     * Method called to check if the default type handler should be
     * used for given type.
     * Note: "natural types" (String, Boolean, Integer, Double) will never
     * use typing; that is both due to them being concrete and final,
     * and since actual serializers and deserializers will also ignore any
     * attempts to enforce typing.
     */
    public boolean useForType(JavaType t) {
        return t.isMapLikeType() || t.isJavaLangObject();
    }
}

, TypeResolverBuilder. , , , . post .

+1

readValue , JSON. , Hashtable HashMap TreeMap Map. , , - , Shelf Book. , Book, , Map.

Map - . , Map, . LinkedHashMap. , .

,

private HashMap<String, Object> reviews;

, JSON HashMap. , .

. , Map. , . .

( , Hashtable .)

0

Source: https://habr.com/ru/post/1609095/


All Articles