2017-06-19 20 views
0

我發現使用GSON反序列化這個類有點困難。 從這裏資源抽象類開始:具有內部抽象類的容器類的Gson deserializaton

public abstract class Resource() { 
String id; 
Integer quantity; 
} 

public class Wood extends Resource { 
} 

public class Stone extends Resource{ 
} 

然後,我有一個容器類:

public class ResourceSet { 
Map<String, Resource> resourcesMap; 
} 

在地圖的關鍵是資源的ID,而值是資源本身。 我不知道如何正確地反序列化這個類,讓我們知道當他解析字符串「Wood」時,資源是Wood的一個實例。否則,gson使用抽象類的資源類的基礎構造函數,所以它給了我一個例外。

,我想反序列化可能是一個JSON字符串的一個例子:

{ 
"resourcesMap":{ 
       "Wood":{"quantity":4}, 
       "Stone":{"quantity":2} 
       } 
} 

回答

0

其中一個方案是爲您創造Resource類型的自定義解串器。在它中,使用JSON消息中的提示來決定Resource應該是什麼類型。

我不知道你的JSON消息是什麼樣子,但解決方案會是這個樣子:

public class ResourceDeserializer implements JsonDeserializer<Resource> { 

    @Override 
    public Resource deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     final JsonObject root = json.getAsJsonObject(); 

     final Resource resource; 

     if("wood".equalsIgnoreCase(root.get("type"))) { 
      resource = new WoodResource(); 
     } else { 
      resource = new StoneResource(); 
     } 

     return resource; 
    } 

} 

修訂

abstract class Resource { 
    protected String id; 
    protected Integer quantity; 
} 

class Wood extends Resource {} 

class Stone extends Resource {} 

class ResourceMap { 
    protected Map<String,Resource> resources; 

    ResourceMap() { 
     this.resources = new HashMap<>(); 
    } 
} 

class ResourceMapDeserializer implements JsonDeserializer<ResourceMap> { 

    @Override 
    public ResourceMap deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     final JsonObject root = json.getAsJsonObject(); 

     final ResourceMap instance = new ResourceMap(); 
     instance.resources.put("Wood", parse(root, "Wood")); 
     instance.resources.put("Stone", parse(root, "Stone")); 

     return instance; 
    } 

    private Resource parse(JsonObject root, String fieldName) { 
     final JsonElement field = root.get(fieldName); 

     if(field != null) { 
      final Resource resource; 

      if("Wood".equalsIgnoreCase(fieldName)) { 
       resource = new Wood(); 
      } else { 
       resource = new Stone(); 
      } 

      resource.quantity = field.getAsJsonObject().get("quantity").getAsInt(); 

      return resource; 

     } else { 
      return null; 
     } 
    } 

} 

簡單的驗證......

@RunWith(MockitoJUnitRunner.class) 
public class ResourceDeserializerTest { 

    @Mock private JsonDeserializationContext mockContext; 

    private Gson gson; 

    @Before 
    public void setUp() { 
     gson = new GsonBuilder() 
       .registerTypeAdapter(ResourceMap.class, new ResourceMapDeserializer()) 
       .setPrettyPrinting() 
       .create(); 
    } 

    @Test 
    public void deserializes_resource_map() { 
     final JsonObject woodJson = new JsonObject(); 
     woodJson.addProperty("quantity", 4); 

     final JsonObject stoneJson = new JsonObject(); 
     stoneJson.addProperty("quantity", 2); 

     final JsonObject mapJson = new JsonObject(); 
     mapJson.add("Wood", woodJson); 
     mapJson.add("Stone", stoneJson); 

     final ResourceMap deserialized = gson.fromJson(mapJson, ResourceMap.class); 

     assertThat(deserialized.resources.get("Wood").getClass()).isEqualTo(Wood.class); 

     assertThat(deserialized.resources.get("Stone").getClass()).isEqualTo(Stone.class); 
    } 

} 
+0

這是一個很好的迴應,但我的問題是,我想寫一個JSON DES資源集的erializer,而不是資源。想象一下,我想反序列化這個json字符串:'{「resources」:{「Wood」:{「quantity」:4},「Stone」:{「quantity」:2}}}' –

+0

在這種情況下,上一級「,並反序列化」Map 「本身。我已經添加了更新到我的答案來演示我在說什麼。 – hsl