The problem is with your TypeReference<Map<String, T>>
. When you give T here jackson will try to infer the type. Since at this point jackson doesnt know anything about Student class it infer the "name" : "name1" to be a LinkedHashMap with key "name" and value "name1". So in-turn it creates a LinkedHashMap<String, LinkedHashMap<String>>
.
As a quick solution you in the object mapper method you could use TypeReference as
studentMap = mapper.readValue(new File(filename), new TypeReference<Map<String, Student>>() { });
Since the method is getStudents it make sense to use this TypeReference but then the whole point of generics in that method is wasted.
Another approach would be to use a custom deserializer. There are many ways of doing this. You could find the details in http://wiki.fasterxml.com/JacksonPolymorphicDeserialization
For example lets make a marker interface for all possible class use a custom deserializer. Say for you scenario lets say we have an interface StudentI which will be implemented by all possible classes you type T could have. Then use the @JsonTypeInfo to give additional details about the class
Student interface
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@Type(value = Student.class, name = "student") })
public interface StudentI {
}
This means if you give something like 'type : student' in your json the mapper would use Student.class for you T.
Sample Class
import java.io.File;
import java.io.IOException;
import java.util.Map;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class SampleClass {
public static <T extends StudentI> Map<String, T> getStudents(String filename) {
Map<String, T> studentMap = null;
ObjectMapper mapper = new ObjectMapper();
try {
studentMap = mapper.readValue(new File(filename),
new TypeReference<Map<String, StudentI>>() { });
} catch (JsonParseException e) {
System.out.println(e.getMessage());
} catch (JsonMappingException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
}
return (Map<String, T>)studentMap;
}
}
Students.json
{
"student1" :
{
"name" : "name1",
"age" : 22,
"type" : "student"
},
"student2" :
{
"name" : "name2",
"age" : 22,
"type" : "student"
}
}
Now your Student class should implement this interface
public class Student implements StudentI {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
Once this is done your code would work just as expected
public static void main(String[] args) {
Map<String, Student> students = SampleClass.getStudents("students.json");
System.out.println(students.get("student1").getName());
}
//Output : name1