Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map an array of JSON objects to a java.util.Map and vice versa

The question is how to map an array of JSON objects to a java.util.Map where each key would be some specified property of an object and the value is the object itself.

JSON:

{"items": [{"field1": 1, "field2": "Hello"}, {"field1": 2, "field2":"World"}]}

Java POJO:

public class Storage {
    private Map<Integer, Item> items;
}

public class Item {
    private Integer field1;
    private String field2;
}

So is there a some way to specify to ObjectMapper that it should use field1 property of each JSON object as key when deserializing array of items to the Map?

like image 947
Pavel Mitrofanov Avatar asked Nov 25 '15 10:11

Pavel Mitrofanov


People also ask

How do I pass a JSON object to a map?

We need to use the JSON-lib library for serializing and de-serializing a Map in JSON format. Initially, we can create a POJO class and pass this instance as an argument to the put() method of Map class and finally add this map instance to the accumulateAll() method of JSONObject.

Can we convert JSON to map in Java?

We can easily convert JSON data into a map because the JSON format is essentially a key-value pair grouping and the map also stores data in key-value pairs. Let's understand how we can use both JACKSON and Gson libraries to convert JSON data into a Map.

Can map be used with JSON object?

You can map the data types of your business model into JSON by using the examples. Data in JSON is either an object or an array. A JSON object is an unordered collection of names and values. A JSON array is an ordered sequence of values.

How do I create a map array?

map() creates a new array from calling a function for every array element. map() calls a function once for each element in an array. map() does not execute the function for empty elements. map() does not change the original array.


2 Answers

How to deserialize a JSON string

You can use Jackson to deserialize a JSON string:

For example if you have class Foo

public class Foo {

   private Bar[] items;

   // Constructor / Getters & Setters

} 

And that class has an array of class Bar

 public class Bar {

     private int field1;
     private String field2;


     // Constructor / Getters & Setters

 }

Where the field names match those in your JSON string then you can do the following to convert it:

String jsonString = "{\"items\": [{\"field1\": 1, \"field2\": \"Hello\"}, {\"field1\": 2, \"field2\":\"World\"}]}";

ObjectMapper mapper = new ObjectMapper();

Foo foo = mapper.readValue(jsonString, Foo.class);

If you are using Maven, the following dependency would be required in your pom.xml:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>

Approaches to solve your problem:

Option 1 - Custom Deserializer

Write a custom JsonDeserializer to deserialize your JSON string into a Storage object with a field items of type Map<String,Item>

 public class CustomDeserializer extends JsonDeserializer<Storage> {

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

        Map<Integer, Item> map = new HashMap<>();

        ObjectCodec oc = jsonParser.getCodec();
        JsonNode rootNode = oc.readTree(jsonParser);
        JsonNode items = rootNode.get("items");

        for (int i = 0; i < items.size(); i++) {

            JsonNode childNode = items.get(i);

            Item item = new Item(childNode.get("field1").asInt(), childNode.get("field2").asText());

            map.put(item.getField1(), item);
        }

        return new Storage(map);
    }
}

You would then annotate your Storage class with the following:

@JsonDeserialize(using = CustomDeserializer.class)

Your Storage class would look something like;

@JsonDeserialize(using = CustomDeserializer.class)
public class Storage {

   private Map<Integer, Item> items;

   public Storage(Map<Integer, Item> map) {
    this.items = map;
   }

   ...

}

Option 2 - Create Map post deserialization

Deserialize the JSON string into a Storage object with an array of Item as described at the beginning and then construct your Map<Integer, Item> after.

Hope this helps.

like image 68
kstandell Avatar answered Oct 13 '22 12:10

kstandell


You can create your own custom Serializers/Deserializers to achieve this. Jackson provides a neat way of doing this. Just annotate the Storage class with @JsonDeserialize(using = YourDeserializer.class) and have the logic to convert the json in YourDeserializer.

like image 36
shivdim Avatar answered Oct 13 '22 12:10

shivdim