Skip to content

Commit

Permalink
Avoid slow Class.forName when serializing lambdas (#944)
Browse files Browse the repository at this point in the history
  • Loading branch information
theigl authored Mar 27, 2023
1 parent 3fb0a62 commit cd5980b
Showing 1 changed file with 25 additions and 2 deletions.
27 changes: 25 additions & 2 deletions src/com/esotericsoftware/kryo/serializers/ClosureSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/** Serializer for Java8 closures which implement Serializable. To serialize closures, use:
Expand All @@ -49,6 +50,7 @@ public static class Closure {
}

private static Method readResolve;
private static Field capturingClass;

public ClosureSerializer () {
if (readResolve == null) {
Expand All @@ -61,6 +63,16 @@ public ClosureSerializer () {
"Falling back on resolving lambdas via capturing class.", ex);
}
}
if (capturingClass == null) {
try {
capturingClass = SerializedLambda.class.getDeclaredField("capturingClass");
capturingClass.setAccessible(true);
} catch (Exception ex) {
capturingClass = null;
Log.warn("Unable to obtain SerializedLambda#capturingClass via reflection. " +
"Falling back to resolving capturing class via Class.forName.", ex);
}
}
}

public void write (Kryo kryo, Output output, Object object) {
Expand All @@ -70,7 +82,7 @@ public void write (Kryo kryo, Output output, Object object) {
for (int i = 0; i < count; i++)
kryo.writeClassAndObject(output, serializedLambda.getCapturedArg(i));
try {
kryo.writeClass(output, Class.forName(serializedLambda.getCapturingClass().replace('/', '.')));
kryo.writeClass(output, getCapturingClass(serializedLambda));
} catch (ClassNotFoundException ex) {
throw new KryoException("Error writing closure.", ex);
}
Expand Down Expand Up @@ -103,7 +115,7 @@ public Object read (Kryo kryo, Input input, Class type) {
public Object copy (Kryo kryo, Object original) {
try {
SerializedLambda lambda = toSerializedLambda(original);
Class<?> capturingClass = Class.forName(lambda.getCapturingClass().replace('/', '.'));
Class<?> capturingClass = getCapturingClass(lambda);
return readResolve(capturingClass, lambda);
} catch (Exception ex) {
throw new KryoException("Error copying closure.", ex);
Expand Down Expand Up @@ -137,4 +149,15 @@ private SerializedLambda toSerializedLambda (Object object) {
throw new KryoException("writeReplace must return a SerializedLambda: " + className(replacement.getClass()), ex);
}
}

private static Class<?> getCapturingClass (SerializedLambda serializedLambda) throws ClassNotFoundException {
if (capturingClass != null) {
try {
return (Class<?>)capturingClass.get(serializedLambda);
} catch (IllegalAccessException ignored) {
// ignore
}
}
return Class.forName(serializedLambda.getCapturingClass().replace('/', '.'));
}
}

0 comments on commit cd5980b

Please sign in to comment.