Junfeic / kryo

Automatically exported from code.google.com/p/kryo
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

Deserialization problem for the classes which extend the implementation classes of Java collection #141

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
My test class extends ArrayList and has a _name attribute. By Kryo 
deserializer, the _name attribute stays null, can't be read correctly.

public class TestClassForList extends ArrayList<String>
{
  private static final long serialVersionUID = 8944285015775325886L;
  String _name;
  public String getName()
  {
    return _name;
  }

  public void setName( String name )
  {
    _name = name;
  }

  @Override
  public boolean equals( Object o )
  {
    TestClassForList obj = (TestClassForList) o;
    return super.equals( obj )  && _name.equals( obj.getName() );
  }
}

Test Method:
  @Test
  public void validateList()
  {
    TestClassForList testClass = new TestClassForList();
    testClass.add( "value" );
    testClass.setName( "name" );
    Kryo kryo = new Kryo();
    ByteArrayOutputStream os = new ByteArrayOutputStream();

    Output output = new Output( os );
    kryo.writeClassAndObject( output, testClass );
    output.flush();

    ByteArrayInputStream is = new ByteArrayInputStream( os.toByteArray() );
    Input input = new Input( is );
    TestClassForList readObject = (TestClassForList) kryo.readClassAndObject( input );

    assertEquals( testClass.getName(), readObject.getName() );
  }

The test failed with output:

java.lang.AssertionError: expected:<name> but was:<null>
    at org.junit.Assert.fail(Assert.java:91)
    at org.junit.Assert.failNotEquals(Assert.java:645)
    at org.junit.Assert.assertEquals(Assert.java:126)
    at org.junit.Assert.assertEquals(Assert.java:145)
    at blackboard.redis.serialization.KryoTest.validateList(KryoTest.java:61)

As to this problem, now we have to write a customised serializer which can set 
Name in read(...) method.
Although this can resolve issue, this still makes our code not reliable because 
we need to keep adding the customised serializer. 

Can this be resolved by kryo?

Original issue reported on code.google.com by yangzhao...@gmail.com on 18 Oct 2013 at 5:46

GoogleCodeExporter commented 9 years ago
I tested against kryo 2.22.

Original comment by yangzhao...@gmail.com on 18 Oct 2013 at 5:56

GoogleCodeExporter commented 9 years ago
You do not provide a custom serializer for your class. Therefore Kryo tries to 
guess a matching serializer. It correctly detects that your class is derived 
from ArrayList. Therefore it tries to use a corresponding default collection 
serializer which is able to serialize ArrayLists. The problem is that this 
serializer can serialize only vanilla collection classes, without any 
additional fields. 

Two solve your problem, I see two possibilities:
1) You create your own serializer for your class. It can be derived from a 
CollectionSerializer. Your serializer first performs super.write (super.read) 
and then writes/reads your additional field. Then you register your serializer 
to be used for your class.

2) You rewrite your class in such a way that it uses composition instead of 
inheritance. Done this way, it would contain two fields: one field containing 
an ArrayList and one field containing a name. Due to this changed structure, 
Kryo would use FieldSerializer for it and perform serialization properly.

I hope these suggestions help you to solve your problem.

Original comment by romixlev on 18 Oct 2013 at 7:33