当前位置: 首页 > 知识库问答 >
问题:

Gson-使用InstanceCreator动态设置对象引用

邵阳
2023-03-14

我陷入了一个问题,需要在反序列化过程中使用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;
    }
}

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

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

我知道,我可以添加额外的InstanceCreator到我的GsonBuilder,但我不知道如何提供我的WorkShift对象的引用,该对象正在被解析(即时)到访问对象?

任何帮助将不胜感激!

共有2个答案

麹耘豪
2023-03-14

问题:

目前,当反序列化时,访问中的工作班字段被证明为空。

解决方案:

workshift字段是Visit类中的临时成员,临时成员不会被序列化,这就是为什么在反序列化时会得到空值的原因。

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

反序列化后,您可以引用对象轮班和访问。只需要通过轮班访问的引用就可以解决。

访问.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将工作班次的引用设置为访问类。

示例代码:

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;
        }
    }
葛霄
2023-03-14

您绝对应该使用GraphAdapterBuilder。

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

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()+"}";
    }
}

访问.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();

具有

私有最终构造函数构造函数构造函数 = 新构造函数构造函数(实例创建者);

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

 类似资料:
  • 问题内容: 我被困在我需要我的对象的设定参考使用反序列化过程中被解析到其子对象的问题和。 为了描述这个问题,下面是类结构的简单表示。 通过这样的结构,我能够设置在通过提供给我的,例如: 我知道,我可以添加额外的给我,但我不知道如何提供我的参考对象,它是在被解析(上即时)的进程对象? 任何帮助,将不胜感激! 问题答案: 您绝对应该使用GraphAdapterBuilder。 正如您在@Braj的回答

  • 问题内容: 我有一个名为的类,该类具有一个作为参数的构造函数: 具有以下属性: 并且是我的应用程序的其他类,并具有以下构造函数: ,并且是的子类。 我想用Gson 反序列化数组,所以我写道: 以定义为: 调试时,实例具有正确的“ MainActivity”作为上下文,而其成员变量的上下文为null。 Gson 使用正确的构造函数创建了对象,但使用默认的无参数构造函数创建了实例。我怎样才能解决这个问

  • 我有一个名为PageItem的类,它有一个构造函数,该构造函数将上下文作为参数: 具有以下属性: 新闻提供者(Newsprovider)和主题(Topic)是我的应用程序的其他类,具有以下构造函数:

  • 问题内容: 我正在构建一个API应用程序,该应用程序实质上允许用户构建一个文档,该文档可以按他们想要的方式进行结构化,并将存储在Elasticsearch中。本质上,我为用户提供了一个简单的界面来访问我们的Elasticsearch实例。我试图使实现尽可能简单。到目前为止,这是我要处理的内容。 预期主体的对象: 简单实施: 这可以正常工作,但它在源中包含索引,类型和ID。我真正想做的只是在建立索引

  • 由于几个循环引用,我遇到了通过GoogleGSON序列化Java对象的问题。我的所有尝试都以StackOverflowException结束,因为GSON无法处理这些循环引用。 作为一个解决方案,我发现了以下: http://code.google.com/p/google-gson/source/browse/trunk/extras/src/main/java/com/google/gson/

  • 我有以下POJO: 我可以让GSON将ShapeHolder的实例序列化到JSON。但是当我试图将JSON的字符串反序列化回实例时,我得到错误: 抛出: 所以我看了这里,开始实现我自己的: 但现在我被困住了:我只得到了一个,但我真的需要一个这样我就可以编写如下代码: 我能做什么? 根据@raffian的建议(他/她发布的链接),我实现了一个,与链接中的完全相同(我没有做任何更改)。现在我得到了以下