简体   繁体   中英

json deserialization problem

Have an array, when the size is 1, the json data I received does NOT contains [] ; like

{"firstname":"tom"}

when the size is larger than 1, the data I received contains [] , like

[{"firstname":"tom"},{"firstname":"robert"}]

Currently my class contains an array property

String[] firstname;
//getter setter omit here

Code to handle this likes

ObjectMapper mapper = new ObjectMapper();    
MyClass object = mapper.readValue(json, MyClass.class);

When the size is larger than 1, the deserialization works. However when size is 1, the deserialization failed.

I am currently using jackson, any solution for this problem?

I am wondering if jackson/gson or any other library can handle this?

For Jackson specifically, your best bet would to first bind to a JsonNode or Object, like:

Object raw = objectMapper.readValue(json, Object.class); // becomes Map, List, String etc

and then check what you got, bind again:

MyClass[] result;
if (raw instanceof List<?>) { // array
  result = objectMapper.convertValue(raw, MyClass[].class);
} else { // single object
  result = objectMapper.convertValue(raw, MyClass.class);
}

But I think JSON you are getting is bad -- why would you return an object, or array, intead of just array of size 1? -- so if at all possible, I'd rather fix JSON first. But if that is not possible, this would work.

Here's how to do it with GSON. Let's assume this object structure:

public class Group{

    public Group(final List<Person> members){
        this.members = members;
    }

    private final List<Person> members;
}

public class Person{

    public Person(final String firstName, final String lastName){
        this.firstName = firstName;
        this.lastName = lastName;
    }

    private final String firstName;
    private final String lastName;
}

Here's a deserializer that understands single Person entries as well as arrays of them:

public class GroupDeserializer implements JsonDeserializer<Group>{

    @Override
    public Group deserialize(final JsonElement json,
        final Type typeOfT,
        final JsonDeserializationContext context) throws JsonParseException{
        List<Person> members;
        if(json.isJsonArray()){
            final JsonArray array = json.getAsJsonArray();
            members = new ArrayList<Person>(array.size());
            for(final JsonElement personElement : array){
                members.add(getSinglePerson(personElement, context));
            }
        } else{
            members =
                Collections.singletonList(getSinglePerson(json, context));
        }
        return new Group(members);
    }

    private Person getSinglePerson(final JsonElement element,
        final JsonDeserializationContext context){
        final JsonObject personObject = element.getAsJsonObject();
        final String firstName =
            personObject.getAsJsonPrimitive("firstname").getAsString();
        final String lastName =
            personObject.getAsJsonPrimitive("lastname").getAsString();
        return new Person(firstName, lastName);
    }

}

And here you can find the necessary Configuration to use this

I have faced the same issue when I am trying to deserialize the JSON object which was constructed from XML. (XML-JSON). After quite a bit of research, found that we have a simple fix.

Just set the feature : ACCEPT_SINGLE_VALUE_AS_ARRAY.

ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

For more info : http://fasterxml.github.com/jackson-databind/javadoc/2.0.0/com/fasterxml/jackson/databind/DeserializationFeature.html#ACCEPT_SINGLE_VALUE_AS_ARRAY

edit: I guess you would then just extract a JsonElement and check it's isJsonArray() and/or isJsonObject() . Then, just call getAsJsonArray() or getAsJsonObject() .

Old answer: Why not just try to extract the array and catch the JsonParseException if it fails. In the catch block, try to extract an object instead.

I know it's not pretty but it should work.

In the first instance it looks like an object, in the second instance it looks like an array of objects (which it sounds like you are expecting).

JSON encoding libraries typically have a "force array" option for cases like this. Failing that, on your client you could check the JSON response and if it's not an array, push the returned objected into an new array.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM