2

i am attempting to turn a json string into objects with gson.

I have a very simple example below, and it runs, but the resulting answer is empty, ie: my Answer objects's text field is empty.

import com.google.gson.*;

public class Meow {

    public static void main(String[] args) throws Exception{

        Gson gson = new Gson();
        String jsonOutput = "[{\"answer\":{\"text\":\"text1\"}},{\"answer\":{\"text\":\"text2\"}} ]";

        Answer[] a = gson.fromJson(jsonOutput, Answer[].class);

        for(Answer i:a) {
          System.out.println(i.text);
        }       
    }

    public class Answer {

        public String text;

        public Answer(String text) {
            super();
            this.text=text;
        }

        public String toString(){
            return text;
        }

        public void setText(String a){
            this.text=a;
        }
    }

}

1 Answer 1

5

Because your JSON doesn't match your class.

Your JSON right now is an array of objects, each containing an answer object as a field.

Your JSON the way you have things would need to look like:

String jsonOutput = "[{\"text\":\"text1\"},{\"text\":\"text2\"}]";

Edit to add from comments:

If you can't change the output, you need a "wrapper". Something like:

public class AnswerWrapper {
    public Answer answer;

    // etc
}

And use an array of those. That is what the JSON will map to. It can't see them as Answer objects because ... they're not.

One More Edit to Add: Your other option is to write custom deserializers for your classes. I'm a bit mixed on whether you should do this or not, but it will work. The reason I say that is that you have JSON that isn't an array of Answer objects, but you want it to be. I think I'd be annoyed if I came across this in production code because without understanding what was going on it could be confusing.

With that caveat being said, you can create a custom JsonDeserializer and use GsonBuilder:

class AnswerDeserializer implements JsonDeserializer<Answer> {

    public Answer deserialize(JsonElement je, Type type, 
                              JsonDeserializationContext jdc) 
                                   throws JsonParseException {

        return new Answer(je.getAsJsonObject().get("answer")
                            .getAsJsonObject().get("text").getAsString());
    }

}

Then your code would look like:

public static void main(String[] args) throws Exception{

    String jsonOutput = "[{\"answer\":{\"text\":\"text1\"}},{\"answer\":{\"text\":\"text2\"}} ]";

    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Answer.class, new AnswerDeserializer());

    Gson gson = gsonBuilder.create();

    Answer[] a = gson.fromJson(jsonOutput, Answer[].class);

    for(Answer i:a) {
        System.out.println(i.text);
    }       
}

If it were me, and I had JSON that wasn't what I needed it to be but wanted to use GSON to directly serialize/deserialize I'd create the Answer class as a wrapper that hid the details:

/**
 *  Due to how our JSON is being provided we created an inner
 *  class. 
 **/ 
public class Answer {

    private RealAnswer answer;

    private class RealAnswer {

        public String text;
    }

    ...
}

With the public getters/setters for Answer accessing the private RealAnswer. It just seems way cleaner and easier to understand for the next guy.

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

5 Comments

got it. unfortunately, there is no way i can change that output. how do I tell GSON that I would like these to be recognized as Answer objects? an update to your answer will be much appreciated.
Thanks Brian! It works! But seems a tad weird, since i need to do this for all my files. I figure I could probably specify something for GSON?
@mingyeow - I added another section this morning. As noted, personally I'd not do it, but knowing it exists is in the spirit of SO.
this is an epic answer. thanks a million. i "get" gson a lot better now. thanks again!
btw, my inital json was implemented as such because of how Restkit in iOS expects this json. since learnt from implementing backbone and gson that it is not that smart to do so

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.