diff --git a/README.markdown b/README.markdown index 570b736f..b5f58a99 100644 --- a/README.markdown +++ b/README.markdown @@ -31,6 +31,9 @@ A project that provides [kryo](https://github.com/EsotericSoftware/kryo) (v2 and * UnmodifiableCollectionsSerializer - for unmodifiable Collections and Maps created via Collections.unmodifiable*. * cglib/CGLibProxySerializer - serializer for CGLib proxies +* dexx/ListSerializer - serializer for dexx-collections' List +* dexx/SetSerializer - serializer for dexx collecttions' Set +* dexx/MapSerializer - serializer for dexx collections' Map * guava/ArrayListMultimapSerializer - serializer for guava-libraries' ArrayListMultimap * guava/HashMultimapSerializer -- serializer for guava-libraries' HashMultimap * guava/ImmutableListSerializer - serializer for guava-libraries' ImmutableList @@ -50,7 +53,6 @@ A project that provides [kryo](https://github.com/EsotericSoftware/kryo) (v2 and * protobuf/ProtobufSerializer - serializer for protobuf GeneratedMessages * wicket/MiniMapSerializer - serializer for wicket's MiniMap - # Usage To be able to use the serializers you have to add the jar to your classpath. If your build tool support maven repositories you can use this dependency: @@ -81,6 +83,10 @@ After that's done you can register the custom serializers at the kryo instance. // register CGLibProxySerializer, works in combination with the appropriate action in handleUnregisteredClass (see below) kryo.register( CGLibProxySerializer.CGLibProxyMarker.class, new CGLibProxySerializer( kryo ) ); + // dexx + ListSerializer.registerSerializers( kryo ); + MapSerializer.registerSerializers( kryo ); + SetSerializer.registerSerializers( kryo ); // joda DateTime, LocalDate and LocalDateTime kryo.register( DateTime.class, new JodaDateTimeSerializer() ); kryo.register( LocalDate.class, new JodaLocalDateSerializer() ); @@ -94,7 +100,7 @@ After that's done you can register the custom serializers at the kryo instance. ImmutableSetSerializer.registerSerializers( kryo ); ImmutableMapSerializer.registerSerializers( kryo ); ImmutableMultimapSerializer.registerSerializers( kryo ); - ReverseListSerializer.registerSerializers(_kryo); + ReverseListSerializer.registerSerializers( kryo ); UnmodifiableNavigableSetSerializer.registerSerializers( kryo ); // guava ArrayListMultimap, HashMultimap, LinkedHashMultimap, LinkedListMultimap, TreeMultimap ArrayListMultimapSerializer.registerSerializers( kryo ); diff --git a/pom.xml b/pom.xml index 4f5b46f8..7ba25b11 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,6 @@ 4.0.0 - + org.sonatype.oss @@ -215,6 +215,12 @@ 17.0 true + + com.github.andrewoma.dexx + collection + 0.6 + true + diff --git a/src/main/java/de/javakaffee/kryoserializers/dexx/ListSerializer.java b/src/main/java/de/javakaffee/kryoserializers/dexx/ListSerializer.java new file mode 100644 index 00000000..d113b290 --- /dev/null +++ b/src/main/java/de/javakaffee/kryoserializers/dexx/ListSerializer.java @@ -0,0 +1,70 @@ +package de.javakaffee.kryoserializers.dexx; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.Serializer; +import com.esotericsoftware.kryo.io.Input; +import com.esotericsoftware.kryo.io.Output; + +import com.github.andrewoma.dexx.collection.IndexedLists; +import com.github.andrewoma.dexx.collection.List; + +/** + * A kryo {@link Serializer} for dexx {@link List} + */ +public class ListSerializer extends Serializer { + + private static final boolean DOES_NOT_ACCEPT_NULL = true; + private static final boolean IMMUTABLE = true; + + public ListSerializer() { + super(DOES_NOT_ACCEPT_NULL, IMMUTABLE); + } + + @Override + public void write(Kryo kryo, Output output, List object) { + output.writeInt(object.size(), true); + for (Object elm : object) { + kryo.writeClassAndObject(output, elm); + } + } + + @Override + public List read(Kryo kryo, Input input, Class aClass) { + final int size = input.readInt(true); + final Object[] list = new Object[size]; + for (int i = 0; i < size; ++i) { + list[i] = kryo.readClassAndObject(input); + } + return IndexedLists.copyOf(list); + } + + /** + * Creates a new {@link ImmutableListSerializer} and registers its serializer + * + * @param kryo the {@link Kryo} instance to set the serializer on + */ + public static void registerSerializers(final Kryo kryo) { + + final ListSerializer serializer = new ListSerializer(); + + kryo.register(List.class, serializer); + + // Note: + // Only registering above is good enough for serializing/deserializing. + // but if using Kryo#copy, following is required. + + kryo.register(IndexedLists.of().getClass(), serializer); + kryo.register(IndexedLists.of(1).getClass(), serializer); + kryo.register(IndexedLists.of(1,2).getClass(), serializer); + kryo.register(IndexedLists.of(1,2,3).getClass(), serializer); + kryo.register(IndexedLists.of(1,2,3,4).getClass(), serializer); + kryo.register(IndexedLists.of(1,2,3,4,5).getClass(), serializer); + kryo.register(IndexedLists.of(1,2,3,4,5,6).getClass(), serializer); + kryo.register(IndexedLists.of(1,2,3,4,5,6,7).getClass(), serializer); + kryo.register(IndexedLists.of(1,2,3,4,5,6,7,8).getClass(), serializer); + kryo.register(IndexedLists.of(1,2,3,4,5,6,7,8,9).getClass(), serializer); + kryo.register(IndexedLists.of(1,2,3,4,5,6,7,8,10).getClass(), serializer); + kryo.register(IndexedLists.of(1,2,3,4,5,6,7,8,10,11).getClass(), serializer); + + } +} diff --git a/src/main/java/de/javakaffee/kryoserializers/dexx/MapSerializer.java b/src/main/java/de/javakaffee/kryoserializers/dexx/MapSerializer.java new file mode 100644 index 00000000..ff796f38 --- /dev/null +++ b/src/main/java/de/javakaffee/kryoserializers/dexx/MapSerializer.java @@ -0,0 +1,73 @@ +package de.javakaffee.kryoserializers.dexx; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.Serializer; +import com.esotericsoftware.kryo.io.Input; +import com.esotericsoftware.kryo.io.Output; + +import com.github.andrewoma.dexx.collection.Map; +import com.github.andrewoma.dexx.collection.Maps; +import com.github.andrewoma.dexx.collection.Pair; + +import java.util.HashMap; +import java.util.ArrayList; +import java.util.Map.Entry; +import java.util.Iterator; + +/** +* A kryo {@link Serializer} for dexx {@link Map} + */ +public class MapSerializer extends Serializer> { + + private static final boolean DOES_NOT_ACCEPT_NULL = true; + private static final boolean IMMUTABLE = true; + + public MapSerializer() { + super(DOES_NOT_ACCEPT_NULL, IMMUTABLE); + } + + @Override + public void write(Kryo kryo, Output output, Map immutableMap) { + kryo.writeObject(output, immutableMap.asMap()); + } + + @Override + public Map read(Kryo kryo, Input input, Class> type) { + HashMap map = kryo.readObject(input, HashMap.class); + ArrayList> listOfPairs = new ArrayList(); + + for (Entry entry : map.entrySet()) { + Pair pair = new Pair(entry.getKey(), entry.getValue()); + listOfPairs.add(pair); + } + + return Maps.copyOf(listOfPairs); + } + + /** + * Creates a new {@link ImmutableMapSerializer} and registers its serializer + * for the several ImmutableMap related classes. + * + * @param kryo the {@link Kryo} instance to set the serializer on + */ + public static void registerSerializers(final Kryo kryo) { + + final MapSerializer serializer = new MapSerializer(); + + kryo.register(Map.class, serializer); + kryo.register(Maps.of().getClass(), serializer); + + Object o1 = new Object(); + Object o2 = new Object(); + Object o3 = new Object(); + Object o4 = new Object(); + Object o5 = new Object(); + + kryo.register(Maps.of(o1, o1).getClass(), serializer); + kryo.register(Maps.of(o1, o1, o2, o2).getClass(), serializer); + kryo.register(Maps.of(o1, o1, o2, o2, o3, o3).getClass(), serializer); + kryo.register(Maps.of(o1, o1, o2, o2, o3, o3, o4, o4).getClass(), serializer); + kryo.register(Maps.of(o1, o1, o2, o2, o3, o3, o4, o4, o5, o5).getClass(), serializer); + + } +} diff --git a/src/main/java/de/javakaffee/kryoserializers/dexx/SetSerializer.java b/src/main/java/de/javakaffee/kryoserializers/dexx/SetSerializer.java new file mode 100644 index 00000000..4a0e7b06 --- /dev/null +++ b/src/main/java/de/javakaffee/kryoserializers/dexx/SetSerializer.java @@ -0,0 +1,71 @@ +package de.javakaffee.kryoserializers.dexx; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.Serializer; +import com.esotericsoftware.kryo.io.Input; +import com.esotericsoftware.kryo.io.Output; + +import com.github.andrewoma.dexx.collection.Builder; +import com.github.andrewoma.dexx.collection.Set; +import com.github.andrewoma.dexx.collection.Sets; + +/** +* A kryo {@link Serializer} for dexx {@link Set} + */ +public class SetSerializer extends Serializer> { + + private static final boolean DOES_NOT_ACCEPT_NULL = false; + private static final boolean IMMUTABLE = true; + + public SetSerializer() { + super(DOES_NOT_ACCEPT_NULL, IMMUTABLE); + } + + @Override + public void write(Kryo kryo, Output output, Set object) { + output.writeInt(object.size(), true); + for (Object elm : object) { + kryo.writeClassAndObject(output, elm); + } + } + + @Override + public Set read(Kryo kryo, Input input, Class> type) { + final int size = input.readInt(true); + Builder> builder = Sets.builder(); + for (int i = 0; i < size; ++i) { + builder.add(kryo.readClassAndObject(input)); + } + return builder.build(); + } + + /** + * Creates a new {@link ImmutableSetSerializer} and registers its serializer + * for the several ImmutableSet related classes. + * + * @param kryo the {@link Kryo} instance to set the serializer on + */ + public static void registerSerializers(final Kryo kryo) { + + final SetSerializer serializer = new SetSerializer(); + + kryo.register(Set.class, serializer); + + // Note: + // Only registering above is good enough for serializing/deserializing. + // but if using Kryo#copy, following is required. + + kryo.register(Sets.of().getClass(), serializer); + kryo.register(Sets.of(1).getClass(), serializer); + kryo.register(Sets.of(1,2,3).getClass(), serializer); + kryo.register(Sets.of(1,2,3,4).getClass(), serializer); + kryo.register(Sets.of(1,2,3,4,5).getClass(), serializer); + kryo.register(Sets.of(1,2,3,4,5,6).getClass(), serializer); + kryo.register(Sets.of(1,2,3,4,5,6,7).getClass(), serializer); + kryo.register(Sets.of(1,2,3,4,5,6,7,8).getClass(), serializer); + kryo.register(Sets.of(1,2,3,4,5,6,7,8,9).getClass(), serializer); + kryo.register(Sets.of(1,2,3,4,5,6,7,8,9,10).getClass(), serializer); + kryo.register(Sets.of(1,2,3,4,5,6,7,8,9,10,11).getClass(), serializer); + + } +} diff --git a/src/test/java/de/javakaffee/kryoserializers/dexx/ListSerializerTest.java b/src/test/java/de/javakaffee/kryoserializers/dexx/ListSerializerTest.java new file mode 100644 index 00000000..021022cb --- /dev/null +++ b/src/test/java/de/javakaffee/kryoserializers/dexx/ListSerializerTest.java @@ -0,0 +1,84 @@ +package de.javakaffee.kryoserializers.dexx; + +import static de.javakaffee.kryoserializers.KryoTest.deserialize; +import static de.javakaffee.kryoserializers.KryoTest.serialize; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import com.esotericsoftware.kryo.Kryo; + +import com.github.andrewoma.dexx.collection.ArrayList; +import com.github.andrewoma.dexx.collection.IndexedLists; +import com.github.andrewoma.dexx.collection.List; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +/** + * Test for {@link ListSerializer} + */ +public class ListSerializerTest { + + private Kryo _kryo; + + @BeforeTest + public void setUp() throws Exception { + _kryo = new Kryo(); + + ListSerializer.registerSerializers(_kryo); + } + + @Test(enabled = true) + public void testEmpty() { + final List obj = IndexedLists.of(); + final byte[] serialized = serialize(_kryo, obj); + final List deserialized = deserialize(_kryo, serialized, List.class); + assertTrue(deserialized.isEmpty()); + assertEquals(deserialized.size(), obj.size()); + } + + @Test(enabled = true) + public void testRegular() { + final List obj = IndexedLists.of(3,4,5,6,7); + final byte[] serialized = serialize(_kryo, obj); + final List deserialized = deserialize(_kryo, serialized, List.class); + assertEquals(deserialized, obj); + } + + @Test(enabled = true) + public void testCopyOfIterable() { + final ArrayList iterable = new ArrayList(); + iterable.append(new Object()); + final List obj = IndexedLists.copyOf(iterable.asList()); + final byte[] serialized = serialize(_kryo, obj); + final List deserialized = deserialize(_kryo, serialized, List.class); + assertEquals(deserialized, obj); + } + + // Kryo#copy tests + + @Test(enabled = true) + public void testCopyEmpty() { + final List obj = IndexedLists.of(); + final List copied = _kryo.copy(obj); + assertSame(copied, obj); + } + + @Test(enabled = true) + public void testCopyRegular() { + final List obj = IndexedLists.of(2,3,4,5); + final List copied = _kryo.copy(obj); + assertSame(copied, obj); + } + + @Test(enabled = true) + public void testCopyCopyOfIterable() { + final ArrayList iterable = new ArrayList(); + iterable.append(new Object()); + final List obj = IndexedLists.copyOf(iterable.asList()); + List copied = _kryo.copy(obj); + assertSame(copied, obj); + } +} diff --git a/src/test/java/de/javakaffee/kryoserializers/dexx/MapSerializerTest.java b/src/test/java/de/javakaffee/kryoserializers/dexx/MapSerializerTest.java new file mode 100644 index 00000000..72608128 --- /dev/null +++ b/src/test/java/de/javakaffee/kryoserializers/dexx/MapSerializerTest.java @@ -0,0 +1,61 @@ +package de.javakaffee.kryoserializers.dexx; + +import com.esotericsoftware.kryo.Kryo; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.github.andrewoma.dexx.collection.Map; +import com.github.andrewoma.dexx.collection.Maps; + +import static de.javakaffee.kryoserializers.KryoTest.deserialize; +import static de.javakaffee.kryoserializers.KryoTest.serialize; +import static org.testng.Assert.*; + +/** +* Test for {@link MapSerializer} + */ +public class MapSerializerTest { + + private Kryo _kryo; + + @BeforeTest + public void setUp() throws Exception { + _kryo = new Kryo(); + + MapSerializer.registerSerializers(_kryo); + } + + @Test(enabled = true) + public void testEmpty() { + final Map obj = Maps.of(); + final byte[] serialized = serialize(_kryo, obj); + final Map deserialized = deserialize(_kryo, serialized, Map.class); + assertTrue(deserialized.isEmpty()); + assertEquals(deserialized.size(), obj.size()); + } + + @Test(enabled = true) + public void testRegular() { + final Map obj = Maps.of(3, "k", 5, "r", 6, "y"); + final byte[] serialized = serialize(_kryo, obj); + final Map deserialized = deserialize(_kryo, serialized, Map.class); + assertEquals(deserialized, obj); + } + + // Kryo#copy tests + + @Test(enabled = true) + public void testCopyEmpty() { + final Map obj = Maps.of(); + final Map copied = _kryo.copy(obj); + assertSame(copied, obj); + } + + @Test(enabled = true) + public void testCopyRegular() { + final Map obj = Maps.of(1, 2, 3, 4); + final Map copied = _kryo.copy(obj); + assertSame(copied, obj); + } +} diff --git a/src/test/java/de/javakaffee/kryoserializers/dexx/SetSerializerTest.java b/src/test/java/de/javakaffee/kryoserializers/dexx/SetSerializerTest.java new file mode 100644 index 00000000..7c47d79b --- /dev/null +++ b/src/test/java/de/javakaffee/kryoserializers/dexx/SetSerializerTest.java @@ -0,0 +1,61 @@ +package de.javakaffee.kryoserializers.dexx; + +import com.esotericsoftware.kryo.Kryo; +import static org.testng.Assert.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import static de.javakaffee.kryoserializers.KryoTest.deserialize; +import static de.javakaffee.kryoserializers.KryoTest.serialize; + +import com.github.andrewoma.dexx.collection.Set; +import com.github.andrewoma.dexx.collection.Sets; + +/** + * Test for {@link SetSerializer}. + */ +public class SetSerializerTest { + + private Kryo _kryo; + + @BeforeTest + public void setUp() throws Exception { + _kryo = new Kryo(); + + SetSerializer.registerSerializers(_kryo); + } + + @Test(enabled = true) + public void testEmpty() { + final Set obj = Sets.of(); + final byte[] serialized = serialize( _kryo, obj ); + final Set deserialized = deserialize(_kryo, serialized, Set.class); + assertTrue(deserialized.isEmpty()); + assertEquals(deserialized.size(), obj.size()); + } + + @Test(enabled = true) + public void testRegular() { + final Set obj = Sets.of(3, 4, 5, 6); + final byte[] serialized = serialize( _kryo, obj ); + final Set deserialized = deserialize(_kryo, serialized, Set.class); + assertEquals(deserialized, obj); + } + + // Kryo#copy tests + + @Test(enabled = true) + public void testCopyEmpty() { + final Set obj = Sets.of(); + final Set copied = _kryo.copy(obj); + assertSame(copied, obj); + } + + @Test(enabled = true) + public void testCopyRegular() { + final Set obj = Sets.of(1, 2, 3); + final Set copied = _kryo.copy(obj); + assertSame(copied, obj); + } +}