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
?
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.