【问题标题】:Jackson: How to deserialize instance field of my own class杰克逊:如何反序列化我自己的类的实例字段
【发布时间】:2014-10-15 11:23:40
【问题描述】:

我正在为我的 android 应用程序编写 RESTful Web 服务。 我有一个名为 ServiceResponse 的 POJO 类:

private int responseCode;
private String objectType;
private ArrayList<Object> data;

public int getResponseCode() {
    return responseCode;
}

public void setResponseCode(int responseCode) {
    this.responseCode = responseCode;
}

public ArrayList<Object> getData() {
    return data;
}

public void setArrayData(ArrayList<Object> data) {
    this.data = data;
}

public void setData(Object data) {
    if(this.data == null) this.data = new ArrayList<Object>();
    this.data.add(data);
}

public String getObjectType() {
    return objectType;
}

public void setObjectType(String objectType) {
    this.objectType = objectType;
}

使用 Jackson 将其解析为 JSON,例如:http://pastebin.com/pu8792a1 将使用此数组列表传递许多类。 我的问题是,如何从 JSON 中再次使其成为 ServiceResponse 对象?

{
  "responseCode" : 2,
  "objectType" : "com.example.User",
  "data" : [ {
    "name" : "name",
    "password" : "pass",
    "email" : "mail@gmail.com",
    "device" : "ABC",
    "level" : 10,
    "gold" : 82,
    "delois" : 0,
    "uranium" : 0,
    "attack" : 5,
    "speed" : 5,
    "armor" : 5,
    "controllability" : 5,
    "exp" : 100,
    "hp" : 100,
    "hpMax" : 300,
    "deuter" : 21,
    "deuterMax" : 120,
    "research" : 1413360596907,
    "id" : 1
  } ]

我试过了:(跳过了 try & catch)

    ObjectMapper mapper = new ObjectMapper();
    ServiceResponse response;
    response = mapper.readValue(output, ServiceResponse.class);

    User user =  (User) ( response.getData().get(0) );
    System.out.println(user.toString());

但我得到 ClassCastException: java.util.ArrayList cannot be cast into com.example.User

【问题讨论】:

    标签: java json rest jackson


    【解决方案1】:

    几个问题:

    问题一:

    "data" : [ {
      "name" : "name",
      "password" : "pass"
      ...
    } ]
    
    private ArrayList<Object> data;
    

    由于您将列表的类型定义为Object,解析器不知道将其映射到User 类型,因此它将映射到LinkedHashMap 的数组。所以基本上你只剩下ArrayList&lt;LinkedHashMap&gt; data。将所有Object 更改为User

    问题2:

    private ArrayList<User> data;
    ...
    public void setData(User data) {
        if (this.data == null) {
            this.data = new ArrayList<User>();
        }
        this.data.add(data);
    }
    

    解析器将查找遵循 JavaBean 命名约定的 JavaBean 属性,即 property/setProperty/getProperty。在您的情况下,解析器认为 setDataset data 字段值的设置器。作为 setter,它会期望 ArrayList&lt;User&gt; 而不是 User 作为参数。所以最好把名字改成addUser(User user)。当您使用它时,您应该更改 setArrayData 的名称以遵循名称约定。

    public void setData(ArrayList<User> data) {
        this.data = data;
    }
    
    public void addUser(User data) {
        if (this.data == null) {
            this.data = new ArrayList<User>();
        }
        this.data.add(data);
    }
    

    进行这些少量更改应该可以使其正常工作(经过测试)。


    更新:问题 1 实际上不是问题

    我知道如果我使用 User 而不是 Object,我可以让它工作,但我想在数据数组中发送不同的对象(有时是 User,其他时候,例如 Item)。有没有办法做到这一点? Here 他们说我可以使用这个:POJO pojo = mapper.convertValue(singleObject, POJO.class);LinkedHashMap 转换为我的对象,但是当我尝试它时: User user = mapper.convertValue(response.getData().get(0), User.class );用户仍为空

    正如 OP 引起我注意的那样,我们可以将映射转换为使用 ObjectMapper.convertValue( map , User.class); 创建的解析器。不知道为什么 OP 变空,但是当我测试时,将 User 类型改回 Object 类型,它工作正常

    public class Test {
        public static void main(String[] args) throws Exception {
            ObjectMapper mapper = new ObjectMapper();
            InputStream is = Test.class.getResourceAsStream("test.json");
            ServiceResponse response = mapper.readValue(is, ServiceResponse.class);
            User user = (User) (mapper.convertValue(response.getData().get(0), User.class));
            System.out.println(user.toString());
            is.close();
        }
    }
    

    结果test.json.User@366e2eef


    更新 2:

    OP希望使用String objectType按类型转换地图:

    ServiceResponse response = ...
    String objectType = response.getObjectType();
    Class clazz = Class.forName(objectType);      // catch exception
    ArrayList user = (mapper.convertValue(response.getData(), 
                TypeFactory.defaultInstance().constructCollectionType(
                        ArrayList.class, clazz)));
    

    【讨论】:

    • 感谢您的回答。我知道如果我使用用户而不是对象,我可以让它工作,但我想在数据数组中发送不同的对象(有时是用户,其他时候,例如项目)。有没有办法做到这一点?这里:stackoverflow.com/questions/15430715/… 他们说我可以用这个: POJO pojo = mapper.convertValue(singleObject, POJO.class);从 LinkedHashMap 转换为我的对象,但是当我尝试它时: User user = mapper.convertValue(response.getData().get(0), User.class);用户仍然为空。
    • 我现在没有那样做。但我只是试了一下,对我来说效果很好
    • 我将所有的User 改回Object,它工作正常。不知道你做错了什么。
    • 好吧,我一定是做错了什么。现在看起来像这样: ArrayList users = mapper.convertValue(response.getData(), new TypeReference>() { });但现在我想使用 ServiceResponse.objectType 字符串(可以是 com.example.User 之类的东西)来实例化该类。我知道我必须对此进行反思。你知道如何完成它吗?类似于: ArrayList objects = mapper.convertValue(response.getData(), new TypeReference>() { });
    • Class c = Class.forName(response.getObjectType); 获取课程。并且不要使用TypeReference。类型擦除不允许您这样做。不要引用我的话,但我认为它已被弃用。你可以使用TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, c)
    猜你喜欢
    • 2013-07-10
    • 1970-01-01
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-02
    • 2015-08-01
    • 2013-02-23
    相关资源
    最近更新 更多