I\'m requesting data from a server which returns data in the JSON format. Casting a HashMap into JSON when making the request wasn\'t hard at all but the other way seems to
Here you go:
import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;
Type type = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> myMap = gson.fromJson("{'k1':'apple','k2':'orange'}", type);
This code works:
Gson gson = new Gson();
String json = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
Map<String,Object> map = new HashMap<String,Object>();
map = (Map<String,Object>) gson.fromJson(json, map.getClass());
I had the exact same question and ended up here. I had a different approach that seems much simpler (maybe newer versions of gson?).
Gson gson = new Gson();
Map jsonObject = (Map) gson.fromJson(data, Object.class);
with the following json
{
"map-00": {
"array-00": [
"entry-00",
"entry-01"
],
"value": "entry-02"
}
}
The following
Map map00 = (Map) jsonObject.get("map-00");
List array00 = (List) map00.get("array-00");
String value = (String) map00.get("value");
for (int i = 0; i < array00.size(); i++) {
System.out.println("map-00.array-00[" + i + "]= " + array00.get(i));
}
System.out.println("map-00.value = " + value);
outputs
map-00.array-00[0]= entry-00
map-00.array-00[1]= entry-01
map-00.value = entry-02
You could dynamically check using instanceof when navigating your jsonObject. Something like
Map json = gson.fromJson(data, Object.class);
if(json.get("field") instanceof Map) {
Map field = (Map)json.get("field");
} else if (json.get("field") instanceof List) {
List field = (List)json.get("field");
} ...
It works for me, so it must work for you ;-)
Below is supported since gson 2.8.0
public static Type getMapType(Class keyType, Class valueType){
return TypeToken.getParameterized(HashMap.class, keyType, valueType).getType();
}
public static <K,V> HashMap<K,V> fromMap(String json, Class<K> keyType, Class<V> valueType){
return gson.fromJson(json, getMapType(keyType,valueType));
}
I have overcome a similar problem with a Custom JsonDeSerializer. I tried to make it a bit generic but still not enough. It is a solution though that fits my needs.
First of all you need to implement a new JsonDeserializer for Map objects.
public class MapDeserializer<T, U> implements JsonDeserializer<Map<T, U>>
And the deserialize method will look similar to this:
public Map<T, U> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (!json.isJsonObject()) {
return null;
}
JsonObject jsonObject = json.getAsJsonObject();
Set<Entry<String, JsonElement>> jsonEntrySet = jsonObject.entrySet();
Map<T, U> deserializedMap = new HashMap<T, U>();
for (Entry<java.lang.String, JsonElement> entry : jsonEntrySet) {
try {
U value = context.deserialize(entry.getValue(), getMyType());
deserializedMap.put((T) entry.getKey(), value);
} catch (Exception ex) {
logger.info("Could not deserialize map.", ex);
}
}
return deserializedMap;
}
The con with this solution, is that my Map's key is always of Type "String". However by chaning some things someone can make it generic. In addition, i need to say, that the value's class should be passed in the constructor. So the method getMyType()
in my code returns the type of the Map's values, which was passed in the constructor.
You can reference this post How do I write a custom JSON deserializer for Gson? in order to learn more about custom deserializers.
JSONObject typically uses HashMap
internally to store the data. So, you can use it as Map in your code.
Example,
JSONObject obj = JSONObject.fromObject(strRepresentation);
Iterator i = obj.entrySet().iterator();
while (i.hasNext()) {
Map.Entry e = (Map.Entry)i.next();
System.out.println("Key: " + e.getKey());
System.out.println("Value: " + e.getValue());
}