Gson - 使用InstanceCreator即时设置对象引用

时间:2014-02-27 14:33:25

标签: java android gson on-the-fly

我遇到了一个问题,我需要在反序列化过程中使用GsonInstanceCreator设置我的对象被引用的引用。

为了描述问题,以下是类结构的简单表示。

public class Workshift {
    private final transient Context context;
    private final Visit visit;

    public Workshift(Context context) {
        this.context = context;
        this.visit = new Visit(this);
    }
}

public class Visit {
    private final transient Workshift workshift;

    public Visit(Workshift ws) {
        this.workshift = ws;
    }
}

通过这种结构,我可以通过向Context提供Workshift来设置InstanceCreator中的GsonBuilder,例如:

Gson gson = new GsonBuilder()
    .registerTypeAdapter(Workshift.class, new InstanceCreator<Workshift>() {
        @Override
        public Workshift createInstance(Type type) {
            return new Workshift(context);
        }
    })
    .create();

我知道,我可以向InstanceCreator添加额外的GsonBuilder,但我不确定如何提供正在解析的Workshift对象的引用(即时)到Visit对象?

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:1)

你绝对应该使用GraphAdapterBuilder

正如你在@Braj回答的评论中所说,

  由于某种原因

workshift 设置为瞬态,因此在序列化访问对象时它不会序列化此对象。如果没有标记   作为瞬态,然后序列化陷入堆栈溢出   例外 - 通过创建一个不可阻挡的循环

这有一个简单的解决方案。

<强> Workshift.java

public class Workshift {
    private final transient Context context;
    private final Visit visit;
    //for testing
    private String workshift_description;

    public Workshift(Context context,String id) {
        this.workshift_description=id;
        this.context = context;
        this.visit = new Visit(this);

    }
    public String getId() {
        return workshift_description;
    }

    public void setId(String id) {
        this.workshift_description = id;
    }
    public String toString() {
        return "[Workshift element => { WD: "+this.workshift_description+", VD : "+this.visit.getVisit_description()+"}";
    }
}

<强> Visit.java

public class Visit {

    private final /* transient  */ Workshift workshift;

    public Visit(Workshift ws) {
        this.workshift = ws;

    }
    public String getVisit_description() {
        return "visit containing  "+ workshift.getId();
    }

}

诀窍在于:

GsonBuilder gsonBuilder = new GsonBuilder();
        new GraphAdapterBuilder()
        .addType(Visit.class)
        .addType(Workshift.class)
        .registerOn(gsonBuilder);

全部放在一起,

public static void main(String[] args) {

        Workshift[] workshifts = new Workshift[10];
        for (int i = 0; i < workshifts.length; i++) {
            //Replace Context(i) for the real one
            workshifts[i] = new Workshift(new Context(i), "Workshift#"
                    + i);
        }
        System.out.println("Original Workshifts array:");
        for (int i = 0; i < workshifts.length; i++) {
            System.out.println(workshifts[i]);
        }
        System.out.println("===================================");

        GsonBuilder gsonBuilder = new GsonBuilder();
        new GraphAdapterBuilder()
        .addType(Visit.class)
        .addType(Workshift.class)
        .registerOn(gsonBuilder);

        Gson gson = gsonBuilder.setPrettyPrinting().create();
        String serialized = gson.toJson(workshifts);
        // System.out.println(serialized);
        Workshift[] w_array = gson.fromJson(serialized, Workshift[].class);
        // System.out.println(gson.toJson(w_array));

        System.out.println("Des-serialized Workshifts array:");
        for (int i = 0; i < w_array.length; i++) {
            System.out.println(w_array[i]);
        }
        System.out.println("===================================");

<强>输出:

Original Workshifts array:
[Workshift element => { WD: Workshift#0, VD : visit containing  Workshift#0}
[Workshift element => { WD: Workshift#1, VD : visit containing  Workshift#1}
[Workshift element => { WD: Workshift#2, VD : visit containing  Workshift#2}
[Workshift element => { WD: Workshift#3, VD : visit containing  Workshift#3}
[Workshift element => { WD: Workshift#4, VD : visit containing  Workshift#4}
[Workshift element => { WD: Workshift#5, VD : visit containing  Workshift#5}
[Workshift element => { WD: Workshift#6, VD : visit containing  Workshift#6}
[Workshift element => { WD: Workshift#7, VD : visit containing  Workshift#7}
[Workshift element => { WD: Workshift#8, VD : visit containing  Workshift#8}
[Workshift element => { WD: Workshift#9, VD : visit containing  Workshift#9}
===================================
Des-serialized Workshifts array:
[Workshift element => { WD: Workshift#0, VD : visit containing  Workshift#0}
[Workshift element => { WD: Workshift#1, VD : visit containing  Workshift#1}
[Workshift element => { WD: Workshift#2, VD : visit containing  Workshift#2}
[Workshift element => { WD: Workshift#3, VD : visit containing  Workshift#3}
[Workshift element => { WD: Workshift#4, VD : visit containing  Workshift#4}
[Workshift element => { WD: Workshift#5, VD : visit containing  Workshift#5}
[Workshift element => { WD: Workshift#6, VD : visit containing  Workshift#6}
[Workshift element => { WD: Workshift#7, VD : visit containing  Workshift#7}
[Workshift element => { WD: Workshift#8, VD : visit containing  Workshift#8}
[Workshift element => { WD: Workshift#9, VD : visit containing  Workshift#9}
===================================

没有StackOverflow错误。

如果您取消对该行的评论

// System.out.println(serialized);

输出如下:

[
  {
    "0x1": {
      "visit": "0x2",
      "workshift_description": "Workshift#0"
    },
    "0x2": {
      "workshift": "0x1"
    }
  },
  {
    "0x1": {
      "visit": "0x2",
      "workshift_description": "Workshift#1"
    },
    "0x2": {
      "workshift": "0x1"
    }
  },
  {
    "0x1": {
      "visit": "0x2",
      "workshift_description": "Workshift#2"
    },
    "0x2": {
      "workshift": "0x1"
    }
  },
  {
    "0x1": {
      "visit": "0x2",
      "workshift_description": "Workshift#3"
    },
    "0x2": {
      "workshift": "0x1"
    }
  },
  {
    "0x1": {
      "visit": "0x2",
      "workshift_description": "Workshift#4"
    },
    "0x2": {
      "workshift": "0x1"
    }
  },
  {
    "0x1": {
      "visit": "0x2",
      "workshift_description": "Workshift#5"
    },
    "0x2": {
      "workshift": "0x1"
    }
  },
  {
    "0x1": {
      "visit": "0x2",
      "workshift_description": "Workshift#6"
    },
    "0x2": {
      "workshift": "0x1"
    }
  },
  {
    "0x1": {
      "visit": "0x2",
      "workshift_description": "Workshift#7"
    },
    "0x2": {
      "workshift": "0x1"
    }
  },
  {
    "0x1": {
      "visit": "0x2",
      "workshift_description": "Workshift#8"
    },
    "0x2": {
      "workshift": "0x1"
    }
  },
  {
    "0x1": {
      "visit": "0x2",
      "workshift_description": "Workshift#9"
    },
    "0x2": {
      "workshift": "0x1"
    }
  }

这是因为Gson正在替换您的引用,以避免该堆栈溢出异常。这就像模拟指针

希望它有所帮助。

注意:请记住复制文件GraphAdapterBuilder.java并更改行

private final ConstructorConstructor constructorConstructor = new ConstructorConstructor();

private final ConstructorConstructor constructorConstructor = new ConstructorConstructor(instanceCreators);

否则将无法编译。也许它现在已经修好了。

答案 1 :(得分:0)

<强>问题:

目前,访问中的workshift字段在反序列化时结果为null。

<强>解决方案:

workshift字段是Visit类中的临时成员,并且不会序列化瞬态成员,这就是反序列化时获取空值的原因。

要解决此问题,您必须在反序列化后获取workshift对象后通过调用其setter方法手动设置访问类中的workshift引用。

反序列化时,你引用了对象的workshift和visit。 只需要通过工作转移的参考就可以解决它。

<强> Visit.java:

public class Visit {
    private final transient Workshift workshift;

    public Visit() {

    }

    public Workshift getWorkshift() {
        return workshift;
    }

    public void setWorkshift(Workshift workshift) {
        this.workshift = workshift;
    }

}

使用JsonDeserializer将workshift的引用设置为访问类。

示例代码:

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Type;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

    public class GSON {

        /**
         * @param args
         * @throws IOException
         * @throws ClassNotFoundException
         */
        public static void main(String[] args) throws Exception {
            // serialize
            Gson gson = new Gson();
            String json = gson.toJson(new Workshift());
            System.out.println("Workshift JSON:" + json);

            // deserialize
            GsonBuilder builder = new GsonBuilder();
            builder.registerTypeAdapter(Workshift.class, new WorkshiftDeserializer());

            Workshift workshift = builder.create().fromJson(json, Workshift.class);
            System.out.println("Reference of Workshift from Visit:"
                    + workshift.getVisit().getWorkshift());

        }

    }

    class Workshift implements Serializable {
        private Visit visit;

        public Workshift() {
            this.visit = new Visit(this);
        }

        public Visit getVisit() {
            return visit;
        }

        public void setVisit(Visit visit) {
            this.visit = visit;
        }

    }

    class Visit implements Serializable {
        private transient Workshift workshift;

        public Visit() {

        }

        public Visit(Workshift ws) {
            this.workshift = ws;
        }

        public Workshift getWorkshift() {
            return workshift;
        }

        public void setWorkshift(Workshift workshift) {
            this.workshift = workshift;
        }

    }


    class WorkshiftDeserializer implements JsonDeserializer<Workshift> {
        public Workshift deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
                throws JsonParseException {

            Gson gson = new Gson();

            Workshift workshift = gson.fromJson(json, Workshift.class);
            workshift.getVisit().setWorkshift(workshift);
            return workshift;
        }
    }