ฉันรู้ว่านี่เป็นคำถามที่ค่อนข้างเก่า แต่ฉันกำลังค้นหาวิธีแก้ปัญหาโดยทั่วไปทำให้หมดความรู้สึก JSON ซ้อนกันเพื่อ Map<String, Object>
และไม่พบอะไรเลย
วิธีการทำงานของ deserializer yaml ของฉันมันเริ่มต้นวัตถุ JSON Map<String, Object>
เมื่อคุณไม่ได้ระบุประเภท แต่ gson ดูเหมือนจะไม่ทำเช่นนี้ โชคดีที่คุณสามารถทำได้ด้วย deserializer ที่กำหนดเอง
ฉันใช้ตัว deserializer ต่อไปนี้เพื่อทำให้เป็น deserialize ตามธรรมชาติโดยปริยายJsonObject
s Map<String, Object>
และJsonArray
s เป็นObject[]
s โดยที่เด็กทุกคนถูก deserialized ในทำนองเดียวกัน
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;
}
}
ความยุ่งเหยิงในhandlePrimitive
วิธีการนี้คือเพื่อให้แน่ใจว่าคุณจะได้รับ Double หรือ Integer หรือ Long เท่านั้นและอาจจะดีขึ้นหรืออย่างน้อยก็ง่ายขึ้นถ้าคุณโอเคกับการรับ BigDecimals ซึ่งฉันเชื่อว่าเป็นค่าเริ่มต้น
คุณสามารถลงทะเบียนอะแดปเตอร์นี้เช่น:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Object.class, new NaturalDeserializer());
Gson gson = gsonBuilder.create();
แล้วเรียกมันว่า:
Object natural = gson.fromJson(source, Object.class);
ฉันไม่แน่ใจว่าทำไมนี่ไม่ใช่พฤติกรรมเริ่มต้นใน gson เนื่องจากอยู่ในไลบรารีการทำให้เป็นอันดับกึ่งโครงสร้างอื่น ๆ ส่วนใหญ่ ...
Map<String,Object> result = new Gson().fromJson(json, Map.class);
ทำงานร่วมกับ gson 2.6.2