如何存储对象和维护组合

时间:2017-01-23 20:42:30

标签: java android gson

我有这些课程:

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);

问题在于A类中的对象B.Gson似乎并不知道B的类型。所以我得到了这个例外:

  

JNI在应用程序中检测到错误:无法创建类型的对象   复合

2 个答案:

答案 0 :(得分:2)

原因应该是Gson在A中看到和接口,而不是类。如果我没有弄错的话,Gson使用编译时信息(即变量的数据类型)而不是运行时信息(即包含B类对象的变量)。

如果您将类更改为以下内容,则应将其序列化为正确:

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

class B implements Composite
{
}

interface Composite
{
}

答案 1 :(得分:1)

问题是接口没有属性,因此您需要序列化实现该接口的类。您需要使用构建器

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

并定义序列化Composite实例的代码

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;
    }
}

基本上当它序列化一个Composite实例时,它也会将类名与属性一起存储,并且在反序列化它时会创建一个实际类的实例(比如说B)。这样你不必担心为每个实现Composite的类创建一个序列化器和反序列化器,但是如果你改变了类的名称(全名,包括包名),它就不能反序列化