Gson - Setting object reference on-the-fly using InstanceCreator

后端 未结 2 1160
渐次进展
渐次进展 2020-12-18 09:27

I\'m stuck in a problem where I need to set reference of my object being parsed to its child objects during deserialization using Gson and InstanceCreator

2条回答
  •  天涯浪人
    2020-12-18 10:17

    You should definitely use GraphAdapterBuilder.

    As you said in the comment under @Braj 's answer,

    workshift is set transient for a reason so that it won't serialize this object when serializing visit object. If its not marked as transient then the serialization falls into stack overflow exception - by creating an unstoppable loop

    This has a simple solution.

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

    The trick resides here:

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

    Putting all together,

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

    Output:

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

    There's no StackOverflow error.

    if you un-comment the line

    // System.out.println(serialized);
    

    The output would be like this:

    [
      {
        "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"
        }
      }
    

    ]

    That's because Gson is replacing your references, in order to avoid that stack overflow exception. It's like emulating pointers

    Hope it helps.

    Note: Remember to copy the files GraphAdapterBuilder.java and change the line

    private final ConstructorConstructor constructorConstructor = new ConstructorConstructor();
    

    with

    private final ConstructorConstructor constructorConstructor = new ConstructorConstructor(instanceCreators);

    It won't compile otherwise. Maybe it's fixed right now.

提交回复
热议问题