From ea2843ecc01f50a090142eaf5f890df5e05c7ae0 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sun, 8 Nov 2015 20:27:06 +0100 Subject: [PATCH] MethodInvokeTypeProvider lazily invokes target method (avoiding deserialization exploits) Issue: SPR-13656 --- .../core/SerializableTypeWrapper.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java b/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java index b74480be9f..3afd15fcc6 100644 --- a/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java +++ b/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java @@ -51,6 +51,7 @@ import org.springframework.util.ReflectionUtils; * {@link GenericArrayType#getGenericComponentType()}) will be automatically wrapped. * * @author Phillip Webb + * @author Juergen Hoeller * @since 4.0 */ abstract class SerializableTypeWrapper { @@ -210,7 +211,7 @@ abstract class SerializableTypeWrapper { /** - * {@link Serializable} {@link InvocationHandler} used by the Proxied {@link Type}. + * {@link Serializable} {@link InvocationHandler} used by the proxied {@link Type}. * Provides serialization support and enhances any methods that return {@code Type} * or {@code Type[]}. */ @@ -373,21 +374,27 @@ abstract class SerializableTypeWrapper { private final int index; - private transient Object result; + private transient Method method; + + private transient volatile Object result; public MethodInvokeTypeProvider(TypeProvider provider, Method method, int index) { this.provider = provider; this.methodName = method.getName(); this.index = index; - this.result = ReflectionUtils.invokeMethod(method, provider.getType()); + this.method = method; } @Override public Type getType() { - if (this.result instanceof Type || this.result == null) { - return (Type) this.result; + Object result = this.result; + if (result == null) { + // Lazy invocation of the target method + result = ReflectionUtils.invokeMethod(this.method, this.provider.getType()); + // Cache the result for further calls + this.result = result; } - return ((Type[])this.result)[this.index]; + return (result instanceof Type[] ? ((Type[]) result)[this.index] : (Type) result); } @Override @@ -397,8 +404,8 @@ abstract class SerializableTypeWrapper { private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { inputStream.defaultReadObject(); - Method method = ReflectionUtils.findMethod(this.provider.getType().getClass(), this.methodName); - this.result = ReflectionUtils.invokeMethod(method, this.provider.getType()); + this.method = ReflectionUtils.findMethod(this.provider.getType().getClass(), this.methodName); + Assert.state(this.method.getReturnType() == Type.class || this.method.getReturnType() == Type[].class); } }