Skip to content

Commit 8742e6e

Browse files
authored
Performance improvements for Kryo.isClosure() (#956)
1 parent 379b022 commit 8742e6e

File tree

2 files changed

+49
-4
lines changed

2 files changed

+49
-4
lines changed

src/com/esotericsoftware/kryo/Kryo.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,10 +1257,10 @@ public boolean isFinal (Class type) {
12571257
* the class {@link Registration}.
12581258
* <p>
12591259
* This can be overridden to support alternative closure implementations. The default implementation returns true if the
1260-
* specified type's name contains '/' (to detect a Java 8+ closure). */
1260+
* specified type is synthetic and the type's simple name contains '/' (to detect a Java 8+ closure). */
12611261
public boolean isClosure (Class type) {
12621262
if (type == null) throw new IllegalArgumentException("type cannot be null.");
1263-
return type.getName().indexOf('/') >= 0;
1263+
return type.isSynthetic() && type.getSimpleName().indexOf('/') >= 0;
12641264
}
12651265

12661266
/** Returns true if the specified type is a proxy. When true, Kryo uses {@link InvocationHandler} instead of the specified type

test/com/esotericsoftware/kryo/serializers/ClosureSerializerTest.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.esotericsoftware.kryo.io.Output;
2727

2828
import java.util.concurrent.Callable;
29+
import java.util.function.Supplier;
2930

3031
import org.junit.jupiter.api.BeforeEach;
3132
import org.junit.jupiter.api.Test;
@@ -59,7 +60,40 @@ void testSerializableClosure () {
5960
}
6061

6162
@Test
62-
void testCopyClosure() {
63+
void testCapturingClosure () {
64+
final int number = 72363;
65+
Supplier<Integer> closure1 = (Supplier<Integer> & java.io.Serializable) () -> number;
66+
67+
// The length cannot be checked reliable, as it can vary based on the JVM.
68+
roundTrip(Integer.MIN_VALUE, closure1);
69+
70+
Output output = new Output(1024, -1);
71+
kryo.writeObject(output, closure1);
72+
73+
Input input = new Input(output.getBuffer(), 0, output.position());
74+
Supplier<Integer> closure2 = (Supplier<Integer>)kryo.readObject(input, ClosureSerializer.Closure.class);
75+
76+
doAssertEquals(closure1, closure2);
77+
}
78+
79+
@Test
80+
void testMethodReference () {
81+
Supplier<Integer> closure1 = (Supplier<Integer> & java.io.Serializable)NumberFactory::getNumber;
82+
83+
// The length cannot be checked reliable, as it can vary based on the JVM.
84+
roundTrip(Integer.MIN_VALUE, closure1);
85+
86+
Output output = new Output(1024, -1);
87+
kryo.writeObject(output, closure1);
88+
89+
Input input = new Input(output.getBuffer(), 0, output.position());
90+
Supplier<Integer> closure2 = (Supplier<Integer>)kryo.readObject(input, ClosureSerializer.Closure.class);
91+
92+
doAssertEquals(closure1, closure2);
93+
}
94+
95+
@Test
96+
void testCopyClosure () {
6397
Callable<Integer> closure1 = (Callable<Integer> & java.io.Serializable)( () -> 72363);
6498

6599
final Callable<Integer> closure2 = kryo.copy(closure1);
@@ -69,9 +103,20 @@ void testCopyClosure() {
69103

70104
protected void doAssertEquals (Object object1, Object object2) {
71105
try {
72-
assertEquals(((Callable)object1).call(), ((Callable)object2).call());
106+
if (object1 instanceof Callable) {
107+
assertEquals(((Callable)object1).call(), ((Callable)object2).call());
108+
}
109+
if (object1 instanceof Supplier) {
110+
assertEquals(((Supplier)object1).get(), ((Supplier)object2).get());
111+
}
73112
} catch (Exception ex) {
74113
throw new RuntimeException(ex.getMessage());
75114
}
76115
}
116+
117+
static class NumberFactory {
118+
private static int getNumber () {
119+
return 72363;
120+
}
121+
}
77122
}

0 commit comments

Comments
 (0)