diff --git a/pom-main.xml b/pom-main.xml index 8906ffea0..0914a9acc 100644 --- a/pom-main.xml +++ b/pom-main.xml @@ -109,6 +109,11 @@ com/esotericsoftware/reflectasm/** 8001 + + com/esotericsoftware/kryo/Kryo + *isClousre* + 7002 + diff --git a/pom.xml b/pom.xml index 44cedc66b..3c3696ae5 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,7 @@ UTF-8 1.10.1 + **/Java8*Test.java @@ -101,6 +102,9 @@ 1.5 1.5 utf-8 + + ${test.exclude} + @@ -206,6 +210,18 @@ + + java8 + + [1.8,) + + + + someValueWhichDoesNotExist + 1.8 + 1.8 + + 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()); + } + } + +}