1

I have objects in my game that I want to be able to serialize to JSON. The problem is that attempting to serialize them while they have a pointer that points to an "owner" object results in a stack overflow.

For example:

public class Entity
{

    Vector2 loc;
    Item item;

    public Entity(Vector2 loc)
    {

    this.loc = loc;
    this.item = new Item(this.loc, this);

    }

}


public class Item
{

    Vector2 loc;
    Entity owner;

    public Item(Vector2 loc, Entity owner)
    {

    this.loc = loc;
    this.owner = owner;

    }
}

If I then call

Json json = new Json();
System.out.println(json.prettyprint(instanceOfEntity));

I get a stack overflow.

I realize that this is likely an architecture problem, but I'm not sure of the best way to go about solving it. What is the solution to this problem?

  • Does it work if you remove the circular reference? That is, if you remove the pointer to owner from the Item class, do you still get the stack overflow? – Kurley Dec 12 '13 at 17:07
  • with serialization, normally you place attributes on objects that signify whether or not they will be serialized with the object – wes Dec 12 '13 at 17:07
  • @Kurley it works fine if I remove the pointer to the owner of the item, but then I'm unable to do things like instanceOfItem.getOwner().someFunction(). –  Dec 12 '13 at 17:15
  • This is a general programming question, and you're likely to get better responses from SO. –  Dec 12 '13 at 17:27
  • @chei you probably need to declare the owner pointer in a way that is ignored by the json serialiser. Otherwise you'll need to rearrange your code so there is no recursion when the object gets parsed. – Kurley Dec 12 '13 at 17:29
  • @chei Did we help you solve your issue? – everton Dec 20 '13 at 18:43

3 Answers3

1

Setting the Owner field as transient should do the trick, and avoid circular references on the serialization:

public class Item
{
    Vector2 loc;
    transient Entity owner;

    public Item(Vector2 loc, Entity owner)
    {
        this.loc = loc;
        this.owner = owner;
    }
}

How does marking a field as transient make it possible to serialise an object

Community
  • 1
  • 1
everton
  • 7,579
  • 2
  • 29
  • 42
  • he is using a json serializer that may not honor that, but there may be another way to indicate a transient connection – ratchet freak Dec 12 '13 at 18:41
  • 2
    In this case, he should really look up for a better one. This is the Java standard way to mark fields which should be ignored on serialization. – everton Dec 12 '13 at 19:15
1

Since this post was originally from gamedev exchange, I assume that you are using Libgdx's json parser since it looks like it.

If you implement the Json.Serializable interface in Libgdx, then you can customize your serialization by implementing the write method in which you specify how you are going to turn your object into json string. More information you can look at the libgdx tutorial. I also wrote a blog on how to use the Libgdx json parser.

Another solution is what the other said, remove the circular reference

1

I think the best way to address this is, is to remove your circular link by re-architeching your data structure in some way, maybe using some sort of map or table instead to link the Entity to the Item.

If you really must keep the circular references, then I'd recommend writing your own parser as simply ignoring the owner on serialization will mean the owner is not returned when the serialized objects are deserialized.

An example of how to write your own parser can be found on the LibGDX Google Code website:

Json json = new Json();
json.setSerializer(PhoneNumber.class, new Json.Serializer<PhoneNumber>() {
  public void write (Json json, PhoneNumber number, Class knownType) {
    json.writeObjectStart();
    json.writeValue(number.name, number.number);
    json.writeObjectEnd();
  }

   public PhoneNumber read (Json json, JsonValue jsonData, Class type) {
    PhoneNumber number = new PhoneNumber();
    number.setName(jsonData.child().name());
    number.setNumber(jsonData.child().asString());
    return number;
  }
});
json.setElementType(Person.class, "numbers", PhoneNumber.class);
String text = json.prettyPrint(person);
System.out.println(text);
Person person2 = json.fromJson(Person.class, text);
Kurley
  • 152
  • 1
  • 6