3

I am using protostuff binary with circular references and generics. As a very simplistic scenario i have the following classes:

    public class A {

    private String name;
    private B b;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
        this.b.setA(this);
    }
}

///////////////////////////////////////////////////////////////////////////////

public class B {

    private String name;
    private A a;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }
}

///////////////////////////////////////////////////////////////////////////////

public class Container<E> {
    private E element;
    private String name;

    public Container() {
    }

    public Container(E e, String name) {
        super();
        this.element = e;
        this.name = name;
    }

    public E getElement() {
        return element;
    }

    public void setElement(E e) {
        this.element = e;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

When i run the following unit test to check that the round trip serialisation / deserialisation has executed correctly i get a very odd result. the last assertion fails:

public class CircularRefTest {

    @Test
    public void testCircularReferences() {

        A a = new A();
        a.setName("a");
        B b = new B();
        b.setName("b");
        a.setB(b);
        Container<A> container = new Container<A>(a, "container");

        Schema<Container> schema = RuntimeSchema.getSchema(Container.class);
        LinkedBuffer buffer = LinkedBuffer.allocate(256);
        byte[] data = GraphIOUtil.toByteArray(container, schema, buffer);

        Container<A> copy = new Container<A>();
        GraphIOUtil.mergeFrom(data, copy, schema);

        assertEquals(container.getName(), copy.getName());
        assertEquals(container.getElement().getName(), copy.getElement().getName());
        assertEquals(container.getElement().getB().getName(), copy.getElement().getB().getName());

        // something weird happens here with the circular references here
        System.out.println(copy.getElement().getB().getA().getClass());
        assertTrue(copy.getElement().getB().getA() instanceof A); // fails
    }
}

Protostuff is corrupting the circular references from the child class back up to the parent. The last assertion should pass, but for some reason the class is of type Container.

What am i doing wrong ?

If i change the Container class to use strongly typed objects then the unit test passes. Is this a bug ??

The maven artifact i am using is:

<dependency>
        <groupId>com.dyuproject.protostuff</groupId>
        <artifactId>protostuff-api</artifactId>
        <version>1.0.4</version>
    </dependency>
komelgman
  • 6,949
  • 2
  • 18
  • 18
user1011782
  • 101
  • 5
  • I don't know about protocol buffers, but with WCF serialization it's necessarily to specifically set an attribute IsReference so that references to parent objects are correctly set (otherwise you would have ParentInstanceA -> ChildInstanceA -> ParentInstanceB instead of the child pointing back to the proper parent). Perhaps there's something similar with protocol buffers. – Eric J. Feb 01 '12 at 18:52
  • I couldnt see any reference to this in the Protostuff documentation http://code.google.com/p/protostuff/wiki/SerializingObjectGraphs – user1011782 Feb 01 '12 at 18:58
  • @Eric support for generics and circular references is not part of the google spec; protobuf-net and protostuff essentially cheat with extensions (that fit the wire spec); I have no idea if the approaches taken for the two are even remotely similar – Marc Gravell Feb 01 '12 at 19:40

1 Answers1

2

I looked very carefully through the full list of dependencies in my project, i found the following:

protostuff-api: 1.0.4
protostuff-collectionsschema: 1.0.2
protostuff-runtime: 1.0.2
protostuff-core: 1.0.2

I the 1.0.2 jars looked odd. I then deleted all the dependencies.

I then added the following dependencies:

 <dependency>
      <groupId>com.dyuproject.protostuff</groupId>
      <artifactId>protostuff-runtime</artifactId>
      <version>1.0.4</version>
    </dependency>
    <dependency>
      <groupId>com.dyuproject.protostuff</groupId>
      <artifactId>protostuff-core</artifactId>
      <version>1.0.4</version>
    </dependency>

This pulled in the following jars:

protostuff-api: 1.0.4
protostuff-collectionsschema: 1.0.4
protostuff-runtime: 1.0.4
protostuff-core: 1.0.4

I then re ran the unit test & everything worked !

Just to double check i ran the unit test with all the jars based on version 1.0.2, the test fails. It looks like this problem has been fixed in version 1.0.4

user1011782
  • 101
  • 5