1 package org.apache.maven.shared.utils.reflection;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.lang.reflect.Constructor;
23 import java.lang.reflect.Field;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Member;
26 import java.lang.reflect.Method;
27 import java.util.HashMap;
28 import java.util.Map;
29
30
31
32
33
34
35
36 final class Reflector
37 {
38 private static final String CONSTRUCTOR_METHOD_NAME = "$$CONSTRUCTOR$$";
39
40 private static final String GET_INSTANCE_METHOD_NAME = "getInstance";
41
42 private final Map<String, Map<String, Map<String, Member>>> classMaps =
43 new HashMap<String, Map<String, Map<String, Member>>>();
44
45
46
47
48 public Reflector()
49 {
50 }
51
52
53
54
55
56
57
58
59
60
61 public Object newInstance( Class<?> theClass, Object... params )
62 throws ReflectorException
63 {
64 if ( params == null )
65 {
66 params = new Object[0];
67 }
68
69 Class<?>[] paramTypes = new Class[params.length];
70
71 for ( int i = 0, len = params.length; i < len; i++ )
72 {
73 paramTypes[i] = params[i].getClass();
74 }
75
76 try
77 {
78 Constructor<?> con = getConstructor( theClass, paramTypes );
79
80 return con.newInstance( params );
81 }
82 catch ( InstantiationException ex )
83 {
84 throw new ReflectorException( ex );
85 }
86 catch ( InvocationTargetException ex )
87 {
88 throw new ReflectorException( ex );
89 }
90 catch ( IllegalAccessException ex )
91 {
92 throw new ReflectorException( ex );
93 }
94 }
95
96
97
98
99
100
101
102
103
104
105 public Object getSingleton( Class<?> theClass, Object... initParams )
106 throws ReflectorException
107 {
108 Class<?>[] paramTypes = new Class[initParams.length];
109
110 for ( int i = 0, len = initParams.length; i < len; i++ )
111 {
112 paramTypes[i] = initParams[i].getClass();
113 }
114
115 try
116 {
117 Method method = getMethod( theClass, GET_INSTANCE_METHOD_NAME, paramTypes );
118
119 return method.invoke( null, initParams );
120 }
121 catch ( InvocationTargetException ex )
122 {
123 throw new ReflectorException( ex );
124 }
125 catch ( IllegalAccessException ex )
126 {
127 throw new ReflectorException( ex );
128 }
129 }
130
131
132
133
134
135
136
137
138
139
140 public Object invoke( Object target, String methodName, Object... params )
141 throws ReflectorException
142 {
143 if ( params == null )
144 {
145 params = new Object[0];
146 }
147
148 Class<?>[] paramTypes = new Class[params.length];
149
150 for ( int i = 0, len = params.length; i < len; i++ )
151 {
152 paramTypes[i] = params[i].getClass();
153 }
154
155 try
156 {
157 Method method = getMethod( target.getClass(), methodName, paramTypes );
158
159 return method.invoke( target, params );
160 }
161 catch ( InvocationTargetException ex )
162 {
163 throw new ReflectorException( ex );
164 }
165 catch ( IllegalAccessException ex )
166 {
167 throw new ReflectorException( ex );
168 }
169 }
170
171 public Object getStaticField( Class<?> targetClass, String fieldName )
172 throws ReflectorException
173 {
174 try
175 {
176 Field field = targetClass.getField( fieldName );
177
178 return field.get( null );
179 }
180 catch ( SecurityException e )
181 {
182 throw new ReflectorException( e );
183 }
184 catch ( NoSuchFieldException e )
185 {
186 throw new ReflectorException( e );
187 }
188 catch ( IllegalArgumentException e )
189 {
190 throw new ReflectorException( e );
191 }
192 catch ( IllegalAccessException e )
193 {
194 throw new ReflectorException( e );
195 }
196 }
197
198 public Object getField( Object target, String fieldName )
199 throws ReflectorException
200 {
201 return getField( target, fieldName, false );
202 }
203
204 public Object getField( Object target, String fieldName, boolean breakAccessibility )
205 throws ReflectorException
206 {
207 Class<?> targetClass = target.getClass();
208 while ( targetClass != null )
209 {
210 try
211 {
212 Field field = targetClass.getDeclaredField( fieldName );
213
214 boolean accessibilityBroken = false;
215 if ( !field.isAccessible() && breakAccessibility )
216 {
217 field.setAccessible( true );
218 accessibilityBroken = true;
219 }
220
221 Object result = field.get( target );
222
223 if ( accessibilityBroken )
224 {
225 field.setAccessible( false );
226 }
227
228 return result;
229 }
230 catch ( SecurityException e )
231 {
232 throw new ReflectorException( e );
233 }
234 catch ( NoSuchFieldException e )
235 {
236 if ( targetClass == Object.class )
237 {
238 throw new ReflectorException( e );
239 }
240 targetClass = targetClass.getSuperclass();
241 }
242 catch ( IllegalAccessException e )
243 {
244 throw new ReflectorException( e );
245 }
246 }
247
248 return null;
249 }
250
251
252
253
254
255
256
257
258
259
260 public Object invokeStatic( Class<?> targetClass, String methodName, Object... params )
261 throws ReflectorException
262 {
263 if ( params == null )
264 {
265 params = new Object[0];
266 }
267
268 Class<?>[] paramTypes = new Class[params.length];
269
270 for ( int i = 0, len = params.length; i < len; i++ )
271 {
272 paramTypes[i] = params[i].getClass();
273 }
274
275 try
276 {
277 Method method = getMethod( targetClass, methodName, paramTypes );
278
279 return method.invoke( null, params );
280 }
281 catch ( InvocationTargetException ex )
282 {
283 throw new ReflectorException( ex );
284 }
285 catch ( IllegalAccessException ex )
286 {
287 throw new ReflectorException( ex );
288 }
289 }
290
291
292
293
294
295
296
297
298
299 public Constructor<?> getConstructor( Class<?> targetClass, Class<?>... params )
300 throws ReflectorException
301 {
302 Map<String, Member> constructorMap = getConstructorMap( targetClass );
303
304 StringBuilder key = new StringBuilder( 200 );
305
306 key.append( "(" );
307
308 for ( Class<?> param : params )
309 {
310 key.append( param.getName() );
311 key.append( "," );
312 }
313
314 if ( params.length > 0 )
315 {
316 key.setLength( key.length() - 1 );
317 }
318
319 key.append( ")" );
320
321 Constructor<?> constructor;
322
323 String paramKey = key.toString();
324
325 synchronized ( paramKey.intern() )
326 {
327 constructor = (Constructor<?>) constructorMap.get( paramKey );
328
329 if ( constructor == null )
330 {
331 Constructor<?>[] cands = targetClass.getConstructors();
332
333 for ( Constructor<?> cand : cands )
334 {
335 Class<?>[] types = cand.getParameterTypes();
336
337 if ( params.length != types.length )
338 {
339 continue;
340 }
341
342 for ( int j = 0, len2 = params.length; j < len2; j++ )
343 {
344 if ( !types[j].isAssignableFrom( params[j] ) )
345 {
346 continue;
347 }
348 }
349
350
351 constructor = cand;
352 constructorMap.put( paramKey, constructor );
353 }
354 }
355 }
356
357 if ( constructor == null )
358 {
359 throw new ReflectorException( "Error retrieving constructor object for: " + targetClass.getName()
360 + paramKey );
361 }
362
363 return constructor;
364 }
365
366 public Object getObjectProperty( Object target, String propertyName )
367 throws ReflectorException
368 {
369 Object returnValue;
370
371 if ( propertyName == null || propertyName.trim().length() < 1 )
372 {
373 throw new ReflectorException( "Cannot retrieve value for empty property." );
374 }
375
376 String beanAccessor = "get" + Character.toUpperCase( propertyName.charAt( 0 ) );
377 if ( propertyName.trim().length() > 1 )
378 {
379 beanAccessor += propertyName.substring( 1 ).trim();
380 }
381
382 Class<?> targetClass = target.getClass();
383 Class<?>[] emptyParams = {};
384
385 Method method = _getMethod( targetClass, beanAccessor, emptyParams );
386 if ( method == null )
387 {
388 method = _getMethod( targetClass, propertyName, emptyParams );
389 }
390
391 if ( method != null )
392 {
393 try
394 {
395 returnValue = method.invoke( target, new Object[] {} );
396 }
397 catch ( IllegalAccessException e )
398 {
399 throw new ReflectorException( "Error retrieving property \'" + propertyName + "\' from \'"
400 + targetClass + "\'", e );
401 }
402 catch ( InvocationTargetException e )
403 {
404 throw new ReflectorException( "Error retrieving property \'" + propertyName + "\' from \'"
405 + targetClass + "\'", e );
406 }
407 }
408 else
409 {
410 returnValue = getField( target, propertyName, true );
411 if ( returnValue == null )
412 {
413
414 throw new ReflectorException( "Neither method: \'" + propertyName + "\' nor bean accessor: \'"
415 + beanAccessor + "\' can be found for class: \'" + targetClass + "\', and retrieval of field: \'"
416 + propertyName + "\' returned null as value." );
417 }
418 }
419
420 return returnValue;
421 }
422
423
424
425
426
427
428
429
430
431 public Method getMethod( Class<?> targetClass, String methodName, Class<?>... params )
432 throws ReflectorException
433 {
434 Method method = _getMethod( targetClass, methodName, params );
435
436 if ( method == null )
437 {
438 throw new ReflectorException( "Method: \'" + methodName + "\' not found in class: \'" + targetClass + "\'" );
439 }
440
441 return method;
442 }
443
444 private Method _getMethod( Class<?> targetClass, String methodName, Class<?>... params )
445 throws ReflectorException
446 {
447 Map<String, Member> methodMap = getMethodMap( targetClass, methodName );
448
449 StringBuilder key = new StringBuilder( 200 );
450
451 key.append( "(" );
452
453 for ( Class<?> param : params )
454 {
455 key.append( param.getName() );
456 key.append( "," );
457 }
458
459 key.append( ")" );
460
461 Method method;
462
463 String paramKey = key.toString();
464
465 synchronized ( paramKey.intern() )
466 {
467 method = (Method) methodMap.get( paramKey );
468
469 if ( method == null )
470 {
471 Method[] cands = targetClass.getMethods();
472
473 for ( Method cand : cands )
474 {
475 String name = cand.getName();
476
477 if ( !methodName.equals( name ) )
478 {
479 continue;
480 }
481
482 Class<?>[] types = cand.getParameterTypes();
483
484 if ( params.length != types.length )
485 {
486 continue;
487 }
488
489 for ( int j = 0, len2 = params.length; j < len2; j++ )
490 {
491 if ( !types[j].isAssignableFrom( params[j] ) )
492 {
493 continue;
494 }
495 }
496
497
498 method = cand;
499 methodMap.put( paramKey, method );
500 }
501 }
502 }
503
504 return method;
505 }
506
507
508
509
510
511
512
513
514 private Map<String, Member> getConstructorMap( Class<?> theClass )
515 throws ReflectorException
516 {
517 return getMethodMap( theClass, CONSTRUCTOR_METHOD_NAME );
518 }
519
520
521
522
523
524
525
526
527 private Map<String, Member> getMethodMap( Class<?> theClass, String methodName )
528 {
529 Map<String, Member> methodMap;
530
531 if ( theClass == null )
532 {
533 return null;
534 }
535
536 String className = theClass.getName();
537
538 synchronized ( className.intern() )
539 {
540 Map<String, Map<String, Member>> classMethods = classMaps.get( className );
541
542 if ( classMethods == null )
543 {
544 classMethods = new HashMap<String, Map<String, Member>>();
545 methodMap = new HashMap<String, Member>();
546 classMethods.put( methodName, methodMap );
547
548 classMaps.put( className, classMethods );
549 }
550 else
551 {
552 String key = className + "::" + methodName;
553
554 synchronized ( key.intern() )
555 {
556 methodMap = classMethods.get( methodName );
557
558 if ( methodMap == null )
559 {
560 methodMap = new HashMap<String, Member>();
561 classMethods.put( methodName, methodMap );
562 }
563 }
564 }
565 }
566
567 return methodMap;
568 }
569 }