|
|
|
|
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
|
|
|
|
/* |
|
|
|
|
* Copyright 2002-2014 the original author or authors. |
|
|
|
|
* Copyright 2002-2015 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. |
|
|
|
|
@ -51,6 +51,7 @@ import org.springframework.util.ReflectionUtils;
@@ -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 { |
|
|
|
|
@ -58,15 +59,10 @@ abstract class SerializableTypeWrapper {
@@ -58,15 +59,10 @@ 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"); |
|
|
|
|
|
|
|
|
|
private static final ConcurrentReferenceHashMap<Type, Type> cache = |
|
|
|
|
new ConcurrentReferenceHashMap<Type, Type>(256); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Return a {@link Serializable} variant of {@link Field#getGenericType()}. |
|
|
|
|
*/ |
|
|
|
|
@ -161,35 +157,33 @@ abstract class SerializableTypeWrapper {
@@ -161,35 +157,33 @@ 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, |
|
|
|
|
SerializableTypeProxy.class, Serializable.class }; |
|
|
|
|
Class<?>[] interfaces = new Class<?>[] {type, SerializableTypeProxy.class, Serializable.class}; |
|
|
|
|
InvocationHandler handler = new TypeProxyInvocationHandler(provider); |
|
|
|
|
cached = (Type) Proxy.newProxyInstance(classLoader, interfaces, handler); |
|
|
|
|
cache.put(provider.getType(), cached); |
|
|
|
|
return cached; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
throw new IllegalArgumentException("Unsupported Type class " + provider.getType().getClass().getName()); |
|
|
|
|
throw new IllegalArgumentException("Unsupported Type class: " + provider.getType().getClass().getName()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Additional interface implemented by the type proxy. |
|
|
|
|
*/ |
|
|
|
|
static interface SerializableTypeProxy { |
|
|
|
|
interface SerializableTypeProxy { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Return the underlying type provider. |
|
|
|
|
*/ |
|
|
|
|
TypeProvider getTypeProvider(); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* A {@link Serializable} interface providing access to a {@link Type}. |
|
|
|
|
*/ |
|
|
|
|
static interface TypeProvider extends Serializable { |
|
|
|
|
interface TypeProvider extends Serializable { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Return the (possibly non {@link Serializable}) {@link Type}. |
|
|
|
|
@ -213,12 +207,11 @@ abstract class SerializableTypeWrapper {
@@ -213,12 +207,11 @@ abstract class SerializableTypeWrapper {
|
|
|
|
|
public Object getSource() { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* {@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[]}. |
|
|
|
|
*/ |
|
|
|
|
@ -233,10 +226,7 @@ abstract class SerializableTypeWrapper {
@@ -233,10 +226,7 @@ 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)) { |
|
|
|
|
if (method.getName().equals("equals")) { |
|
|
|
|
Object other = args[0]; |
|
|
|
|
// Unwrap proxies for speed
|
|
|
|
|
if (other instanceof Type) { |
|
|
|
|
@ -244,6 +234,13 @@ abstract class SerializableTypeWrapper {
@@ -244,6 +234,13 @@ abstract class SerializableTypeWrapper {
|
|
|
|
|
} |
|
|
|
|
return this.provider.getType().equals(other); |
|
|
|
|
} |
|
|
|
|
else if (method.getName().equals("hashCode")) { |
|
|
|
|
return this.provider.getType().hashCode(); |
|
|
|
|
} |
|
|
|
|
else if (method.getName().equals("getTypeProvider")) { |
|
|
|
|
return this.provider; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (Type.class.equals(method.getReturnType()) && args == null) { |
|
|
|
|
return forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, -1)); |
|
|
|
|
} |
|
|
|
|
@ -254,6 +251,7 @@ abstract class SerializableTypeWrapper {
@@ -254,6 +251,7 @@ abstract class SerializableTypeWrapper {
|
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
return method.invoke(this.provider.getType(), args); |
|
|
|
|
} |
|
|
|
|
@ -376,21 +374,27 @@ abstract class SerializableTypeWrapper {
@@ -376,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 on the provided type
|
|
|
|
|
result = ReflectionUtils.invokeMethod(this.method, this.provider.getType()); |
|
|
|
|
// Cache the result for further calls to getType()
|
|
|
|
|
this.result = result; |
|
|
|
|
} |
|
|
|
|
return ((Type[])this.result)[this.index]; |
|
|
|
|
return (result instanceof Type[] ? ((Type[]) result)[this.index] : (Type) result); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
@ -400,8 +404,9 @@ abstract class SerializableTypeWrapper {
@@ -400,8 +404,9 @@ 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(Type.class.equals(this.method.getReturnType()) || |
|
|
|
|
Type[].class.equals(this.method.getReturnType())); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|