So che questa è una domanda abbastanza vecchia, ma stavo cercando una soluzione per deserializzare genericamente JSON nidificato in un Map<String, Object> e non trovato nulla.
Nel modo in cui funziona il mio deserializzatore yaml, per impostazione predefinita vengono impostati gli oggetti JSON Map<String, Object>quando non si specifica un tipo, ma gson non sembra farlo. Fortunatamente puoi realizzarlo con un deserializzatore personalizzato.
Ho usato il seguente deserializzatore al naturalmente deserializzare nulla, inadempiente JsonObjects per Map<String, Object>e JsonArrays per Object[]s, dove tutti i bambini sono in modo simile deserializzati.
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;
}
}
Il disordine all'interno del handlePrimitivemetodo è quello di assicurarti di ottenere sempre solo un Double, un Integer o un Long, e probabilmente potrebbe essere migliore, o almeno semplificato se stai bene con BigDecimals, che credo sia l'impostazione predefinita.
È possibile registrare questo adattatore come:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Object.class, new NaturalDeserializer());
Gson gson = gsonBuilder.create();
E poi chiamalo come:
Object natural = gson.fromJson(source, Object.class);
Non sono sicuro del perché questo non sia il comportamento predefinito in gson, poiché è presente nella maggior parte delle altre librerie di serializzazione semi-strutturate ...
Map<String,Object> result = new Gson().fromJson(json, Map.class);funziona con gson 2.6.2.