Kryo and Bad Surprises

 

Jive uses the Kryo Framework to serialize and deserialize objects, typically serialization happens when objects are transferred to the remote Voldemort cache and back. Unfortunately serialization troubles caused by bad implementation mostly occur at runtime, which is a surprise I'd like to avoid.

 

Unittest

 

My colleague Lars Kreisz wrote a short Unittest to test the serialization of a single class, which was a good start. And so I thought "Why not test all the instances implementing Serializable automagically?". All we need for this is a Reflection library, and I chose Google Reflections, which can be added through the following dependency with scope test in your projects pom.xml:

<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.9-RC1</version>
<scope>test</scope>
</dependency>

 

And now for the JUnit test case, which works very well so far. What it does, briefly:

  • init Reflections library with the package name you want to scan for objects (line 22)
  • filter out only types Implementing Serializable (line 23)
  • iterate over every class, filter out the abstract types which can't be instantiated (line 29)
  • instantiate the class (line 31)
  • Serialize, Deserilze and check class

 

When there are any problems with the serialization (like included types that are not serializable them selfs, or missing default constructors), an exception from kryo is thrown and the test case is getting red.

 

import static org.junit.Assert.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.lang.reflect.Modifier;
import java.util.Set;

import org.junit.Test;
import org.reflections.Reflections;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;


public class ExperimentalSerializableTest {

 @Test
  public void test() throws Exception {
  Reflections r = new Reflections("com.your.root.package.goes.here");
  Set<Class<? extends Serializable>> classes = r.getSubTypesOf(Serializable.class);

  for (Class<? extends Serializable> clazz : classes) {

  System.out.println("Checking class " + clazz.getName());

  if (!Modifier.isAbstract(clazz.getModifiers())) {

  Object instance = clazz.newInstance();

  // Serialize to a byte array in ram.
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      Output ko = new Output(bos);
      Kryo kry = new Kryo();
      kry.writeObject(ko, instance);
      ko.flush();
     
      // Deserialize.
      ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
      Input ki = new Input(bis);
      Object deserialiedInstance = kry.readObject(ki, clazz);
     
      // check casting once more
      Object castedObject = clazz.cast(deserialiedInstance);
     
      // this has to be true then
      assertTrue(castedObject.getClass().equals(clazz));
  }
  }
  }

}








 

Happy to hear your thoughts at the comments. Cheers,

 

Mirko