I have a map where the a key's value is a list of objects. Am able to serialize the keys through builder.enableComplexMapKeySerialization();
but the values are not serialized as expected because they return a string on deserialization instead of object.
Below is the output of serialization
[{"id":31001,"name":Teacher"]}, //This is the key
[{"id":33033,"name":"student1"}, {"id":34001,"name":"student2"}]], //This is the list of values
I used the relevant TypeToken which is TypeToken<HashMap<Teacher, List<Student>>>
but still the list values is returned a string on deserialization instead of object.
JSON is made up of name/value pairs (where the value side can be a list of things). The name part of that is a string (See: http://json.org)
What you're trying to do is use an object as a name; you can't do that directly. A JSON object can't be a name for a name/value pair.
If you read the documentation for enableComplexMapKeySerialization it explains what the resulting JSON is going to be.
The JSON it produces (a Map as a JSON array) will deserialize perfectly back to your map. The following is a complete, working example (Java 7).
Note that once I deserialize from JSON back to Java, I'm iterating over the map to get the keys. This is because without equals()
and hashCode()
being overridden in Teacher
there's no way to create a new instance of Teacher
and have it work as a key (only the reference values are compared).
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class App
{
public static void main( String[] args )
{
HashMap<Teacher, List<Student>> map = new HashMap<>();
Teacher t = new Teacher("12345", "Teacher");
Teacher t2 = new Teacher("23456", "Teacher2");
ArrayList<Student> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add(new Student(String.valueOf(i), "Student" + String.valueOf(i)));
}
map.put(t, list);
map.put(t2, list);
GsonBuilder builder = new GsonBuilder();
Gson gson =
builder.enableComplexMapKeySerialization().setPrettyPrinting().create();
Type type = new TypeToken<HashMap<Teacher,List<Student>>>(){}.getType();
String json = gson.toJson(map, type);
System.out.println(json);
System.out.println("\nAfter deserialization:");
HashMap<Teacher, List<Student>> map2 = gson.fromJson(json, type);
for (Teacher t3 : map2.keySet()) {
System.out.println(t3.name);
for (Student s2 : map2.get(t3)) {
System.out.println("\t" + s2.name);
}
}
}
}
class Teacher {
public String id;
public String name;
public Teacher(String id, String name) {
this.id = id;
this.name = name;
}
}
class Student {
public String id;
public String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
}
Output:
[
[
{
"id": "12345",
"name": "Teacher"
},
[
{
"id": "0",
"name": "Student0"
},
{
"id": "1",
"name": "Student1"
},
{
"id": "2",
"name": "Student2"
}
]
],
[
{
"id": "23456",
"name": "Teacher2"
},
[
{
"id": "0",
"name": "Student0"
},
{
"id": "1",
"name": "Student1"
},
{
"id": "2",
"name": "Student2"
}
]
]
]
After deserialization:
Teacher2
Student0
Student1
Student2
Teacher
Student0
Student1
Student2
If you implement equals()
and hashCode()
in your Teacher
class, you would then be able to use a new instance of Teacher
to retrieve things from the map:
class Teacher {
public String id;
public String name;
public Teacher(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public int hashCode()
{
int hash = 3;
hash = 37 * hash + Objects.hashCode(this.id);
hash = 37 * hash + Objects.hashCode(this.name);
return hash;
}
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Teacher other = (Teacher) obj;
if (!Objects.equals(this.id, other.id))
{
return false;
}
if (!Objects.equals(this.name, other.name))
{
return false;
}
return true;
}
}
Once you have that, you could do:
...
HashMap<Teacher, List<Student>> map2 = gson.fromJson(json, type);
Teacher t = new Teacher("23456", "Teacher2");
List<Student> list = map2.get(t);
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With