1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.core;
18
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.Serializable;
22 import java.lang.reflect.Field;
23 import java.lang.reflect.GenericArrayType;
24 import java.lang.reflect.InvocationHandler;
25 import java.lang.reflect.InvocationTargetException;
26 import java.lang.reflect.Method;
27 import java.lang.reflect.ParameterizedType;
28 import java.lang.reflect.Proxy;
29 import java.lang.reflect.Type;
30 import java.lang.reflect.TypeVariable;
31 import java.lang.reflect.WildcardType;
32
33 import org.springframework.util.Assert;
34 import org.springframework.util.ConcurrentReferenceHashMap;
35 import org.springframework.util.ReflectionUtils;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 abstract class SerializableTypeWrapper {
57
58 private static final Class<?>[] SUPPORTED_SERIALIZABLE_TYPES = {
59 GenericArrayType.class, ParameterizedType.class, TypeVariable.class, WildcardType.class};
60
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
67 private static final ConcurrentReferenceHashMap<Type, Type> cache =
68 new ConcurrentReferenceHashMap<Type, Type>(256);
69
70
71
72
73 public static Type forField(Field field) {
74 Assert.notNull(field, "Field must not be null");
75 return forTypeProvider(new FieldTypeProvider(field));
76 }
77
78
79
80
81
82 public static Type forMethodParameter(MethodParameter methodParameter) {
83 return forTypeProvider(new MethodParameterTypeProvider(methodParameter));
84 }
85
86
87
88
89 @SuppressWarnings("serial")
90 public static Type forGenericSuperclass(final Class<?> type) {
91 return forTypeProvider(new DefaultTypeProvider() {
92 @Override
93 public Type getType() {
94 return type.getGenericSuperclass();
95 }
96 });
97 }
98
99
100
101
102 @SuppressWarnings("serial")
103 public static Type[] forGenericInterfaces(final Class<?> type) {
104 Type[] result = new Type[type.getGenericInterfaces().length];
105 for (int i = 0; i < result.length; i++) {
106 final int index = i;
107 result[i] = forTypeProvider(new DefaultTypeProvider() {
108 @Override
109 public Type getType() {
110 return type.getGenericInterfaces()[index];
111 }
112 });
113 }
114 return result;
115 }
116
117
118
119
120 @SuppressWarnings("serial")
121 public static Type[] forTypeParameters(final Class<?> type) {
122 Type[] result = new Type[type.getTypeParameters().length];
123 for (int i = 0; i < result.length; i++) {
124 final int index = i;
125 result[i] = forTypeProvider(new DefaultTypeProvider() {
126 @Override
127 public Type getType() {
128 return type.getTypeParameters()[index];
129 }
130 });
131 }
132 return result;
133 }
134
135
136
137
138
139
140 @SuppressWarnings("unchecked")
141 public static <T extends Type> T unwrap(T type) {
142 Type unwrapped = type;
143 while (unwrapped instanceof SerializableTypeProxy) {
144 unwrapped = ((SerializableTypeProxy) type).getTypeProvider().getType();
145 }
146 return (T) unwrapped;
147 }
148
149
150
151
152 static Type forTypeProvider(final TypeProvider provider) {
153 Assert.notNull(provider, "Provider must not be null");
154 if (provider.getType() instanceof Serializable || provider.getType() == null) {
155 return provider.getType();
156 }
157 Type cached = cache.get(provider.getType());
158 if (cached != null) {
159 return cached;
160 }
161 for (Class<?> type : SUPPORTED_SERIALIZABLE_TYPES) {
162 if (type.isAssignableFrom(provider.getType().getClass())) {
163 ClassLoader classLoader = provider.getClass().getClassLoader();
164 Class<?>[] interfaces = new Class<?>[] { type,
165 SerializableTypeProxy.class, Serializable.class };
166 InvocationHandler handler = new TypeProxyInvocationHandler(provider);
167 cached = (Type) Proxy.newProxyInstance(classLoader, interfaces, handler);
168 cache.put(provider.getType(), cached);
169 return cached;
170 }
171 }
172 throw new IllegalArgumentException("Unsupported Type class " + provider.getType().getClass().getName());
173 }
174
175
176
177
178
179 static interface SerializableTypeProxy {
180
181
182
183
184 TypeProvider getTypeProvider();
185
186 }
187
188
189
190
191
192 static interface TypeProvider extends Serializable {
193
194
195
196
197 Type getType();
198
199
200
201
202 Object getSource();
203 }
204
205
206
207
208
209 @SuppressWarnings("serial")
210 private static abstract class DefaultTypeProvider implements TypeProvider {
211
212 @Override
213 public Object getSource() {
214 return null;
215 }
216
217 }
218
219
220
221
222
223
224
225 @SuppressWarnings("serial")
226 private static class TypeProxyInvocationHandler implements InvocationHandler, Serializable {
227
228 private final TypeProvider provider;
229
230 public TypeProxyInvocationHandler(TypeProvider provider) {
231 this.provider = provider;
232 }
233
234 @Override
235 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)) {
240 Object other = args[0];
241
242 if (other instanceof Type) {
243 other = unwrap((Type) other);
244 }
245 return this.provider.getType().equals(other);
246 }
247 if (Type.class.equals(method.getReturnType()) && args == null) {
248 return forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, -1));
249 }
250 if (Type[].class.equals(method.getReturnType()) && args == null) {
251 Type[] result = new Type[((Type[]) method.invoke(this.provider.getType(), args)).length];
252 for (int i = 0; i < result.length; i++) {
253 result[i] = forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, i));
254 }
255 return result;
256 }
257 try {
258 return method.invoke(this.provider.getType(), args);
259 }
260 catch (InvocationTargetException ex) {
261 throw ex.getTargetException();
262 }
263 }
264 }
265
266
267
268
269
270 @SuppressWarnings("serial")
271 static class FieldTypeProvider implements TypeProvider {
272
273 private final String fieldName;
274
275 private final Class<?> declaringClass;
276
277 private transient Field field;
278
279 public FieldTypeProvider(Field field) {
280 this.fieldName = field.getName();
281 this.declaringClass = field.getDeclaringClass();
282 this.field = field;
283 }
284
285 @Override
286 public Type getType() {
287 return this.field.getGenericType();
288 }
289
290 @Override
291 public Object getSource() {
292 return this.field;
293 }
294
295 private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
296 inputStream.defaultReadObject();
297 try {
298 this.field = this.declaringClass.getDeclaredField(this.fieldName);
299 }
300 catch (Throwable ex) {
301 throw new IllegalStateException("Could not find original class structure", ex);
302 }
303 }
304 }
305
306
307
308
309
310 @SuppressWarnings("serial")
311 static class MethodParameterTypeProvider implements TypeProvider {
312
313 private final String methodName;
314
315 private final Class<?>[] parameterTypes;
316
317 private final Class<?> declaringClass;
318
319 private final int parameterIndex;
320
321 private transient MethodParameter methodParameter;
322
323 public MethodParameterTypeProvider(MethodParameter methodParameter) {
324 if (methodParameter.getMethod() != null) {
325 this.methodName = methodParameter.getMethod().getName();
326 this.parameterTypes = methodParameter.getMethod().getParameterTypes();
327 }
328 else {
329 this.methodName = null;
330 this.parameterTypes = methodParameter.getConstructor().getParameterTypes();
331 }
332 this.declaringClass = methodParameter.getDeclaringClass();
333 this.parameterIndex = methodParameter.getParameterIndex();
334 this.methodParameter = methodParameter;
335 }
336
337
338 @Override
339 public Type getType() {
340 return this.methodParameter.getGenericParameterType();
341 }
342
343 @Override
344 public Object getSource() {
345 return this.methodParameter;
346 }
347
348 private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
349 inputStream.defaultReadObject();
350 try {
351 if (this.methodName != null) {
352 this.methodParameter = new MethodParameter(
353 this.declaringClass.getDeclaredMethod(this.methodName, this.parameterTypes), this.parameterIndex);
354 }
355 else {
356 this.methodParameter = new MethodParameter(
357 this.declaringClass.getDeclaredConstructor(this.parameterTypes), this.parameterIndex);
358 }
359 }
360 catch (Throwable ex) {
361 throw new IllegalStateException("Could not find original class structure", ex);
362 }
363 }
364 }
365
366
367
368
369
370 @SuppressWarnings("serial")
371 static class MethodInvokeTypeProvider implements TypeProvider {
372
373 private final TypeProvider provider;
374
375 private final String methodName;
376
377 private final int index;
378
379 private transient Object result;
380
381 public MethodInvokeTypeProvider(TypeProvider provider, Method method, int index) {
382 this.provider = provider;
383 this.methodName = method.getName();
384 this.index = index;
385 this.result = ReflectionUtils.invokeMethod(method, provider.getType());
386 }
387
388 @Override
389 public Type getType() {
390 if (this.result instanceof Type || this.result == null) {
391 return (Type) this.result;
392 }
393 return ((Type[])this.result)[this.index];
394 }
395
396 @Override
397 public Object getSource() {
398 return null;
399 }
400
401 private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
402 inputStream.defaultReadObject();
403 Method method = ReflectionUtils.findMethod(this.provider.getType().getClass(), this.methodName);
404 this.result = ReflectionUtils.invokeMethod(method, this.provider.getType());
405 }
406 }
407
408 }