2017-06-19 17 views
0

GSONを使用してこのクラスを逆シリアル化するのは少し難しいです。 ここでは、リソースの抽象クラス最低料金:内部抽象クラスを持つコンテナクラスのGsonの逆シリアル化

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のインスタンスであることをgsonに知らせます。それ以外の場合は、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; 
    } 

} 

UPDATED

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リソースセットではなく、リソースセットでのエイリアライザ。私はこのjson文字列を逆シリアル化したいとします: '{" resourcesMap ":{" Wood ":{" quantity ":4}" Stone ":{" quantity ":2}}}' –

+0

1レベルアップ "し、' Map '自身を逆直列化します。私は私の答えにアップデートを加えて、私が何を言っているかを実証しました。 – hsl

関連する問題