Generally it looks like a bad idea to create Map
like this. JSON Object
can be converted to Java
Map
where key
is String
and value
is any Object
: can be another Map
, array
, POJO
or simple types. So, generally your JSON
should look like:
{
"key" : { .. complex nested object .. }
}
Theres is no other option. If you want to have in Java
mapping POJO
-> POJO
you need to instruct deserialiser how to convert JSON
-String
-key
to an object. There is no other option. I will try to explain this process using Jackson
library because it is most used in RESTful Web Services
. Let's define Person
class which fits to your JSON
payload.
class Person {
private String name;
private double weight;
private int id;
public Person() {
}
public Person(String value) {
String[] values = value.split(",");
name = values[0];
weight = Double.valueOf(values[1]);
id = Integer.valueOf(values[2]);
}
public Person(String name, double weight, int id) {
this.name = name;
this.weight = weight;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public String toString() {
return name + "," + weight + "," + id;
}
}
Because it is used in Map
as key we need to implement hashCode
and equals
methods. Except public Person(String value)
constructor and toString
method everything else looks pretty normal. Now, let's take a look on this constructor and toString
method. They are in correlation: toString
builds String
from the Person
instance and constructor builds Person
from String
. We can call first transformation as serialisation and second as deserialisation of our key in Map
serialisation and deserialisation. (Whether these two are well implemented this is another story. I just want to show an idea behind it. Before using on production should be improved)
Let's use this knowledge and Jackson
features to serialise and deserialise Map<Person, Person>
:
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.MapType;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public class JsonApp {
public static void main(String[] args) throws Exception {
// register deserializer for Person as keys.
SimpleModule module = new SimpleModule();
module.addKeyDeserializer(Person.class, new PersonKeyDeserializer());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// Create example Map
Person key = new Person("Rick", 80.5, 1);
Person value = new Person("Morty", 40.1, 2);
Map<Person, Person> personMap = new HashMap<>();
personMap.put(key, value);
// Serialise Map to JSON
String json = mapper.writeValueAsString(personMap);
System.out.println(json);
// Deserialise it back to `Object`
MapType mapType = mapper.getTypeFactory().constructMapType(HashMap.class, Person.class, Person.class);
System.out.println(mapper.readValue(json, mapType).toString());
}
}
class PersonKeyDeserializer extends KeyDeserializer {
@Override
public Object deserializeKey(String key, DeserializationContext ctxt) {
return new Person(key);
}
}
Above code prints as first JSON
:
{
"Rick,80.5,1" : {
"name" : "Morty",
"weight" : 40.1,
"id" : 2
}
}
As you can see, Person
's toString
method was used to generate JSON
key
. Normal serialisation proces serialised Person
to JSON
object. As second below text is printed:
{Rick,80.5,1=Morty,40.1,2}
This is a default representation of Map
and it's keys and values. Because both are Person
object it's toString
method is invoked.
As you can see there is an option to send JSON
as Map<Person, Person>
but key should be somehow represented. You need to take a look on Person
class implementation. Maybe you will find some similarities to my example. If no, maybe it was configured somehow. First of all try to send in PostMan
:
{
"123" : {"name":"def","weight":200.0,"id":"123"}
}
Or:
{
"{\"name\":\"abc\",\"weight\":100.0,\"id\":\"123\"}":{
"name":"def",
"weight":200.0,
"id":"123"
}
}
Maybe it will work.
See also: