11/*
2- * Copyright 2002-2014 the original author or authors.
2+ * Copyright 2002-2015 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
5151 * {@link GenericArrayType#getGenericComponentType()}) will be automatically wrapped.
5252 *
5353 * @author Phillip Webb
54+ * @author Juergen Hoeller
5455 * @since 4.0
5556 */
5657abstract class SerializableTypeWrapper {
5758
5859 private static final Class <?>[] SUPPORTED_SERIALIZABLE_TYPES = {
5960 GenericArrayType .class , ParameterizedType .class , TypeVariable .class , WildcardType .class };
6061
61- private static final Method EQUALS_METHOD = ReflectionUtils .findMethod (Object .class ,
62- "equals" , Object .class );
63-
64- private static final Method GET_TYPE_PROVIDER_METHOD = ReflectionUtils .findMethod (
65- SerializableTypeProxy .class , "getTypeProvider" );
66-
6762 private static final ConcurrentReferenceHashMap <Type , Type > cache =
6863 new ConcurrentReferenceHashMap <Type , Type >(256 );
6964
65+
7066 /**
7167 * Return a {@link Serializable} variant of {@link Field#getGenericType()}.
7268 */
@@ -161,35 +157,33 @@ static Type forTypeProvider(final TypeProvider provider) {
161157 for (Class <?> type : SUPPORTED_SERIALIZABLE_TYPES ) {
162158 if (type .isAssignableFrom (provider .getType ().getClass ())) {
163159 ClassLoader classLoader = provider .getClass ().getClassLoader ();
164- Class <?>[] interfaces = new Class <?>[] { type ,
165- SerializableTypeProxy .class , Serializable .class };
160+ Class <?>[] interfaces = new Class <?>[] {type , SerializableTypeProxy .class , Serializable .class };
166161 InvocationHandler handler = new TypeProxyInvocationHandler (provider );
167162 cached = (Type ) Proxy .newProxyInstance (classLoader , interfaces , handler );
168163 cache .put (provider .getType (), cached );
169164 return cached ;
170165 }
171166 }
172- throw new IllegalArgumentException ("Unsupported Type class " + provider .getType ().getClass ().getName ());
167+ throw new IllegalArgumentException ("Unsupported Type class: " + provider .getType ().getClass ().getName ());
173168 }
174169
175170
176171 /**
177172 * Additional interface implemented by the type proxy.
178173 */
179- static interface SerializableTypeProxy {
174+ interface SerializableTypeProxy {
180175
181176 /**
182177 * Return the underlying type provider.
183178 */
184179 TypeProvider getTypeProvider ();
185-
186180 }
187181
188182
189183 /**
190184 * A {@link Serializable} interface providing access to a {@link Type}.
191185 */
192- static interface TypeProvider extends Serializable {
186+ interface TypeProvider extends Serializable {
193187
194188 /**
195189 * Return the (possibly non {@link Serializable}) {@link Type}.
@@ -213,12 +207,11 @@ private static abstract class DefaultTypeProvider implements TypeProvider {
213207 public Object getSource () {
214208 return null ;
215209 }
216-
217210 }
218211
219212
220213 /**
221- * {@link Serializable} {@link InvocationHandler} used by the Proxied {@link Type}.
214+ * {@link Serializable} {@link InvocationHandler} used by the proxied {@link Type}.
222215 * Provides serialization support and enhances any methods that return {@code Type}
223216 * or {@code Type[]}.
224217 */
@@ -233,17 +226,21 @@ public TypeProxyInvocationHandler(TypeProvider provider) {
233226
234227 @ Override
235228 public Object invoke (Object proxy , Method method , Object [] args ) throws Throwable {
236- if (GET_TYPE_PROVIDER_METHOD .equals (method )) {
237- return this .provider ;
238- }
239- if (EQUALS_METHOD .equals (method )) {
229+ if (method .getName ().equals ("equals" )) {
240230 Object other = args [0 ];
241231 // Unwrap proxies for speed
242232 if (other instanceof Type ) {
243233 other = unwrap ((Type ) other );
244234 }
245235 return this .provider .getType ().equals (other );
246236 }
237+ else if (method .getName ().equals ("hashCode" )) {
238+ return this .provider .getType ().hashCode ();
239+ }
240+ else if (method .getName ().equals ("getTypeProvider" )) {
241+ return this .provider ;
242+ }
243+
247244 if (Type .class .equals (method .getReturnType ()) && args == null ) {
248245 return forTypeProvider (new MethodInvokeTypeProvider (this .provider , method , -1 ));
249246 }
@@ -254,6 +251,7 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
254251 }
255252 return result ;
256253 }
254+
257255 try {
258256 return method .invoke (this .provider .getType (), args );
259257 }
@@ -376,21 +374,27 @@ static class MethodInvokeTypeProvider implements TypeProvider {
376374
377375 private final int index ;
378376
379- private transient Object result ;
377+ private transient Method method ;
378+
379+ private transient volatile Object result ;
380380
381381 public MethodInvokeTypeProvider (TypeProvider provider , Method method , int index ) {
382382 this .provider = provider ;
383383 this .methodName = method .getName ();
384384 this .index = index ;
385- this .result = ReflectionUtils . invokeMethod ( method , provider . getType ()) ;
385+ this .method = method ;
386386 }
387387
388388 @ Override
389389 public Type getType () {
390- if (this .result instanceof Type || this .result == null ) {
391- return (Type ) this .result ;
390+ Object result = this .result ;
391+ if (result == null ) {
392+ // Lazy invocation of the target method on the provided type
393+ result = ReflectionUtils .invokeMethod (this .method , this .provider .getType ());
394+ // Cache the result for further calls to getType()
395+ this .result = result ;
392396 }
393- return (( Type [])this . result )[this .index ];
397+ return (result instanceof Type [] ? (( Type []) result )[this .index ] : ( Type ) result ) ;
394398 }
395399
396400 @ Override
@@ -400,8 +404,9 @@ public Object getSource() {
400404
401405 private void readObject (ObjectInputStream inputStream ) throws IOException , ClassNotFoundException {
402406 inputStream .defaultReadObject ();
403- Method method = ReflectionUtils .findMethod (this .provider .getType ().getClass (), this .methodName );
404- this .result = ReflectionUtils .invokeMethod (method , this .provider .getType ());
407+ this .method = ReflectionUtils .findMethod (this .provider .getType ().getClass (), this .methodName );
408+ Assert .state (Type .class .equals (this .method .getReturnType ()) ||
409+ Type [].class .equals (this .method .getReturnType ()));
405410 }
406411 }
407412
0 commit comments