2016-09-25 9 views
0

良い一日私の仲間の開発者と呼ばれていません。私はJsonの文字列にオブジェクトのリストをシリアル化しようとしているが、運がない。私の継承階層は次のようになります。アンドロイドgson AbstractAdapter.serializeは、(ポリモーフィックシリアライズ)

interface IFloorPlanPrimitive 
abstract class FloorPlanPrimitiveBase implements IFloorPlanPrimitive 
class Wall extends FloorPlanPrimitiveBase 
class Mark extends FloorPlanPrimitiveBase 

かなり簡単です。各クラスにはいくつかのフィールドがあります。私はウェブ上の問題を検索し、シリアライズ/デシリアライズを容易にするためにこのアダプタクラスを追加しました。現在、私はシリアル化することができませんので、それに焦点を当てましょう。

public class FloorPlanPrimitiveAdapter implements 
     JsonSerializer<FloorPlanPrimitiveBase>, JsonDeserializer<FloorPlanPrimitiveBase> { 

    @Override 
    public JsonElement serialize(FloorPlanPrimitiveBase src, Type typeOfSrc, JsonSerializationContext context) { 
     JsonObject result = new JsonObject(); 
     result.add("type", new JsonPrimitive(src.getClass().getSimpleName())); 
     result.add("properties", context.serialize(src, src.getClass())); 

     return result; 
    } 

    @Override 
    public FloorPlanPrimitiveBase deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     JsonObject jsonObject = json.getAsJsonObject(); 
     String type = jsonObject.get("type").getAsString(); 
     JsonElement element = jsonObject.get("properties"); 

     try { 
      final String packageName = IFloorPlanPrimitive.class.getPackage().getName(); 
      return context.deserialize(element, Class.forName(packageName + '.' + type)); 
     } catch (ClassNotFoundException cnfe) { 
      throw new JsonParseException("Unknown element type: " + type, cnfe); 
     } 
    } 
} 

そして、これは私がそれを使用する方法です:私はシリアライズので、私はそれらの「タイプ」を取得していないときFloorPlanPrimitiveAdapterserializeメソッドが呼び出されていないことがわかり、簡単なデバッグから

public String getFloorPlanAsJSon() { 
    GsonBuilder gsonBilder = new GsonBuilder(); 
    gsonBilder.registerTypeAdapter(FloorPlanPrimitiveBase.class, new FloorPlanPrimitiveAdapter()); 
    Gson gson = gsonBilder.create(); 

    List<IFloorPlanPrimitive> floorPlan = mRenderer.getFloorPlan(); 
    String jsonString = gson.toJson(floorPlan); 

    return jsonString; 
} 

Jsonの "properties"フィールドを使用します。代わりに、私はストレートフォワードJsonの文字列を取得します。これはタイプの不一致によるものだと思います。私はIFloorPlanPrimitiveをシリアル化するように求めていますが、代わりにこのインターフェイスを実装するFloorPlanPrimitiveBaseを渡します。私の期待は、それが動作するはずでした:)

誰もこの状況でシリアル化とデシリアライズを処理する方法を指摘できますか?その "ミスマッチ"を克服する方法は?

ありがとうございました。

親切、グレッグ。

答えて

0

おはよう、

自分の解決策を自分の問題に分けたいと思っています。これが他の人に役立つことを願っています。また、このソリューションに欠陥があるかどうかを知りたいと思います。

だから、まず使い方。私はSOに関する別の答えを見ました(下にリンクしています)。またGson githubの上のthis問題も(特に私はtoJson()メソッドに型パラメータを渡すことが有用学びました:

public String getFloorPlanAsJSon() { 
    GsonBuilder builder = new GsonBuilder(); 

    final Type type = (new TypeToken<List<FloorPlanPrimitiveBase>>() {}).getType(); 
    builder.registerTypeAdapter(type, new FloorPlanAdapter()); 
    Gson gson = builder.create(); 

    List<IFloorPlanPrimitive> floorPlan = mRenderer.getFloorPlan(); 
    String jsonString = gson.toJson(floorPlan, type); 

    return jsonString; 
} 

そして今、私は実際にはSO(答え、それはそれでバグがあり、注意してくださいthisから取ったAdapter - JSONに入れ、クラスの名前ArrayListの代わりの要素のクラスです):

public class FloorPlanAdapter implements JsonSerializer<List<FloorPlanPrimitiveBase>> { 

    private static final String CLASSNAME = "CLASSNAME"; 
    private static final String INSTANCE = "INSTANCE"; 

    @Override 
    public JsonElement serialize(List<FloorPlanPrimitiveBase> src, Type typeOfSrc, 
           JsonSerializationContext context) { 
     JsonArray array = new JsonArray(); 

     for (FloorPlanPrimitiveBase primitiveBase : src) { 
      JsonObject primitiveJson = new JsonObject(); 

      String className = primitiveBase.getClass().getCanonicalName(); 
      primitiveJson.addProperty(CLASSNAME, className); 

      JsonElement elem = context.serialize(primitiveBase); 
      primitiveJson.add(INSTANCE, elem); 

      array.add(primitiveJson); 
     } 
     return array; 
    } 
} 

あなたはそれがList<>内のすべてのオブジェクトの上にループし、ちょうど私の元の質問でFloorPlanPrimitiveBaseAdapterのようにそれを処理して見ることができるように

これは私がそれを逆シリアル化する方法です:

@Override 
public List<FloorPlanPrimitiveBase> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
    final String packageName = IFloorPlanPrimitive.class.getPackage().getName(); 
    List<FloorPlanPrimitiveBase> result = new ArrayList<>(); 
    JsonArray jsonArray = json.getAsJsonArray(); 

    for (JsonElement element : jsonArray) { 
     final JsonObject asJsonObject = element.getAsJsonObject(); 
     String className = asJsonObject.get(CLASSNAME).getAsString(); 
     JsonElement serializedInstance = asJsonObject.get(INSTANCE); 

     Class<?> klass; 
     try { 
      klass = Class.forName(packageName + '.' + className); 
      final FloorPlanPrimitiveBase deserializedInstance = context.deserialize(serializedInstance, klass); 
      result.add(deserializedInstance); 
     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } 
    } 
    return result; 
}