3636import  org .springframework .util .StringUtils ;
3737
3838/** 
39-  * Simple PropertyAccessor that uses reflection to access properties for reading and writing. A property can be accessed 
40-  * if it is accessible as a field on the object or through a getter (if being read) or a setter (if being written).  
41-  *  
39+  * Simple PropertyAccessor that uses reflection to access properties for reading and writing. 
40+  * A property can be accessed if it is accessible as a field on the object or through a 
41+  * getter (if being read) or a setter (if being written). 
42+  * 
4243 * @author Andy Clement 
4344 * @author Juergen Hoeller 
4445 * @since 3.0 
@@ -48,7 +49,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
4849	protected  final  Map <CacheKey , InvokerPair > readerCache  = new  ConcurrentHashMap <CacheKey , InvokerPair >();
4950
5051	protected  final  Map <CacheKey , Member > writerCache  = new  ConcurrentHashMap <CacheKey , Member >();
51- 	 
52+ 
5253	protected  final  Map <CacheKey , TypeDescriptor > typeDescriptorCache  = new  ConcurrentHashMap <CacheKey , TypeDescriptor >();
5354
5455
@@ -252,7 +253,7 @@ public void write(EvaluationContext context, Object target, String name, Object
252253
253254		throw  new  AccessException ("Neither setter nor field found for property '"  + name  + "'" );
254255	}
255- 	 
256+ 
256257	private  TypeDescriptor  getTypeDescriptor (EvaluationContext  context , Object  target , String  name ) {
257258		if  (target  == null ) {
258259			return  null ;
@@ -306,23 +307,24 @@ private Field findField(String name, Class<?> clazz, Object target) {
306307	}
307308
308309	/** 
309- 	 * Find a getter method for the specified property. A getter is defined as a method whose name start with the prefix 
310- 	 * 'get' and the rest of the name is the same as the property name (with the first character uppercased). 
310+ 	 * Find a getter method for the specified property. 
311+ 	 * <p>A getter is defined as a method whose name start with the prefix 'get' and the 
312+ 	 * rest of the name is the same as the property name (with the first character uppercased). 
311313	 */ 
312314	protected  Method  findGetterForProperty (String  propertyName , Class <?> clazz , boolean  mustBeStatic ) {
313315		Method [] ms  = clazz .getMethods ();
314316		// Try "get*" method... 
315317		String  getterName  = "get"  + StringUtils .capitalize (propertyName );
316318		for  (Method  method  : ms ) {
317- 			if  (method .getName ().equals (getterName ) && method .getParameterTypes ().length  == 0  &&
319+ 			if  (! method . isBridge () &&  method .getName ().equals (getterName ) && method .getParameterTypes ().length  == 0  &&
318320					(!mustBeStatic  || Modifier .isStatic (method .getModifiers ()))) {
319321				return  method ;
320322			}
321323		}
322324		// Try "is*" method... 
323325		getterName  = "is"  + StringUtils .capitalize (propertyName );
324326		for  (Method  method  : ms ) {
325- 			if  (method .getName ().equals (getterName ) && method .getParameterTypes ().length  == 0  &&
327+ 			if  (! method . isBridge () &&  method .getName ().equals (getterName ) && method .getParameterTypes ().length  == 0  &&
326328					boolean .class .equals (method .getReturnType ()) &&
327329					(!mustBeStatic  || Modifier .isStatic (method .getModifiers ()))) {
328330				return  method ;
@@ -338,7 +340,7 @@ protected Method findSetterForProperty(String propertyName, Class<?> clazz, bool
338340		Method [] methods  = clazz .getMethods ();
339341		String  setterName  = "set"  + StringUtils .capitalize (propertyName );
340342		for  (Method  method  : methods ) {
341- 			if  (method .getName ().equals (setterName ) && method .getParameterTypes ().length  == 1  &&
343+ 			if  (! method . isBridge () &&  method .getName ().equals (setterName ) && method .getParameterTypes ().length  == 1  &&
342344					(!mustBeStatic  || Modifier .isStatic (method .getModifiers ()))) {
343345				return  method ;
344346			}
@@ -358,56 +360,10 @@ protected Field findField(String name, Class<?> clazz, boolean mustBeStatic) {
358360		}
359361		return  null ;
360362	}
361- 	
362- 	/** 
363- 	 * Captures the member (method/field) to call reflectively to access a property value and the type descriptor for the 
364- 	 * value returned by the reflective call. 
365- 	 */ 
366- 	private  static  class  InvokerPair  {
367- 		
368- 		final  Member  member ;
369- 		
370- 		final  TypeDescriptor  typeDescriptor ;
371- 
372- 		public  InvokerPair (Member  member , TypeDescriptor  typeDescriptor ) {
373- 			this .member  = member ;
374- 			this .typeDescriptor  = typeDescriptor ;
375- 		}	
376- 		
377- 	}
378363
379- 	private  static  class  CacheKey  {
380- 
381- 		private  final  Class  clazz ;
382- 
383- 		private  final  String  name ;
384- 
385- 		public  CacheKey (Class  clazz , String  name ) {
386- 			this .clazz  = clazz ;
387- 			this .name  = name ;
388- 		}
389- 
390- 		@ Override 
391- 		public  boolean  equals (Object  other ) {
392- 			if  (this  == other ) {
393- 				return  true ;
394- 			}
395- 			if  (!(other  instanceof  CacheKey )) {
396- 				return  false ;
397- 			}
398- 			CacheKey  otherKey  = (CacheKey ) other ;
399- 			return  (this .clazz .equals (otherKey .clazz ) && this .name .equals (otherKey .name ));
400- 		}
401- 
402- 		@ Override 
403- 		public  int  hashCode () {
404- 			return  this .clazz .hashCode () * 29  + this .name .hashCode ();
405- 		}
406- 	}
407- 
408- 	/**  
364+ 	/** 
409365	 * Attempt to create an optimized property accessor tailored for a property of a particular name on 
410- 	 * a particular class. The general ReflectivePropertyAccessor will always work but is not optimal   
366+ 	 * a particular class. The general ReflectivePropertyAccessor will always work but is not optimal 
411367	 * due to the need to lookup which reflective member (method/field) to use each time read() is called. 
412368	 * This method will just return the ReflectivePropertyAccessor instance if it is unable to build 
413369	 * something more optimal. 
@@ -456,37 +412,90 @@ public PropertyAccessor createOptimalAccessor(EvaluationContext eContext, Object
456412		}
457413		return  this ;
458414	}
459- 	
415+ 
416+ 
417+ 	/** 
418+ 	 * Captures the member (method/field) to call reflectively to access a property value 
419+ 	 * and the type descriptor for the value returned by the reflective call. 
420+ 	 */ 
421+ 	private  static  class  InvokerPair  {
422+ 
423+ 		final  Member  member ;
424+ 
425+ 		final  TypeDescriptor  typeDescriptor ;
426+ 
427+ 		public  InvokerPair (Member  member , TypeDescriptor  typeDescriptor ) {
428+ 			this .member  = member ;
429+ 			this .typeDescriptor  = typeDescriptor ;
430+ 		}
431+ 	}
432+ 
433+ 
434+ 	private  static  class  CacheKey  {
435+ 
436+ 		private  final  Class  clazz ;
437+ 
438+ 		private  final  String  name ;
439+ 
440+ 		public  CacheKey (Class  clazz , String  name ) {
441+ 			this .clazz  = clazz ;
442+ 			this .name  = name ;
443+ 		}
444+ 
445+ 		@ Override 
446+ 		public  boolean  equals (Object  other ) {
447+ 			if  (this  == other ) {
448+ 				return  true ;
449+ 			}
450+ 			if  (!(other  instanceof  CacheKey )) {
451+ 				return  false ;
452+ 			}
453+ 			CacheKey  otherKey  = (CacheKey ) other ;
454+ 			return  (this .clazz .equals (otherKey .clazz ) && this .name .equals (otherKey .name ));
455+ 		}
456+ 
457+ 		@ Override 
458+ 		public  int  hashCode () {
459+ 			return  this .clazz .hashCode () * 29  + this .name .hashCode ();
460+ 		}
461+ 	}
462+ 
463+ 
460464	/** 
461- 	 * An optimized form of a PropertyAccessor that will use reflection but only knows how to access a particular property  
462- 	 * on a particular class.  This is unlike the general ReflectivePropertyResolver which manages a cache of methods/fields that  
463- 	 * may be invoked to access different properties on different classes.  This optimal accessor exists because looking up 
464- 	 * the appropriate reflective object by class/name on each read is not cheap. 
465+ 	 * An optimized form of a PropertyAccessor that will use reflection but only knows 
466+ 	 * how to access a particular property on a particular class. This is unlike the 
467+ 	 * general ReflectivePropertyResolver which manages a cache of methods/fields that 
468+ 	 * may be invoked to access different properties on different classes. This optimal 
469+ 	 * accessor exists because looking up the appropriate reflective object by class/name 
470+ 	 * on each read is not cheap. 
465471	 */ 
466- 	static  class  OptimalPropertyAccessor  implements  PropertyAccessor  {
472+ 	private  static  class  OptimalPropertyAccessor  implements  PropertyAccessor  {
473+ 
467474		private  final  Member  member ;
475+ 
468476		private  final  TypeDescriptor  typeDescriptor ;
477+ 
469478		private  final  boolean  needsToBeMadeAccessible ;
470- 		 
479+ 
471480		OptimalPropertyAccessor (InvokerPair  target ) {
472- 			this .member  = target .member ;			 
481+ 			this .member  = target .member ;
473482			this .typeDescriptor  = target .typeDescriptor ;
474483			if  (this .member  instanceof  Field ) {
475- 				Field  field  = (Field )member ;
476- 				needsToBeMadeAccessible  = (!Modifier .isPublic (field .getModifiers ()) || ! Modifier . isPublic ( field . getDeclaringClass (). getModifiers ()))  
477- 				&& !field .isAccessible ();
484+ 				Field  field  = (Field )  this . member ;
485+ 				this . needsToBeMadeAccessible  = (!Modifier .isPublic (field .getModifiers ()) ||
486+ 						! Modifier . isPublic ( field . getDeclaringClass (). getModifiers ()))  && !field .isAccessible ();
478487			}
479488			else  {
480- 				Method  method  = (Method )member ;
481- 				needsToBeMadeAccessible  = ((!Modifier .isPublic (method .getModifiers ()) || ! Modifier . isPublic ( method . getDeclaringClass (). getModifiers ())) 
482- 						&& !method .isAccessible ());
489+ 				Method  method  = (Method )  this . member ;
490+ 				this . needsToBeMadeAccessible  = ((!Modifier .isPublic (method .getModifiers ()) ||
491+ 						! Modifier . isPublic ( method . getDeclaringClass (). getModifiers ()))  && !method .isAccessible ());
483492			}
484493		}
485494
486495		public  Class [] getSpecificTargetClasses () {
487496			throw  new  UnsupportedOperationException ("Should not be called on an OptimalPropertyAccessor" );
488497		}
489- 		 
498+ 
490499		public  boolean  canRead (EvaluationContext  context , Object  target , String  name ) throws  AccessException  {
491500			if  (target  == null ) {
492501				return  false ;
@@ -495,8 +504,8 @@ public boolean canRead(EvaluationContext context, Object target, String name) th
495504			if  (type .isArray ()) {
496505				return  false ;
497506			}
498- 			if  (member  instanceof  Method ) {
499- 				Method  method  = (Method )member ;
507+ 			if  (this . member  instanceof  Method ) {
508+ 				Method  method  = (Method )  this . member ;
500509				String  getterName  = "get"  + StringUtils .capitalize (name );
501510				if  (getterName .equals (method .getName ())) {
502511					return  true ;
@@ -505,31 +514,31 @@ public boolean canRead(EvaluationContext context, Object target, String name) th
505514				return  getterName .equals (method .getName ());
506515			}
507516			else  {
508- 				Field  field  = (Field )member ;
517+ 				Field  field  = (Field )  this . member ;
509518				return  field .getName ().equals (name );
510519			}
511520		}
512521
513522		public  TypedValue  read (EvaluationContext  context , Object  target , String  name ) throws  AccessException  {
514- 			if  (member  instanceof  Method ) {
523+ 			if  (this . member  instanceof  Method ) {
515524				try  {
516- 					if  (needsToBeMadeAccessible ) {
517- 						ReflectionUtils .makeAccessible ((Method ) member );
525+ 					if  (this . needsToBeMadeAccessible ) {
526+ 						ReflectionUtils .makeAccessible ((Method ) this . member );
518527					}
519- 					Object  value  = ((Method ) member ).invoke (target );
520- 					return  new  TypedValue (value , typeDescriptor .narrow (value ));
528+ 					Object  value  = ((Method ) this . member ).invoke (target );
529+ 					return  new  TypedValue (value , this . typeDescriptor .narrow (value ));
521530				}
522531				catch  (Exception  ex ) {
523532					throw  new  AccessException ("Unable to access property '"  + name  + "' through getter" , ex );
524533				}
525- 			}		 
526- 			if  (member  instanceof  Field ) {
534+ 			}
535+ 			if  (this . member  instanceof  Field ) {
527536				try  {
528- 					if  (needsToBeMadeAccessible ) {
529- 						ReflectionUtils .makeAccessible ((Field )member );
537+ 					if  (this . needsToBeMadeAccessible ) {
538+ 						ReflectionUtils .makeAccessible ((Field )  this . member );
530539					}
531- 					Object  value  = ((Field )member ).get (target );
532- 					return  new  TypedValue (value , typeDescriptor .narrow (value ));
540+ 					Object  value  = ((Field )  this . member ).get (target );
541+ 					return  new  TypedValue (value , this . typeDescriptor .narrow (value ));
533542				}
534543				catch  (Exception  ex ) {
535544					throw  new  AccessException ("Unable to access field: "  + name , ex );
@@ -538,12 +547,11 @@ public TypedValue read(EvaluationContext context, Object target, String name) th
538547			throw  new  AccessException ("Neither getter nor field found for property '"  + name  + "'" );
539548		}
540549
541- 		public  boolean  canWrite (EvaluationContext  context , Object  target , String  name ) throws   AccessException   {
550+ 		public  boolean  canWrite (EvaluationContext  context , Object  target , String  name ) {
542551			throw  new  UnsupportedOperationException ("Should not be called on an OptimalPropertyAccessor" );
543552		}
544- 		
545- 		public  void  write (EvaluationContext  context , Object  target , String  name , Object  newValue )
546- 				throws  AccessException  {
553+ 
554+ 		public  void  write (EvaluationContext  context , Object  target , String  name , Object  newValue ) {
547555			throw  new  UnsupportedOperationException ("Should not be called on an OptimalPropertyAccessor" );
548556		}
549557	}
0 commit comments