Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson deserialization - with contained ArrayList<T>

Tags:

json

jackson

Good day,

I am currently integration attempting to consume a REST service that produces JSON (written in .NET) using Jackson (with Jersey). The JSON consists of a possible error message and an array of objects. Below is a sample of the JSON returned as produced by Jersey's logging filter:

{
    "error":null,
    "object":"[{\"Id\":16,\"Class\":\"ReportType\",\"ClassID\":\"4\",\"ListItemParent_ID\":4,\"Item\":\"Pothole\",\"Description\":\"Pothole\",\"Sequence\":1,\"LastEditDate\":null,\"LastEditor\":null,\"ItemStatus\":\"Active\",\"ItemColor\":\"#00AF64\"}]"
}

I have two classes to represent the type (the outer ListResponse):

public class ListResponse { 

    public String error;    
    public ArrayList<ListItem> object;  

    public ListResponse() { 
    }
}

and (the inner ListItem):

public class ListItem {
    @JsonProperty("Id")
    public int id;      
    @JsonProperty("Class")
    public String classType;
    @JsonProperty("ClassID")
    public String classId;  
    @JsonProperty("ListItemParent_ID")
    public int parentId;    
    @JsonProperty("Item")
    public String item; 
    @JsonProperty("Description")
    public String description;

    @JsonAnySetter 
    public void handleUnknown(String key, Object value) {}

    public ListItem() {
    }
}

The class that invokes and returns the JSON looks like this:

public class CitizenPlusService {
    private Client client = null;   
    private WebResource service = null;     

    public CitizenPlusService() {
        initializeService("http://localhost:59105/PlusService/"); 
    }

    private void initializeService(String baseURI) {    
        // Use the default client configuration. 
        ClientConfig clientConfig = new DefaultClientConfig();      
        clientConfig.getClasses().add(JacksonJsonProvider.class);                       

        client = Client.create(clientConfig);

        // Add a logging filter to track communication between server and client. 
        client.addFilter(new LoggingFilter()); 
        // Add the base URI
        service = client.resource(UriBuilder.fromUri(baseURI).build()); 
    }

    public ListResponse getListItems(String id) throws Exception
    {           
        ListResponse response = service.path("GetListItems").path(id).accept(MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE).get(ListResponse.class);                                  
        return response;            
    }
}

The important call here is the getListItems method. Running the code in a test harness, produces the following:

org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token
at [Source: java.io.StringReader@49497eb8; line: 1, column: 14] (through reference chain: citizenplus.types.ListResponse["object"])

Please assist.

Regards, Carl-Peter Meyer

like image 952
Carl Meyer Avatar asked Dec 26 '22 23:12

Carl Meyer


1 Answers

You may be missing a @JsonDeserialize attribute as the type information does get lost in generics at run-time. Also you should avoid using concrete classes for collections if you can.

public class ListResponse { 

    public String error;

    @JsonDeserialize(as=ArrayList.class, contentAs=ListItem.class)
    public List<ListItem> object;  

}
like image 54
Archimedes Trajano Avatar answered Dec 29 '22 13:12

Archimedes Trajano