7

I'm using Jackson within CXF to serialize/deserialize data. Unfortunately, I am having difficulty configuring CXF/Jackson to deserialize a JSON array. I'd appreciate help in resolving the issue.

Up to this point most of the json data has been in object format, i.e.

{ "objectCollection": [ {...}, {...}, {...}... ] }

However, the json data in question is of the form:

[ {...}, {...}, {...} ]

The web service endpoint expects a "GroupsDto" object (see following) that has a single property -- a collection of groups, which is transmitted via the JSON array.

@PATH(...)
public Response createGroups(GroupsDto groups) {
...
}

I added @JsonDeserialize as follows to the GroupsDto collection property, but it does NOT work. I continue to get: "Can not deserialize instance of GroupsDto out of START_ARRAY token"

public class GroupsDto {

       private Collection<GroupDto> groups;

       /**
        * @return the groups
        */
       @XmlElement(name="group")
       @JsonDeserialize(contentAs=GroupDto.class)
       public Collection<GroupDto> getGroups() {
               return groups;
       }
...
}
1
  • Check this question [Jackson - reading a JSON array with Robospice using loadDataFromNetwork() method][1] [1]: stackoverflow.com/questions/18792702/… Commented May 16, 2014 at 1:59

3 Answers 3

9

If json data is of the form:

[ {...}, {...}, {...} ]

You got to use add another class say 'wrapper':

@JsonIgnoreProperties(ignoreUnknown = true)
public class ListDto extends ArrayList<GroupDto> {

    public ListDto() {
    }
}

And use this class while deserailizing. This approach worked for me.

Sign up to request clarification or add additional context in comments.

Comments

1

You just need to specify the @JsonDeserialize(contentAs=GroupDto.class) in your setter. Serialization is always on get desserialization is always on set, or if you prefer you can specify both on the field.

Documentation for Serialize and Deserialize

Code sample:

import java.io.IOException;
import java.util.List;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonDeserialize;

public class JacksonDeserialize {

    public static class ModelClass {

        private String name;

        public ModelClass() {
        }

        public String getName() {
            return name;
        }

        public void setName(final String name) {
            this.name = name;
        }

        public ModelClass(final String name) {
            super();
            this.name = name;
        }

        @Override
        public String toString() {
            return "ModelClass [name=" + name + "]";
        }

    }

    public static class ListModelClass {

        private List<ModelClass> list;

        @JsonDeserialize(contentAs = ModelClass.class)
        public void setList(final List<ModelClass> list) {
            this.list = list;
        }

        @Override
        public String toString() {
            return "ListModelClass [list=" + list + "]";
        }

    }

    public static void main(final String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        System.out.println(objectMapper.readValue("{\"list\":[{\"name\":\"name1\"},{\"name\":\"name2\"}]}",
                ListModelClass.class));
    }

}

6 Comments

Thanks for the heads-up on the getter/setter issue. I noticed in your example that you're qualifying the json array i.e. "{\" list \":...} Is it possible to deserialize without the qualification? If yes, how?
there iss no qualification, the magic is done in this case by @JsonDeserialize annotation. The property contentAs is to indicate that this is a collection and will be deserialized as ModelClass. If you want you could change the property name from list to something else. The name doesn't matter, what matters is the annotation.
I understand that the specific name is immaterial, but what does one do in the case where there is no name? In your example you're reading in {"list": [...]}, which has the key 'list', but what if there is no key (name) -- i.e. [...]?
Ah, there in lies the problem. The serialization/deserialization is handled by CXF, which calls a pre-defined ObjectMapper; consequently, I can't simply pass a TypeReference to a custom ObjectMapper, I have to rely on the pre-defined ObjectMapper and annotations.
Ok, which library are you using to integrate both?
|
0

Without using wrapper classes

Using Jackson's ObjectMapper

objectMapper.readValue();

Having data as follows...

[... , {YourObj} , {YourObj} , ... ]

You could do

YourObj[] yourObjArray = objectMapper.readValue(source, YourObj[].class);


If you then want to convert it to a List you could further do something like

List<YourObj> yourObjList = Arrays.stream(yourObjArray).collect(Collectors.toList())

Reference https://www.baeldung.com/jackson-collection-array

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.