1

I'm writing RESTful web service for my android app. I have my POJO class named ServiceResponse:

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;
}

It's parsed to JSON using Jackson, example here: http://pastebin.com/pu8792a1 There will be many classes passed using this arraylist. My question is, how do I make it ServiceResponse object again from the JSON?

{
  "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
  } ]

I tried: (skipped 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());

but I got ClassCastException: java.util.ArrayList cannot be cast into com.example.User

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
navarion
  • 91
  • 5

1 Answers1

0

A couple problems:

Problem 1:

"data" : [ {
  "name" : "name",
  "password" : "pass"
  ...
} ]

private ArrayList<Object> data;

Since you define the type of the list as Object the parser doesn't know to map it to a User type, so it will map it to an array of LinkedHashMap. So basically you're left with ArrayList<LinkedHashMap> data. Change all the Object to User.

Problem 2:

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

The parser will look for JavaBean properties that follow JavaBean naming convention i.e. property/setProperty/getProperty. In your case the parser thinks the setData is a setter to set the value of the data field. As a setter, it will expect an ArrayList<User> and not a User as the argument. So better to change the name to something like addUser(User user). While you're at it, you should change the name of setArrayData to follow the name convention also.

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);
}

Making these few changes should get it working (tested).


UPDATE: Problem 1 is actually not a problem

I know I could make it work if I used User instead of Object, but I'd like to send different objects in data array (sometimes it would be User, other time, for example Item). Is there a way to do it? Here They say I can use this: POJO pojo = mapper.convertValue(singleObject, POJO.class); To convert from LinkedHashMap to my object, but when I try it: User user = mapper.convertValue(response.getData().get(0), User.class); User is still null

As the OP brought to my attention, we can convert the map the parser created by using ObjectMapper.convertValue( map , User.class);. Not sure why the OP is getting null, but when I tested, changing the User types back to Object type, it works fine

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();
    }
}

Result test.json.User@366e2eef


UPDATE 2:

The OP wants to use the String objectType to convert the the map by type:

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)));
Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Thanks for answer. I know I could make it work if I used User instead of Object, but I'd like to send different objects in data array (sometimes it would be User, other time, for example Item). Is there a way to do it? Here: http://stackoverflow.com/questions/15430715/casting-linkedhashmap-to-complex-object They say I can use this: POJO pojo = mapper.convertValue(singleObject, POJO.class); To convert from LinkedHashMap to my object, but when I try it: User user = mapper.convertValue(response.getData().get(0), User.class); User is still null. – navarion Oct 15 '14 at 12:39
  • I didn't now that. But I just tried it, and it works fine for me – Paul Samsotha Oct 15 '14 at 12:50
  • I changed all the `User` back to `Object` and it works fine. Not sure what you are doing wrong. – Paul Samsotha Oct 15 '14 at 12:57
  • Ok it works, I must've done something wrong. Now it looks like that: ArrayList users = mapper.convertValue(response.getData(), new TypeReference>() { }); BUT now I'd like to use ServiceResponse.objectType string (which can be something like com.example.User) to instantiate that class. I know I have to use reflection to that. Do you have any idea how to accomplish it? It would be something like: ArrayList objects = mapper.convertValue(response.getData(), new TypeReference>() { }); – navarion Oct 15 '14 at 13:13
  • `Class c = Class.forName(response.getObjectType);` to get the class. And don't use `TypeReference`. Type erasure will not allow you do it that way. Don't quote me, but I think it's deprecated. You can use `TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, c)` – Paul Samsotha Oct 15 '14 at 13:20
  • Hmm I'm not sure how to do it. Could you please rewrite the line I've provided: ArrayList users = mapper.convertValue(response.getData(), new TypeReference>() { }); To use String as class name? I would be very grateful! :) – navarion Oct 15 '14 at 13:26
  • Thanks, it works! But you have accidentally put User.class instead of clazz when creating TypeFactory. Cheers! – navarion Oct 15 '14 at 13:48