2017-01-23 20 views
1

我有這些類:如何存儲對象和維護組成

class A implements Composite 
{ 
    Composite b = new B(); 
} 

class B implements Composite 
{ 
} 

interface Composite 
{ 
} 

基本上AB,我想它們存儲保持在這個文件組成。

在活動我這樣做:

String filename = "myfile.txt"; 

A a = new A(); 

Gson gson = new Gson(); 
String s = son.toJson(a); 

FileOutputStream outputStream; 
try 
{ 
    outputStream = openFileOutput(filename, Context.MODE_PRIVATE); 
    outputStream.write(s.getBytes); 
    outputStream.close(); 
} 
catch(Exception e) 
{ 
} 

然後我用這個代碼改爲:

FileInputStream fileInputStream = null; 
try 
{ 
    fileInputStream = openFileInput(filename); 
} 
catch(FileNotFoundException e) 
{} 

InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream)l; 
BufferReader bufferedReader = new BufferedReader(inputStreamReader); 
StringBuilder stringBuilder = new StringBuilder(); 

String line; 

try 
{ 
    while((line = bufferedReader.readLine()) != null) 
    { 
     stringBuilder.append(line); 
    } 
} 
catch(IOException e) 
{ 
} 

String json = stringBuilder.toString(); 
Gson gson2 = new Gson(); 

// Exception here. 
A a2 = gson2.fromJson(json, A.class); 

問題是與對象B類裏面A. GSON似乎並不要知道B的類型。所以,我得到這個異常:

JNI檢測應用程序錯誤:A,不是一個類中不能使 型複合

+0

我更新並測試了我的答案,你也可以找到完整的代碼[這裏](https://gist.github.com/lelloman/a009a8b7c863071551c6dbc2d0fdaa0d) – lelloman

回答

1

的問題是,接口沒有屬性,所以你需要序列化實現該接口的類。你需要有一個建設者

GsonBuilder builder = new GsonBuilder(); 
builder.registerTypeAdapter(Composite.class, new CompositeAdapter()); 
Gson gson = builder.create(); 

創建GSON實例,並定義代碼序列化的綜合情況

public static class CompositeAdapter implements JsonSerializer<Composite>, JsonDeserializer<Composite> { 

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

    public Composite deserialize(JsonElement jsonElement, Type type, 
         JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { 

     JsonObject jsonObject = jsonElement.getAsJsonObject(); 
     JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME); 
     String className = prim.getAsString(); 
     Class klass = null; 
     try { 
      klass = Class.forName(className); 
     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
      // TODO: handle somehow 
     } 
     return jsonDeserializationContext.deserialize(jsonObject.get(DATA), klass); 
    } 

    public JsonElement serialize(Composite jsonElement, Type type, JsonSerializationContext jsonSerializationContext) { 
     JsonObject jsonObject = new JsonObject(); 
     jsonObject.addProperty(CLASSNAME, jsonElement.getClass().getName()); 
     jsonObject.add(DATA, jsonSerializationContext.serialize(jsonElement)); 
     return jsonObject; 
    } 
} 

基本上當它與一起串行化一個複合比如,它也將存儲類名屬性以及反序列化時會創建實際類的實例(如B)。這樣您就不必擔心爲實現Composite的每個類創建序列化器和反序列化器,但是如果更改類的名稱(全名,包括包名稱),將無法反序列化它

2

的原因應該是GSON看到和接口的對象。如果我沒有弄錯,Gson使用編譯時間信息(即變量的數據類型)而不是運行時信息(即包含B類對象的變量)。

如果你改變你的類以下,應該就好了連載:

class A implements Composite 
{ 
    B b = new B(); 
} 

class B implements Composite 
{ 
} 

interface Composite 
{ 
} 
+0

這應該工作,但我想代碼到接口而不是具體類。 –

+0

在這種情況下,您可以爲A級編寫自己的串行器。 https://github.com/google/gson/blob/master/UserGuide.md#TOC-Writing-a-Serializer – Ray