Saya tahu ini adalah pertanyaan yang cukup lama, tapi saya sedang mencari solusi untuk deserialize umum bersarang JSON ke Map<String, Object>, dan tidak menemukan apa pun.
Cara deserializer yaml saya berfungsi, default objek JSON Map<String, Object>ketika Anda tidak menentukan tipe, tetapi gson tampaknya tidak melakukan ini. Untungnya Anda dapat mencapainya dengan deserializer khusus.
Saya menggunakan deserializer berikut untuk secara alami deserialize apa pun, default JsonObjects ke Map<String, Object>dan JsonArrays ke Object[]s, di mana semua anak deserialized sama.
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;
}
}
Kekacauan dalam handlePrimitivemetode ini adalah untuk memastikan Anda hanya mendapatkan Double atau Integer atau Long, dan mungkin bisa lebih baik, atau setidaknya disederhanakan jika Anda baik-baik saja dengan mendapatkan BigDecimal, yang saya percaya adalah default.
Anda dapat mendaftarkan adaptor ini seperti:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Object.class, new NaturalDeserializer());
Gson gson = gsonBuilder.create();
Dan kemudian menyebutnya seperti:
Object natural = gson.fromJson(source, Object.class);
Saya tidak yakin mengapa ini bukan perilaku default di gson, karena itu di sebagian besar perpustakaan serialisasi semi-terstruktur ...
Map<String,Object> result = new Gson().fromJson(json, Map.class);bekerja dengan gson 2.6.2.