From d96b91a57bfab0ecb7543f687d297dc5db9414ee Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 20 Jan 2014 13:33:24 -0800 Subject: [PATCH] Fix SerializableTypeWrapper equals() performance Change SerializableTypeWrapper proxies to directly call equals() methods on the underlying Type, rather than possibly generating more wrappers. This should help to improve performance, especially as the equals() method is called many times when the ResolvableType cache is checked. Issue: SPR-11335 --- .../core/SerializableTypeWrapper.java | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 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 592d1b97ffc..6551228f663 100644 --- a/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java +++ b/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,6 +57,11 @@ abstract class SerializableTypeWrapper { private static final Class[] SUPPORTED_SERIALIZABLE_TYPES = { GenericArrayType.class, ParameterizedType.class, TypeVariable.class, WildcardType.class}; + private static final Method EQUALS_METHOD = ReflectionUtils.findMethod(Object.class, + "equals", Object.class); + + private static final Method GET_TYPE_PROVIDER_METHOD = ReflectionUtils.findMethod( + SerializableTypeProxy.class, "getTypeProvider"); /** * Return a {@link Serializable} variant of {@link Field#getGenericType()}. @@ -134,7 +139,8 @@ abstract class SerializableTypeWrapper { for (Class type : SUPPORTED_SERIALIZABLE_TYPES) { if (type.isAssignableFrom(provider.getType().getClass())) { ClassLoader classLoader = provider.getClass().getClassLoader(); - Class[] interfaces = new Class[] { type, Serializable.class }; + Class[] interfaces = new Class[] { type, + SerializableTypeProxy.class, Serializable.class }; InvocationHandler handler = new TypeProxyInvocationHandler(provider); return (Type) Proxy.newProxyInstance(classLoader, interfaces, handler); } @@ -143,6 +149,19 @@ abstract class SerializableTypeWrapper { } + /** + * Additional interface implemented by the type proxy. + */ + static interface SerializableTypeProxy { + + /** + * Return the underlying type provider. + */ + TypeProvider getTypeProvider(); + + } + + /** * A {@link Serializable} interface providing access to a {@link Type}. */ @@ -190,6 +209,17 @@ abstract class SerializableTypeWrapper { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (GET_TYPE_PROVIDER_METHOD.equals(method)) { + return this.provider; + } + if (EQUALS_METHOD.equals(method)) { + Object other = args[0]; + // Unwrap proxies for speed + while (other instanceof SerializableTypeProxy) { + other = ((SerializableTypeProxy) other).getTypeProvider().getType(); + } + return this.provider.getType().equals(other); + } if (Type.class.equals(method.getReturnType()) && args == null) { return forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, -1)); }