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 @SuppressWarnings( "checkstyle:magicnumber" )
305 StringBuilder key = new StringBuilder( 200 );
306
307 key.append( "(" );
308
309 for ( Class<?> param : params )
310 {
311 key.append( param.getName() );
312 key.append( "," );
313 }
314
315 if ( params.length > 0 )
316 {
317 key.setLength( key.length() - 1 );
318 }
319
320 key.append( ")" );
321
322 Constructor<?> constructor;
323
324 String paramKey = key.toString();
325
326 synchronized ( paramKey.intern() )
327 {
328 constructor = (Constructor<?>) constructorMap.get( paramKey );
329
330 if ( constructor == null )
331 {
332 Constructor<?>[] cands = targetClass.getConstructors();
333
334 for ( Constructor<?> cand : cands )
335 {
336 Class<?>[] types = cand.getParameterTypes();
337
338 if ( params.length != types.length )
339 {
340 continue;
341 }
342
343 for ( int j = 0, len2 = params.length; j < len2; j++ )
344 {
345 if ( !types[j].isAssignableFrom( params[j] ) )
346 {
347 continue;
348 }
349 }
350
351
352 constructor = cand;
353 constructorMap.put( paramKey, constructor );
354 }
355 }
356 }
357
358 if ( constructor == null )
359 {
360 throw new ReflectorException( "Error retrieving constructor object for: " + targetClass.getName()
361 + paramKey );
362 }
363
364 return constructor;
365 }
366
367 public Object getObjectProperty( Object target, String propertyName )
368 throws ReflectorException
369 {
370 Object returnValue;
371
372 if ( propertyName == null || propertyName.trim().length() < 1 )
373 {
374 throw new ReflectorException( "Cannot retrieve value for empty property." );
375 }
376
377 String beanAccessor = "get" + Character.toUpperCase( propertyName.charAt( 0 ) );
378 if ( propertyName.trim().length() > 1 )
379 {
380 beanAccessor += propertyName.substring( 1 ).trim();
381 }
382
383 Class<?> targetClass = target.getClass();
384 Class<?>[] emptyParams = {};
385
386 Method method = _getMethod( targetClass, beanAccessor, emptyParams );
387 if ( method == null )
388 {
389 method = _getMethod( targetClass, propertyName, emptyParams );
390 }
391
392 if ( method != null )
393 {
394 try
395 {
396 returnValue = method.invoke( target, new Object[] {} );
397 }
398 catch ( IllegalAccessException e )
399 {
400 throw new ReflectorException( "Error retrieving property \'" + propertyName + "\' from \'"
401 + targetClass + "\'", e );
402 }
403 catch ( InvocationTargetException e )
404 {
405 throw new ReflectorException( "Error retrieving property \'" + propertyName + "\' from \'"
406 + targetClass + "\'", e );
407 }
408 }
409 else
410 {
411 returnValue = getField( target, propertyName, true );
412 if ( returnValue == null )
413 {
414
415 throw new ReflectorException( "Neither method: \'" + propertyName + "\' nor bean accessor: \'"
416 + beanAccessor + "\' can be found for class: \'" + targetClass + "\', and retrieval of field: \'"
417 + propertyName + "\' returned null as value." );
418 }
419 }
420
421 return returnValue;
422 }
423
424
425
426
427
428
429
430
431
432 public Method getMethod( Class<?> targetClass, String methodName, Class<?>... params )
433 throws ReflectorException
434 {
435 Method method = _getMethod( targetClass, methodName, params );
436
437 if ( method == null )
438 {
439 throw new ReflectorException( "Method: \'" + methodName + "\' not found in class: \'" + targetClass
440 + "\'" );
441 }
442
443 return method;
444 }
445
446 @SuppressWarnings( "checkstyle:methodname" )
447 private Method _getMethod( Class<?> targetClass, String methodName, Class<?>... params )
448 throws ReflectorException
449 {
450 Map<String, Member> methodMap = getMethodMap( targetClass, methodName );
451
452 @SuppressWarnings( "checkstyle:magicnumber" )
453 StringBuilder key = new StringBuilder( 200 );
454
455 key.append( "(" );
456
457 for ( Class<?> param : params )
458 {
459 key.append( param.getName() );
460 key.append( "," );
461 }
462
463 key.append( ")" );
464
465 Method method;
466
467 String paramKey = key.toString();
468
469 synchronized ( paramKey.intern() )
470 {
471 method = (Method) methodMap.get( paramKey );
472
473 if ( method == null )
474 {
475 Method[] cands = targetClass.getMethods();
476
477 for ( Method cand : cands )
478 {
479 String name = cand.getName();
480
481 if ( !methodName.equals( name ) )
482 {
483 continue;
484 }
485
486 Class<?>[] types = cand.getParameterTypes();
487
488 if ( params.length != types.length )
489 {
490 continue;
491 }
492
493 for ( int j = 0, len2 = params.length; j < len2; j++ )
494 {
495 if ( !types[j].isAssignableFrom( params[j] ) )
496 {
497 continue;
498 }
499 }
500
501
502 method = cand;
503 methodMap.put( paramKey, method );
504 }
505 }
506 }
507
508 return method;
509 }
510
511
512
513
514
515
516
517
518 private Map<String, Member> getConstructorMap( Class<?> theClass )
519 throws ReflectorException
520 {
521 return getMethodMap( theClass, CONSTRUCTOR_METHOD_NAME );
522 }
523
524
525
526
527
528
529
530
531 private Map<String, Member> getMethodMap( Class<?> theClass, String methodName )
532 {
533 Map<String, Member> methodMap;
534
535 if ( theClass == null )
536 {
537 return null;
538 }
539
540 String className = theClass.getName();
541
542 synchronized ( className.intern() )
543 {
544 Map<String, Map<String, Member>> classMethods = classMaps.get( className );
545
546 if ( classMethods == null )
547 {
548 classMethods = new HashMap<String, Map<String, Member>>();
549 methodMap = new HashMap<String, Member>();
550 classMethods.put( methodName, methodMap );
551
552 classMaps.put( className, classMethods );
553 }
554 else
555 {
556 String key = className + "::" + methodName;
557
558 synchronized ( key.intern() )
559 {
560 methodMap = classMethods.get( methodName );
561
562 if ( methodMap == null )
563 {
564 methodMap = new HashMap<String, Member>();
565 classMethods.put( methodName, methodMap );
566 }
567 }
568 }
569 }
570
571 return methodMap;
572 }
573 }