altoo-ag/akka-kryo-serialization

Using Arrays.asList() created lists causes NPE when deserializing

Closed this issue · 1 comments

When sending a message with a List<> property that was created with Arrays.asList a null pointer exception is thrown while deserializing. I've add a test to reproduce this problem.

ERROR c.b.c.c.c.a.i.s.ArrayListSerializationTest$TestActor - swallowing exception during message send
com.esotericsoftware.kryo.KryoException: java.lang.NullPointerException
Serialization trace:
strings (**.ArrayListSerializationTest$TestMessage)
at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:144) ~[kryo-3.0.3.jar:na]
at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:551) ~[kryo-3.0.3.jar:na]
at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:790) ~[kryo-3.0.3.jar:na]
at com.romix.akka.serialization.kryo.KryoBasedSerializer.fromBinary(KryoSerializer.scala:483) ~[akka-kryo-serialization_2.11-0.4.1.jar:na]
at com.romix.akka.serialization.kryo.KryoSerializer.fromBinary(KryoSerializer.scala:339) ~[akka-kryo-serialization_2.11-0.4.1.jar:na]
at akka.serialization.Serialization$$anonfun$deserialize$3.apply(Serialization.scala:142) ~[akka-actor_2.11-2.4.2.jar:na]
at scala.util.Try$.apply(Try.scala:192) ~[scala-library-2.11.7.jar:na]
at akka.serialization.Serialization.deserialize(Serialization.scala:142) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.dungeon.Dispatch$class.sendMessage(Dispatch.scala:128) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.ActorCell.sendMessage(ActorCell.scala:374) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.UnstartedCell$$anonfun$replaceWith$1.apply$mcV$sp(RepointableActorRef.scala:215) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.UnstartedCell$$anonfun$replaceWith$1.apply(RepointableActorRef.scala:197) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.UnstartedCell$$anonfun$replaceWith$1.apply(RepointableActorRef.scala:197) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.UnstartedCell.locked(RepointableActorRef.scala:285) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.UnstartedCell.replaceWith(RepointableActorRef.scala:196) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.RepointableActorRef.point(RepointableActorRef.scala:106) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.ActorCell.handleSupervise(ActorCell.scala:624) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.ActorCell.supervise(ActorCell.scala:616) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.ActorCell.invokeAll$1(ActorCell.scala:468) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.actor.ActorCell.systemInvoke(ActorCell.scala:483) ~[akka-actor_2.11-2.4.2.jar:na]
at akka.dispatch.Mailbox.processAllSystemMessages(Mailbox.scala:282) [akka-actor_2.11-2.4.2.jar:na]
at akka.dispatch.Mailbox.run(Mailbox.scala:223) [akka-actor_2.11-2.4.2.jar:na]
at akka.dispatch.Mailbox.exec(Mailbox.scala:234) [akka-actor_2.11-2.4.2.jar:na]
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) [scala-library-2.11.7.jar:na]
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) [scala-library-2.11.7.jar:na]
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) [scala-library-2.11.7.jar:na]
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) [scala-library-2.11.7.jar:na]
Caused by: java.lang.NullPointerException: null
at java.util.Arrays$ArrayList.size(Arrays.java:3818) ~[na:1.8.0_91]
at java.util.AbstractList.add(AbstractList.java:108) ~[na:1.8.0_91]
at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(CollectionSerializer.java:127) ~[kryo-3.0.3.jar:na]
at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(CollectionSerializer.java:40) ~[kryo-3.0.3.jar:na]
at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:708) ~[kryo-3.0.3.jar:na]
at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:125) ~[kryo-3.0.3.jar:na]
... 26 common frames omitted

Reproduction test:

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.testkit.JavaTestKit;
import org.junit.BeforeClass;
import org.junit.Test;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

/**
 * Created by bob on 6/27/16.
 */
public class ArrayListSerializationTest {


    private static ActorSystem system;

    @BeforeClass
    public static void setup() {
        system = ActorSystem.create("myAkkaCluster");
    }

    @Test
    public void asList(){
        TestMessage testMessage = new TestMessage(Arrays.asList("test1", "test2"));
        runTest(testMessage);
    }

    @Test
    public void arrayListConstructor(){
        List<String> strings = new ArrayList<>();
        strings.add("test1");
        strings.add("test2");
        TestMessage testMessage = new TestMessage(strings);
        runTest(testMessage);
    }

    private void runTest(TestMessage testMessage) {
        new JavaTestKit(system) {{
            ActorRef actorRef = system.actorOf(Props.create(TestActor.class));
            actorRef.tell(testMessage, getRef());
            String s = expectMsgClass(String.class);
            assertThat(s, is("test1"));

            String s1 = expectMsgClass(String.class);
            assertThat(s1, is("test2"));
        }};

    }

    public static class TestActor extends UntypedActor {

        @Override
        public void onReceive(Object message) throws Exception {
            TestMessage testMessage = (TestMessage) message;
            for (String s : testMessage.getStrings()) {
                getSender().tell(s, getSelf());
            }
        }
    }

    public static class TestMessage implements Serializable{

        public List<String> getStrings() {
            return strings;
        }

        private final List<String> strings;

        public TestMessage(List<String> strings) {
            this.strings = strings;
        }
    }
}

Currently fixed this by adding a custom kryo initializer (https://github.com/romix/akka-kryo-serialization#how-to-create-a-custom-initializer-for-kryo) and adding the serializers available in https://github.com/magro/kryo-serializers.