You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2016/01/04 21:24:16 UTC

[8/9] incubator-tinkerpop git commit: TINKERPOP-1066 Allow ioRegistries to be set on GraphSON MessageSerializers

TINKERPOP-1066 Allow ioRegistries to be set on GraphSON MessageSerializers

This makes the configuration symmetrical to Gryo.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/f8dc1aab
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/f8dc1aab
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/f8dc1aab

Branch: refs/heads/master
Commit: f8dc1aabd280bde7711d873c8ac0083eacf6e2c9
Parents: e480f4a
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Wed Dec 30 13:59:50 2015 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Wed Dec 30 13:59:50 2015 -0500

----------------------------------------------------------------------
 .../AbstractGraphSONMessageSerializerV1d0.java  |  5 +-
 .../driver/ser/AbstractMessageSerializer.java   | 82 ++++++++++++++++++++
 .../driver/ser/GryoMessageSerializerV1d0.java   | 41 +---------
 ...raphSONMessageSerializerGremlinV1d0Test.java |  5 +-
 .../ser/GraphSONMessageSerializerV1d0Test.java  | 60 ++++++++++++++
 .../ser/GryoMessageSerializerV1d0Test.java      | 43 ++++++++++
 6 files changed, 194 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/f8dc1aab/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV1d0.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV1d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV1d0.java
index 3410ede..810220b 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV1d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractGraphSONMessageSerializerV1d0.java
@@ -18,7 +18,6 @@
  */
 package org.apache.tinkerpop.gremlin.driver.ser;
 
-import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
@@ -51,7 +50,7 @@ import java.util.UUID;
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public abstract class AbstractGraphSONMessageSerializerV1d0 implements MessageSerializer {
+public abstract class AbstractGraphSONMessageSerializerV1d0 extends AbstractMessageSerializer {
     private static final Logger logger = LoggerFactory.getLogger(AbstractGraphSONMessageSerializerV1d0.class);
 
     protected ObjectMapper mapper;
@@ -97,6 +96,8 @@ public abstract class AbstractGraphSONMessageSerializerV1d0 implements MessageSe
             initialBuilder = GraphSONMapper.build();
         }
 
+        addIoRegistries(config, initialBuilder);
+
         mapper = configureBuilder(initialBuilder).create().createMapper();
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/f8dc1aab/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractMessageSerializer.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractMessageSerializer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractMessageSerializer.java
new file mode 100644
index 0000000..3c4380c
--- /dev/null
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/AbstractMessageSerializer.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.driver.ser;
+
+import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
+import org.apache.tinkerpop.gremlin.structure.io.IoRegistry;
+import org.apache.tinkerpop.gremlin.structure.io.Mapper;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base {@link MessageSerializer} that serializers can implement to get some helper methods around configuring a
+ * {@link org.apache.tinkerpop.gremlin.structure.io.Mapper.Builder}.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public abstract class AbstractMessageSerializer implements MessageSerializer {
+    public static final String TOKEN_IO_REGISTRIES = "ioRegistries";
+
+    /**
+     * Reads a list of fully qualified class names from the value of the {@link #TOKEN_IO_REGISTRIES} configuration
+     * key. These classes should equate to {@link IoRegistry} implementations that will be assigned to the
+     * {@link org.apache.tinkerpop.gremlin.structure.io.Mapper.Builder}.  The assumption is that the
+     * {@link IoRegistry} either has a static {@code getInstance()} method or has a zero-arg constructor from which
+     * it can be instantiated.
+     */
+    protected void addIoRegistries(final Map<String, Object> config, final Mapper.Builder builder) {
+        final List<String> classNameList = getListStringFromConfig(TOKEN_IO_REGISTRIES, config);
+
+        classNameList.stream().forEach(className -> {
+            try {
+                final Class<?> clazz = Class.forName(className);
+                try {
+                    final Method instanceMethod = clazz.getDeclaredMethod("getInstance");
+                    if (IoRegistry.class.isAssignableFrom(instanceMethod.getReturnType()))
+                        builder.addRegistry((IoRegistry) instanceMethod.invoke(null));
+                    else
+                        throw new Exception();
+                } catch (Exception methodex) {
+                    // tried getInstance() and that failed so try newInstance() no-arg constructor
+                    builder.addRegistry((IoRegistry) clazz.newInstance());
+                }
+            } catch (Exception ex) {
+                throw new IllegalStateException(ex);
+            }
+        });
+    }
+
+    /**
+     * Gets a {@link List} of strings from the configuration object.
+     */
+    protected List<String> getListStringFromConfig(final String token, final Map<String, Object> config) {
+        final List<String> classNameList;
+        try {
+            classNameList = (List<String>) config.getOrDefault(token, Collections.emptyList());
+        } catch (Exception ex) {
+            throw new IllegalStateException(String.format("Invalid configuration value of [%s] for [%s] setting on %s serialization configuration",
+                    config.getOrDefault(token, ""), token, this.getClass().getName()), ex);
+        }
+
+        return classNameList;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/f8dc1aab/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0.java
index 721d596..ce46dfc 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0.java
@@ -21,12 +21,10 @@ package org.apache.tinkerpop.gremlin.driver.ser;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufAllocator;
 import io.netty.util.ReferenceCountUtil;
-import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.io.IoRegistry;
 import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoIo;
 import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoMapper;
 import org.apache.tinkerpop.shaded.kryo.ClassResolver;
@@ -38,7 +36,6 @@ import org.apache.tinkerpop.shaded.kryo.io.Output;
 import java.io.ByteArrayOutputStream;
 import java.lang.reflect.Method;
 import java.nio.charset.Charset;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -51,7 +48,7 @@ import java.util.stream.Collectors;
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public final class GryoMessageSerializerV1d0 implements MessageSerializer {
+public final class GryoMessageSerializerV1d0 extends AbstractMessageSerializer {
     private GryoMapper gryoMapper;
     private ThreadLocal<Kryo> kryoThreadLocal = new ThreadLocal<Kryo>() {
         @Override
@@ -65,7 +62,6 @@ public final class GryoMessageSerializerV1d0 implements MessageSerializer {
     private static final String MIME_TYPE = SerTokens.MIME_GRYO_V1D0;
     private static final String MIME_TYPE_STRINGD = SerTokens.MIME_GRYO_V1D0 + "-stringd";
 
-    public static final String TOKEN_IO_REGISTRIES = "ioRegistries";
     public static final String TOKEN_CUSTOM = "custom";
     public static final String TOKEN_SERIALIZE_RESULT_TO_STRING = "serializeResultToString";
     public static final String TOKEN_USE_MAPPER_FROM_GRAPH = "useMapperFromGraph";
@@ -124,28 +120,6 @@ public final class GryoMessageSerializerV1d0 implements MessageSerializer {
         this.gryoMapper = builder.create();
     }
 
-    private void addIoRegistries(final Map<String, Object> config, final GryoMapper.Builder builder) {
-        final List<String> classNameList = getClassNamesFromConfig(TOKEN_IO_REGISTRIES, config);
-
-        classNameList.stream().forEach(className -> {
-            try {
-                final Class<?> clazz = Class.forName(className);
-                try {
-                    final Method instanceMethod = clazz.getDeclaredMethod("getInstance");
-                    if (IoRegistry.class.isAssignableFrom(instanceMethod.getReturnType()))
-                        builder.addRegistry((IoRegistry) instanceMethod.invoke(null));
-                    else
-                        throw new Exception();
-                } catch (Exception methodex) {
-                    // tried getInstance() and that failed so try newInstance() no-arg constructor
-                    builder.addRegistry((IoRegistry) clazz.newInstance());
-                }
-            } catch (Exception ex) {
-                throw new IllegalStateException(ex);
-            }
-        });
-    }
-
     private void addClassResolverSupplier(final Map<String, Object> config, final GryoMapper.Builder builder) {
         final String className = (String) config.getOrDefault(TOKEN_CLASS_RESOLVER_SUPPLIER, null);
         if (className != null && !className.isEmpty()) {
@@ -165,7 +139,7 @@ public final class GryoMessageSerializerV1d0 implements MessageSerializer {
     }
 
     private void addCustomClasses(final Map<String, Object> config, final GryoMapper.Builder builder) {
-        final List<String> classNameList = getClassNamesFromConfig(TOKEN_CUSTOM, config);
+        final List<String> classNameList = getListStringFromConfig(TOKEN_CUSTOM, config);
 
         classNameList.stream().forEach(serializerDefinition -> {
             String className;
@@ -197,17 +171,6 @@ public final class GryoMessageSerializerV1d0 implements MessageSerializer {
         });
     }
 
-    private List<String> getClassNamesFromConfig(final String token, final Map<String, Object> config) {
-        final List<String> classNameList;
-        try {
-            classNameList = (List<String>) config.getOrDefault(token, new ArrayList<String>());
-        } catch (Exception ex) {
-            throw new IllegalStateException(String.format("Invalid configuration value of [%s] for [%s] setting on %s serialization configuration",
-                    config.getOrDefault(token, ""), token, this.getClass().getName()), ex);
-        }
-        return classNameList;
-    }
-
     @Override
     public String[] mimeTypesSupported() {
         return new String[]{this.serializeToString ? MIME_TYPE_STRINGD : MIME_TYPE};

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/f8dc1aab/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0Test.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0Test.java
index 91fa899..de719c1 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0Test.java
@@ -44,7 +44,10 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 
 /**
  * Serializer tests that cover non-lossy serialization/deserialization methods.

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/f8dc1aab/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0Test.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0Test.java
index 3772c7d..de4b4b6 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0Test.java
@@ -27,22 +27,39 @@ import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.io.AbstractIoRegistry;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONIo;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerationException;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
+import org.apache.tinkerpop.shaded.jackson.core.JsonParser;
+import org.apache.tinkerpop.shaded.jackson.core.JsonProcessingException;
+import org.apache.tinkerpop.shaded.jackson.databind.DeserializationContext;
 import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
 import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
+import org.apache.tinkerpop.shaded.jackson.databind.deser.std.StdDeserializer;
+import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeSerializer;
+import org.apache.tinkerpop.shaded.jackson.databind.module.SimpleModule;
 import org.apache.tinkerpop.shaded.jackson.databind.node.NullNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer;
 import org.apache.tinkerpop.shaded.jackson.databind.util.StdDateFormat;
 import org.junit.Test;
 
+import java.awt.*;
+import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
@@ -61,6 +78,23 @@ public class GraphSONMessageSerializerV1d0Test {
     private static final ObjectMapper mapper = new ObjectMapper();
 
     @Test
+    public void shouldConfigureIoRegistry() throws Exception {
+        final GraphSONMessageSerializerV1d0 serializer = new GraphSONMessageSerializerV1d0();
+        final Map<String, Object> config = new HashMap<String, Object>() {{
+            put(GryoMessageSerializerV1d0.TOKEN_IO_REGISTRIES, Arrays.asList(ColorIoRegistry.class.getName()));
+        }};
+
+        serializer.configure(config, null);
+
+        final ResponseMessage toSerialize = ResponseMessage.build(UUID.fromString("2D62161B-9544-4F39-AF44-62EC49F9A595"))
+                .result(Color.RED).create();
+        final String results = serializer.serializeResponseAsString(toSerialize);
+        final JsonNode json = mapper.readTree(results);
+        assertNotNull(json);
+        assertThat(json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA).booleanValue(), is(true));
+    }
+
+    @Test
     public void shouldSerializeToJsonNullResultReturnsNull() throws Exception {
         final ResponseMessage message = ResponseMessage.build(msg).create();
         final String results = SERIALIZER.serializeResponseAsString(message);
@@ -385,4 +419,30 @@ public class GraphSONMessageSerializerV1d0Test {
             return this.val;
         }
     }
+
+    public static class ColorIoRegistry extends AbstractIoRegistry {
+        public ColorIoRegistry() {
+            register(GraphSONIo.class, null, new ColorSimpleModule());
+        }
+    }
+
+    public static class ColorSimpleModule extends SimpleModule {
+        public ColorSimpleModule() {
+            super("color-fun");
+            addSerializer(Color.class, new ColorSerializer());
+
+        }
+    }
+
+    public static class ColorSerializer extends StdSerializer<Color> {
+        public ColorSerializer() {
+            super(Color.class);
+        }
+
+        @Override
+        public void serialize(final Color color, final JsonGenerator jsonGenerator,
+                              final SerializerProvider serializerProvider) throws IOException, JsonGenerationException {
+            jsonGenerator.writeBoolean(color.equals(Color.RED));
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/f8dc1aab/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0Test.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0Test.java
index f56bf51..bb731a9 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GryoMessageSerializerV1d0Test.java
@@ -29,7 +29,9 @@ import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.io.AbstractIoRegistry;
 import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoClassResolver;
+import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoIo;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
@@ -39,11 +41,17 @@ import io.netty.buffer.ByteBufAllocator;
 import io.netty.buffer.UnpooledByteBufAllocator;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.apache.tinkerpop.shaded.kryo.ClassResolver;
+import org.apache.tinkerpop.shaded.kryo.Kryo;
 import org.apache.tinkerpop.shaded.kryo.KryoException;
 import org.apache.tinkerpop.shaded.kryo.Registration;
+import org.apache.tinkerpop.shaded.kryo.Serializer;
+import org.apache.tinkerpop.shaded.kryo.io.Input;
+import org.apache.tinkerpop.shaded.kryo.io.Output;
 import org.junit.Test;
 
+import java.awt.*;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -82,6 +90,23 @@ public class GryoMessageSerializerV1d0Test {
     }
 
     @Test
+    public void shouldConfigureIoRegistry() throws Exception {
+        final MessageSerializer serializer = new GryoMessageSerializerV1d0();
+        final Map<String, Object> config = new HashMap<String, Object>() {{
+            put(GryoMessageSerializerV1d0.TOKEN_IO_REGISTRIES, Arrays.asList(ColorIoRegistry.class.getName()));
+        }};
+
+        serializer.configure(config, null);
+
+        final ResponseMessage toSerialize = ResponseMessage.build(requestId).result(Color.RED).create();
+        final ByteBuf bb = serializer.serializeResponseAsBinary(toSerialize, allocator);
+        final ResponseMessage deserialized = serializer.deserializeResponse(bb);
+
+        assertCommon(deserialized);
+        assertEquals(Color.RED, deserialized.getResult().getData());
+    }
+
+    @Test
     public void shouldConfigureCustomClassResolver() {
         final MessageSerializer serializer = new GryoMessageSerializerV1d0();
         final Map<String, Object> config = new HashMap<String, Object>() {{
@@ -556,4 +581,22 @@ public class GryoMessageSerializerV1d0Test {
             throw new RuntimeException("Registration is not allowed with this ClassResolver - it is not a good implementation");
         }
     }
+
+    public static class ColorIoRegistry extends AbstractIoRegistry {
+        public ColorIoRegistry() {
+            register(GryoIo.class, Color.class, new ColorSerializer());
+        }
+    }
+
+    public static class ColorSerializer extends Serializer<Color> {
+        @Override
+        public void write(final Kryo kryo, final Output output, final Color color) {
+            output.write(color.equals(Color.RED) ? 1 : 0);
+        }
+
+        @Override
+        public Color read(final Kryo kryo, final Input input, final Class<Color> aClass) {
+            return input.read() == 1 ? Color.RED : Color.BLACK;
+        }
+    }
 }