14

I need to parse a JSON Response that looks like:

{"key1": "value1", 
 "key2": "value2", 
 "key3": 
    {"childKey1": "childValue1", 
     "childKey2": "childValue2", 
     "childKey3": "childValue3" }
}

class Egg { 
    @SerializedName("key1")
    private String mKey1;

    @SerializedName("key2")
    private String mKey2;

    @SerializedName("key3")
    // ???
}

I'm reading through the Gson docs but cannot figure out how to properly deserialize a dictionary to a Map.

Will Curran
  • 6,959
  • 15
  • 59
  • 92

2 Answers2

17

Gson readily handles deserialization of a JSON object with name:value pairs into a Java Map.

Following is such an example using the JSON from the original question. (This example also demonstrates using a FieldNamingStrategy to avoid specifying the serialized name for every field, provided that the field-to-element name mapping is consistent.)

import java.io.FileReader;
import java.lang.reflect.Field;
import java.util.Map;

import com.google.gson.FieldNamingStrategy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setFieldNamingStrategy(new MyFieldNamingStrategy());
    Gson gson = gsonBuilder.create();
    Egg egg = gson.fromJson(new FileReader("input.json"), Egg.class);
    System.out.println(gson.toJson(egg));
  }
}

class Egg
{
  private String mKey1;
  private String mKey2;
  private Map<String, String> mKey3;
}

class MyFieldNamingStrategy implements FieldNamingStrategy
{
  //Translates the Java field name into its JSON element name representation.
  @Override
  public String translateName(Field field)
  {
    String name = field.getName();
    char newFirstChar = Character.toLowerCase(name.charAt(1));
    return newFirstChar + name.substring(2);
  }
}
Programmer Bruce
  • 64,977
  • 7
  • 99
  • 97
  • How would you implement a Map in this case while specifying the serialized name? – Will Curran Jun 15 '11 at 21:53
  • I'm not sure what you're asking. The serialized name of what? The example I posted uses the custom FieldNamingStrategy to specify the serialized names of the JSON elements: that they are the same as the Java field names changed to not have the starting 'm' and changed so that the second character of the Java field name is made lower case and used as the first character of the JSON element name. – Programmer Bruce Jun 15 '11 at 23:01
  • Oh I see. That makes sense. But how do I define get/set methods to access childKey1, childKey2, and childKey3? – Will Curran Jun 16 '11 at 00:33
  • I'm not sure what you're asking. Those are the keys in the Map. Are you asking about how to get all of the keys in a Map? Why would you want to have a setter method for the Map keys? What would it do? Do you maybe not actually want a Map on the Java side, but instead have an object along the lines that Zuljin suggested? – Programmer Bruce Jun 16 '11 at 00:37
  • For some reason I thought you were suggesting that I still use a subclass but it implements Map. I see, it creates a Map property and then I can implement my own get methods that basically just grab the value from the Map for a corresponding key. I need to be able to get those properties out individually, so I need public access. – Will Curran Jun 16 '11 at 01:27
  • Right. I was just demonstrating what's necessary for Gson purposes. The example Egg class that I used is probably not complete enough for purposes other than Gson serialization/deserialization. The Egg class could certainly be defined to have a method such as public Map getKey3() {return mKey3;}. – Programmer Bruce Jun 16 '11 at 01:31
2

As far as I remember you should create separate class for each json object. Try something like this:

class Key { 
    @SerializedName("childKey1")
    private String mchildKey1;

    @SerializedName("childKey2")
    private String mchildKey2;

    @SerializedName("childKey3")
    private String mchildKey3;
}

class Egg { 
    @SerializedName("key1")
    private String mKey1;

    @SerializedName("key2")
    private String mKey2;

    @SerializedName("key3")
    private Key mKey3;
}

If this is not what you expected you can write your own serialize/deserialize adapter.

Zuljin
  • 2,612
  • 17
  • 14
  • I'll look into customized adapters. Thanks. – Will Curran Jun 15 '11 at 19:06
  • 3
    Note that it is not necessary to implement a custom deserializer to deserialize to a simple Map from a JSON object with name:value pairs. I posted a relevant example in another answer to this question. – Programmer Bruce Jun 15 '11 at 19:57