diff --git a/src/com/esotericsoftware/kryo/Kryo.java b/src/com/esotericsoftware/kryo/Kryo.java
index 2b26efe61..c3c236da1 100644
--- a/src/com/esotericsoftware/kryo/Kryo.java
+++ b/src/com/esotericsoftware/kryo/Kryo.java
@@ -44,6 +44,7 @@
import java.util.TreeMap;
import java.util.TreeSet;
+import com.esotericsoftware.kryo.serializers.ClosureSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.URLSerializer;
import com.esotericsoftware.kryo.serializers.OptionalSerializers;
import com.esotericsoftware.kryo.serializers.GenericsResolver;
@@ -491,8 +492,8 @@ public Registration getRegistration (Class type) {
registration = getRegistration(type.getEnclosingClass());
} else if (EnumSet.class.isAssignableFrom(type)) {
registration = classResolver.getRegistration(EnumSet.class);
- } else if (isClousre(type)) {
- registration = classResolver.getRegistration(Closure.class);
+ } else if (isClosure(type)) {
+ registration = classResolver.getRegistration(ClosureSerializer.Closure.class);
}
if (registration == null) {
if (registrationRequired) {
@@ -1174,7 +1175,7 @@ public boolean isFinal (Class type) {
/** Returns true if the specified type is a closure.
*
* This can be overridden to support alternative implementations of clousres. Current version supports Oracle's Java8 only */
- public boolean isClousre (Class type) {
+ protected boolean isClosure(Class type) {
if (type == null) throw new IllegalArgumentException("type cannot be null.");
return type.getName().indexOf('/') >= 0;
}
@@ -1290,6 +1291,4 @@ public Object newInstance () {
}
}
- private static class Closure {
- }
}
diff --git a/src/com/esotericsoftware/kryo/serializers/ClosureSerializer.java b/src/com/esotericsoftware/kryo/serializers/ClosureSerializer.java
index cd9c7af5d..6853bbcf5 100644
--- a/src/com/esotericsoftware/kryo/serializers/ClosureSerializer.java
+++ b/src/com/esotericsoftware/kryo/serializers/ClosureSerializer.java
@@ -30,15 +30,18 @@
*
*
* kryo.register(java.lang.invoke.SerializedLambda.class);
- * kryo.register(Closure.class, new ClosureSerializer());
+ * kryo.register(ClosureSerializer.Closure.class, new ClosureSerializer());
* @author Roman Levenstein */
public class ClosureSerializer extends Serializer {
+ /** Marker class to bind ClosureSerializer to. See also {@link Kryo#isClosure(Class)} and {@link Kryo#getRegistration(Class)} */
+ public static class Closure {
+ }
+
private static Method readResolve;
- private static Class serializedLambda;
+ private static Class serializedLambda = java.lang.invoke.SerializedLambda.class;
static {
try {
- serializedLambda = Class.forName("java.lang.invoke.SerializedLambda");
readResolve = serializedLambda.getDeclaredMethod("readResolve");
readResolve.setAccessible(true);
} catch (Exception e) {
diff --git a/test/com/esotericsoftware/kryo/serializers/Java8ClosureSerializerTest.java b/test/com/esotericsoftware/kryo/serializers/Java8ClosureSerializerTest.java
new file mode 100644
index 000000000..c5135e515
--- /dev/null
+++ b/test/com/esotericsoftware/kryo/serializers/Java8ClosureSerializerTest.java
@@ -0,0 +1,69 @@
+/* Copyright (c) 2016, Martin Grotzke
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the distribution.
+ * - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+package com.esotericsoftware.kryo.serializers;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.KryoTestCase;
+import org.junit.Assert;
+import org.junit.Test;
+import org.objenesis.strategy.StdInstantiatorStrategy;
+
+import java.lang.invoke.SerializedLambda;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Test for java 8 closures.
+ *
+ * For jdk < 1.8 excluded from surefire tests via the "until-java8" profile in pom.xml which excludes "Java8*Tests".
+ */
+public class Java8ClosureSerializerTest extends KryoTestCase {
+
+ public void setUp() throws Exception {
+ super.setUp();
+ kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
+ // the following registrations are needed because registration is required
+ kryo.register(Object[].class);
+ kryo.register(java.lang.Class.class);
+ kryo.register(getClass()); // closure capturing class (in this test `this`), it would usually already be registered
+ kryo.register(SerializedLambda.class);
+ // always needed for closure serialization, also if registrationRequired=false
+ kryo.register(ClosureSerializer.Closure.class, new ClosureSerializer());
+ }
+
+ public void testSerializeSerializableLambdaWithKryo() throws Exception {
+ Callable doNothing = (Callable & java.io.Serializable)(() -> true);
+ roundTrip(222, 225, doNothing);
+ }
+
+ // we must override equals as lambdas have no equals check built in...
+ @Override
+ protected void doAssertEquals(Object object1, Object object2) {
+ try {
+ Assert.assertEquals(((Callable>)object1).call(), ((Callable>)object2).call());
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+}