magro / kryo-serializers

More kryo serializers
Apache License 2.0
381 stars 120 forks source link

ImmutableMultimapSerializer does not properly handle EmptyImutableSetMultimap #119

Open fericit-bostan opened 5 years ago

fericit-bostan commented 5 years ago

Working with version 0.45, the ImmutableMultimapSerializer read method does not properly handle the class EmptyImmutableSetMultimap. It fails the statement at line 43.

The following statement always fails when the type is class com.google.common.collect.EmptyImmutableSetMultimap

else if (type.equals (ImmutableSetMultimap.class)) {

The if statement evaluates to false and the result is that an instance of EmptyImmutableListMultimap is returned instead, which does not match the datatype of ImmutableSetMultimap. This only occurs with an empty ImmutableSetMultimap.

If it were changed to the following: if(ImmutableSetMultimap.class.isAssignableFrom(type)) {

then it would pass and handle the type correctly.

I'm attaching a unit test that exhibits this behavior.

` import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.Kryo.DefaultInstantiatorStrategy; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.SetMultimap; import de.javakaffee.kryoserializers.guava.ImmutableMultimapSerializer; import org.junit.Before; import org.junit.Test; import org.objenesis.strategy.StdInstantiatorStrategy;

import java.io.Serializable; import java.util.Map;

import static org.junit.Assert.assertEquals;

public class ImmutableSetMultimapTestU { private Kryo kryo;

@Before
public void setup() {
    kryo = createKryoInstance();
}

@Test
public void testImmutableSetMutlimap() {
    // Create an EMPTY ImmutableSetMultimap (only happens when empty)
    ImmutableSetMultimap<String, String> thisIsAnEmptySet = ImmutableSetMultimap.of();
    MyTestClass toSerialize = new MyTestClass(thisIsAnEmptySet);

    // Serialize it using Kryo
    byte[] bytes = serialize(kryo, toSerialize);

    // Deserialize it using Kryo
    MyTestClass fromSerialize = (MyTestClass) deserialize(kryo, bytes);

    // It's an ImmutableListMultimap which is Inconvertible with ImmutableSetMultimap
    assertEquals(toSerialize.items.getClass(), fromSerialize.items.getClass());

    // And trying to iterate over this would fail hard
    for(Map.Entry<String, String> entry : fromSerialize.items.entries()) {
        System.out.println("Iteration fails hard with Exception");
    }
}

class MyTestClass implements Serializable {
    private SetMultimap<String, String> items;

    MyTestClass(SetMultimap<String, String> items) {
        this.items = items;
    }
}

public Object deserialize(Kryo kryo, byte[] in) {
    Object rv = null;
    try(Input input = new Input(in)) {
        rv = kryo.readClassAndObject(input);
    } catch(Exception e) {
        e.printStackTrace();
    }
    return rv;
}

public byte[] serialize(Kryo kryo, Object o) {
    byte[] rv = null;
    try(Output output = new Output(2048)) {
        kryo.writeClassAndObject(output, o);
        output.flush();
        rv = output.getBuffer();
    } catch(Exception e) {
        e.printStackTrace();
    }
    return rv;
}

private Kryo createKryoInstance() {
    Kryo kryo = new Kryo();
    kryo.setInstantiatorStrategy(new DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));

    ImmutableMultimapSerializer.registerSerializers(kryo);

    return kryo;
}

}`