Ich weiß, dass dies eine ziemlich alte Frage ist, aber ich suchte nach einer Lösung, um verschachtelten JSON generisch in a zu deserialisieren Map<String, Object>
, und fand nichts.
So wie mein yaml-Deserializer funktioniert, werden JSON-Objekte standardmäßig verwendet, Map<String, Object>
wenn Sie keinen Typ angeben, aber gson scheint dies nicht zu tun. Glücklicherweise können Sie dies mit einem benutzerdefinierten Deserializer erreichen.
Ich habe den folgenden Deserializer verwendet, um alles auf natürliche Weise zu deserialisieren, wobei standardmäßig JsonObject
s bis s Map<String, Object>
und JsonArray
s bis Object[]
s verwendet werden, wobei alle Kinder auf ähnliche Weise deserialisiert werden.
private static class NaturalDeserializer implements JsonDeserializer<Object> {
public Object deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) {
if(json.isJsonNull()) return null;
else if(json.isJsonPrimitive()) return handlePrimitive(json.getAsJsonPrimitive());
else if(json.isJsonArray()) return handleArray(json.getAsJsonArray(), context);
else return handleObject(json.getAsJsonObject(), context);
}
private Object handlePrimitive(JsonPrimitive json) {
if(json.isBoolean())
return json.getAsBoolean();
else if(json.isString())
return json.getAsString();
else {
BigDecimal bigDec = json.getAsBigDecimal();
// Find out if it is an int type
try {
bigDec.toBigIntegerExact();
try { return bigDec.intValueExact(); }
catch(ArithmeticException e) {}
return bigDec.longValue();
} catch(ArithmeticException e) {}
// Just return it as a double
return bigDec.doubleValue();
}
}
private Object handleArray(JsonArray json, JsonDeserializationContext context) {
Object[] array = new Object[json.size()];
for(int i = 0; i < array.length; i++)
array[i] = context.deserialize(json.get(i), Object.class);
return array;
}
private Object handleObject(JsonObject json, JsonDeserializationContext context) {
Map<String, Object> map = new HashMap<String, Object>();
for(Map.Entry<String, JsonElement> entry : json.entrySet())
map.put(entry.getKey(), context.deserialize(entry.getValue(), Object.class));
return map;
}
}
Die Unordnung in der handlePrimitive
Methode besteht darin, sicherzustellen, dass Sie immer nur ein Double oder ein Integer oder ein Long erhalten und wahrscheinlich besser oder zumindest vereinfacht sein könnten, wenn Sie mit BigDecimals einverstanden sind, was meiner Meinung nach die Standardeinstellung ist.
Sie können diesen Adapter wie folgt registrieren:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Object.class, new NaturalDeserializer());
Gson gson = gsonBuilder.create();
Und dann nenne es wie:
Object natural = gson.fromJson(source, Object.class);
Ich bin mir nicht sicher, warum dies nicht das Standardverhalten in gson ist, da es in den meisten anderen halbstrukturierten Serialisierungsbibliotheken vorkommt ...
Map<String,Object> result = new Gson().fromJson(json, Map.class);
funktioniert mit gson 2.6.2.