EASY VERSION
If I ask Gson to convert some valid json to MyMap it has no problem doing it
public class MyMap{
Map<Long,String> content;
}
MyMap myMap = gson.fromJson(json, new TypeToken<MyMap>() {}.getType());
HARD VERSION:
How do I get Gson to do the following?
public class MyDS{
Map<Map.Entry<Long,String>,Map<Long,String>> content;
}
MyDS myDS = gson.fromJson(json, new TypeToken<MyDS>() {}.getType());
Example json if you really need it.
"content": {
"[1, dog]": {
"1": "max",
"2": "pi",
"3": "robot",
"4": "catcher",
"5": "reaper"
},
"[2, cat]": {
"6": "black",
"7": "white",
"8": "meow",
"9": "mice",
"10": "rat"
},
"[3, rabbit]": {
"16": "bunny",
"17": "ears",
"28": "burgerbun",
"39": "alice",
"50": "tweak"
}
}
more notes
For good measure, I try to run a unit test where all I do is try to read the json with Gson, and I get the following error trace:
at sun.misc.Unsafe.allocateInstance(Native method)
java.lang.reflect.Method.invoke!(Native method)
com.google.gson.internal.UnsafeAllocator$1.newInstance(UnsafeAllocator.java:48)
com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:223)
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:207)
com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:186)
com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145)
com.google.gson.Gson.fromJson(Gson.java:861)
com.google.gson.Gson.fromJson(Gson.java:826)
com.google.gson.Gson.fromJson(Gson.java:775)
It does not matter if the keys are of the form "[3, rabbit]"
for "{3, rabbit}"
Assuming that you have a valid JSON
content of type:
{
"content": {
"[1, dog]": {
"1": "max",
"2": "pi",
"3": "robot",
"4": "catcher",
"5": "reaper"
},
"[2, cat]": {
"6": "black",
"7": "white",
"8": "meow",
"9": "mice",
"10": "rat"
},
"[3, rabbit]": {
"16": "bunny",
"17": "ears",
"28": "burgerbun",
"39": "alice",
"50": "tweak"
}
}
}
To achieve what you want, you could simply implement your own Map.Entry
Deserializer
since it cannot be deserialized out of the box because it is not an array and {3, rabbit}
is not a valid JSON
object.
So your Deserializer
could rely on a regular expression to extract the key and the value then create an instance of AbstractMap.SimpleEntry
using the extracted values, something like:
public class MapEntryDeserializer implements JsonDeserializer<Map.Entry<Long, String>> {
/**
* Pattern corresponding to:
* Starts with [
* <a non empty sequence of digit characters>,
* <a non empty sequence of any characters
* Ends with ]
*/
private static final Pattern PATTERN = Pattern.compile("^\\[(\\d+), ?(.+)\\]$");
public Map.Entry<Long, String> deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
// Extract the key/value pair from Strings of type [3, rabbit]
String value = json.getAsString();
Matcher matcher = PATTERN.matcher(value);
if (!matcher.find()) {
throw new JsonParseException(
String.format("The map entry doesn't have the expected format: %s", value)
);
}
return new AbstractMap.SimpleEntry<>(
Long.valueOf(matcher.group(1)), matcher.group(2)
);
}
}
I can then deserialize my JSON
content with:
Type type = new TypeToken<MyDS>() {}.getType();
Gson gson = new GsonBuilder()
.registerTypeAdapter(Map.Entry.class, new MapEntryDeserializer())
.create();
MyDS myDS = gson.fromJson(json, type);
According to the documentation for Map.Entry:
The only way to obtain a reference to a map entry is from the iterator of this collection-view.
https://docs.oracle.com/javase/8/docs/api/java/util/Map.Entry.html
This means you can't get the Map.Entry until you've created the initial Map. In order to achieve what you want you would need to parse the JSON into a Map, then iterate over it to insert it into your MyDS object.
Having said that, depending on your end use there might be better ways of re-organising/keying the data after parsing it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With