Daniil
Daniil

Reputation: 86

Jackson deserialize inner collection

I have an issue with deserialization of inner collection: Imagine there are two classes:

// RootClass.java
package somepackage;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.util.ArrayList;
import java.util.List;

class RootClass {
    public List getItems() {
        return items;
    }

    public void setItems(List items) {
        this.items = items;
    }

    @JsonSerialize(contentAs = Item.class)
    List<Item> items = new ArrayList<>();
}

//Item.java
package somepackage;

class Item {
    String name;

    public Item() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Item(String cat) {
        name = cat;
    }
}

// main class
package somepackage;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

public class SampleCase {
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        RootClass root = new RootClass();
        root.items.add(new Item("cat"));
        String json = mapper.writeValueAsString(root);
        RootClass root2 = mapper.readValue(json, RootClass.class);
        Item item = (Item) root2.items.get(0);
    }
}

I get an exception:

Exception in thread "main" java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class somepackage.Item (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; somepackage.Item is in unnamed module of loader 'app')

According to javadoc @JsonSerialize(contentAs = Item.class) on the collection would have help me, but it wouldn't. The question is: What am i missing?

If it is not about this annotation i suspect there is a standard way to deal with the problem (i do not want to create custom deserializers).

Most questions on collection deserialization are about situation when root object is a collection itself, but this is not the case for me.

jackson 2.9.8 java 11.0.2 OpenJDK x64

Upvotes: 2

Views: 1430

Answers (1)

CryptoFool
CryptoFool

Reputation: 23129

There's nothing wrong with the basic form of your code. What you're trying to do will work. You just have problems with your code, starting with the fact that it won't even compile since you call a constructor on Item that takes a String, and yet you define no such constructor. You also need getters for Jackson to work with.

Here's a version of your code that works:

class RootClass {
    List<Item> items = new ArrayList<>();
    public List<Item> getItems() {
        return items;
    }
}

class Item {
    String name;
    Item() {}
    Item(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

public static void main(String[] argsx) throws IOException{

    ObjectMapper mapper = new ObjectMapper();
    RootClass root = new RootClass();
    root.items.add(new Item("cat"));
    RootClass root2 = null;
    String json = mapper.writeValueAsString(root);
    root2 = mapper.readValue(json, RootClass.class);
    Item item = root2.items.get(0);
    System.out.println(item.getName());
}

Output:

cat

Upvotes: 3

Related Questions