通用方法不起作用

时间:2014-05-08 16:40:36

标签: java generics map jackson generic-method

我的通用方法给出了转换异常。

  

java.util.LinkedHashMap无法强制转换为com.example.model.Student

主要班级

public static void main(String[] args) {
    Map<String, Student> students = SampleClass.getStudents("students.json");

    System.out.println(students.get("student1").getName());

}

SampleClass

public static <T> 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, T>>() { });
    } 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;
}

我做错了什么?

更新 json文件

{
"student1" :
    {
        "name" : "name1",
        "age" : 22
    },
"student2" :
    {
        "name" : "name2",
        "age" : 22
    }
}

更新

找到this作为解决方案。

2 个答案:

答案 0 :(得分:1)

问题在于您的TypeReference<Map<String, T>>。当你在这里给T时,杰克逊会尝试推断出这种类型。因为在这一点上杰克逊对学生课程一无所知,所以它推断出了这个名字&#34; :&#34; name1&#34;使用key&#34; name&#34;成为LinkedHashMap;和价值&#34; name1&#34;。因此,它会创建一个LinkedHashMap<String, LinkedHashMap<String>>

作为对象映射器方法的快速解决方案,您可以将TypeReference用作

studentMap = mapper.readValue(new File(filename), new TypeReference<Map<String, Student>>() { });

由于该方法是getStudents,因此使用此TypeReference是有意义的,但是该方法中泛型的整个点被浪费了。

另一种方法是使用自定义反序列化器。有很多方法可以做到这一点。您可以在http://wiki.fasterxml.com/JacksonPolymorphicDeserialization

中找到详细信息

例如,让我们为所有可能的类创建一个标记接口使用自定义反序列化器。为你说场景让我们说我们有一个接口StudentI,它将由你输入T所有可能的类实现。然后使用@JsonTypeInfo提供有关类

的其他详细信息

学生界面

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 {

}

这意味着,如果您提供的类似于&#39;输入:student&#39;在你的json中,映射器将为你使用Student.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"
    }
}

现在您的Student类应该实现此接口

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 + "]";
    }
}

完成此操作后,您的代码将按预期工作

public static void main(String[] args) {
    Map<String, Student> students = SampleClass.getStudents("students.json");
    System.out.println(students.get("student1").getName());
}

//Output : name1

答案 1 :(得分:0)

取决于你的json文件中的内容。看起来mapper正在返回Student对象而不是map。