Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
296 views
in Technique[技术] by (71.8m points)

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

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.

To depict the problem, following is the simple representation of classes' structure.

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

With this structure, I am able to set Context in Workshift by providing an InstanceCreator to my GsonBuilder, for example:

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

I know, I can add additional InstanceCreator to my GsonBuilder, but I'm not sure how to provide a reference of my Workshift object which is in the process of being parsed (on-the-fly) to Visit object?

Any help would be appreciated!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...