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).
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).
4142 *
4243 * @author Andy Clement
4344 * @author Juergen Hoeller
4445 * @since 3.0
4546 */
4647public class ReflectivePropertyAccessor implements PropertyAccessor {
4748
48- protected final Map <CacheKey , InvokerPair > readerCache = new ConcurrentHashMap <CacheKey , InvokerPair >();
49+ private final Map <CacheKey , InvokerPair > readerCache = new ConcurrentHashMap <CacheKey , InvokerPair >();
4950
50- protected final Map <CacheKey , Member > writerCache = new ConcurrentHashMap <CacheKey , Member >();
51+ private final Map <CacheKey , Member > writerCache = new ConcurrentHashMap <CacheKey , Member >();
5152
52- protected final Map <CacheKey , TypeDescriptor > typeDescriptorCache = new ConcurrentHashMap <CacheKey , TypeDescriptor >();
53+ private final Map <CacheKey , TypeDescriptor > typeDescriptorCache = new ConcurrentHashMap <CacheKey , TypeDescriptor >();
5354
5455
5556/**
@@ -365,52 +366,6 @@ protected Field findField(String name, Class<?> clazz, boolean mustBeStatic) {
365366return null ;
366367}
367368
368- /**
369- * Captures the member (method/field) to call reflectively to access a property value and the type descriptor for the
370- * value returned by the reflective call.
371- */
372- private static class InvokerPair {
373-
374- final Member member ;
375-
376- final TypeDescriptor typeDescriptor ;
377-
378- public InvokerPair (Member member , TypeDescriptor typeDescriptor ) {
379- this .member = member ;
380- this .typeDescriptor = typeDescriptor ;
381- }
382-
383- }
384-
385- private static class CacheKey {
386-
387- private final Class clazz ;
388-
389- private final String name ;
390-
391- public CacheKey (Class clazz , String name ) {
392- this .clazz = clazz ;
393- this .name = name ;
394- }
395-
396- @ Override
397- public boolean equals (Object other ) {
398- if (this == other ) {
399- return true ;
400- }
401- if (!(other instanceof CacheKey )) {
402- return false ;
403- }
404- CacheKey otherKey = (CacheKey ) other ;
405- return (this .clazz .equals (otherKey .clazz ) && this .name .equals (otherKey .name ));
406- }
407-
408- @ Override
409- public int hashCode () {
410- return this .clazz .hashCode () * 29 + this .name .hashCode ();
411- }
412- }
413-
414369/**
415370 * Attempt to create an optimized property accessor tailored for a property of a particular name on
416371 * a particular class. The general ReflectivePropertyAccessor will always work but is not optimal
@@ -463,29 +418,82 @@ public PropertyAccessor createOptimalAccessor(EvaluationContext eContext, Object
463418return this ;
464419}
465420
421+
422+ /**
423+ * Captures the member (method/field) to call reflectively to access a property value
424+ * and the type descriptor for the value returned by the reflective call.
425+ */
426+ private static class InvokerPair {
427+
428+ final Member member ;
429+
430+ final TypeDescriptor typeDescriptor ;
431+
432+ public InvokerPair (Member member , TypeDescriptor typeDescriptor ) {
433+ this .member = member ;
434+ this .typeDescriptor = typeDescriptor ;
435+ }
436+ }
437+
438+
439+ private static class CacheKey {
440+
441+ private final Class clazz ;
442+
443+ private final String name ;
444+
445+ public CacheKey (Class clazz , String name ) {
446+ this .clazz = clazz ;
447+ this .name = name ;
448+ }
449+
450+ @ Override
451+ public boolean equals (Object other ) {
452+ if (this == other ) {
453+ return true ;
454+ }
455+ if (!(other instanceof CacheKey )) {
456+ return false ;
457+ }
458+ CacheKey otherKey = (CacheKey ) other ;
459+ return (this .clazz .equals (otherKey .clazz ) && this .name .equals (otherKey .name ));
460+ }
461+
462+ @ Override
463+ public int hashCode () {
464+ return this .clazz .hashCode () * 29 + this .name .hashCode ();
465+ }
466+ }
467+
468+
466469/**
467- * An optimized form of a PropertyAccessor that will use reflection but only knows how to access a particular property
468- * on a particular class. This is unlike the general ReflectivePropertyResolver which manages a cache of methods/fields that
469- * may be invoked to access different properties on different classes. This optimal accessor exists because looking up
470- * the appropriate reflective object by class/name on each read is not cheap.
470+ * An optimized form of a PropertyAccessor that will use reflection but only knows
471+ * how to access a particular property on a particular class. This is unlike the
472+ * general ReflectivePropertyResolver which manages a cache of methods/fields that
473+ * may be invoked to access different properties on different classes. This optimal
474+ * accessor exists because looking up the appropriate reflective object by class/name
475+ * on each read is not cheap.
471476 */
472- static class OptimalPropertyAccessor implements PropertyAccessor {
477+ private static class OptimalPropertyAccessor implements PropertyAccessor {
478+
473479private final Member member ;
480+
474481private final TypeDescriptor typeDescriptor ;
482+
475483private final boolean needsToBeMadeAccessible ;
476484
477485OptimalPropertyAccessor (InvokerPair target ) {
478486this .member = target .member ;
479487this .typeDescriptor = target .typeDescriptor ;
480488if (this .member instanceof Field ) {
481- Field field = (Field )member ;
482- needsToBeMadeAccessible = (!Modifier .isPublic (field .getModifiers ()) || ! Modifier . isPublic ( field . getDeclaringClass (). getModifiers ()))
483- && !field .isAccessible ();
489+ Field field = (Field ) this . member ;
490+ this . needsToBeMadeAccessible = (!Modifier .isPublic (field .getModifiers ()) ||
491+ ! Modifier . isPublic ( field . getDeclaringClass (). getModifiers ())) && !field .isAccessible ();
484492}
485493else {
486- Method method = (Method )member ;
487- needsToBeMadeAccessible = ((!Modifier .isPublic (method .getModifiers ()) || ! Modifier . isPublic ( method . getDeclaringClass (). getModifiers ()))
488- && !method .isAccessible ());
494+ Method method = (Method ) this . member ;
495+ this . needsToBeMadeAccessible = ((!Modifier .isPublic (method .getModifiers ()) ||
496+ ! Modifier . isPublic ( method . getDeclaringClass (). getModifiers ())) && !method .isAccessible ());
489497}
490498}
491499
@@ -501,8 +509,8 @@ public boolean canRead(EvaluationContext context, Object target, String name) th
501509if (type .isArray ()) {
502510return false ;
503511}
504- if (member instanceof Method ) {
505- Method method = (Method )member ;
512+ if (this . member instanceof Method ) {
513+ Method method = (Method ) this . member ;
506514String getterName = "get" + StringUtils .capitalize (name );
507515if (getterName .equals (method .getName ())) {
508516return true ;
@@ -511,31 +519,31 @@ public boolean canRead(EvaluationContext context, Object target, String name) th
511519return getterName .equals (method .getName ());
512520}
513521else {
514- Field field = (Field )member ;
522+ Field field = (Field ) this . member ;
515523return field .getName ().equals (name );
516524}
517525}
518526
519527public TypedValue read (EvaluationContext context , Object target , String name ) throws AccessException {
520- if (member instanceof Method ) {
528+ if (this . member instanceof Method ) {
521529try {
522- if (needsToBeMadeAccessible ) {
523- ReflectionUtils .makeAccessible ((Method ) member );
530+ if (this . needsToBeMadeAccessible ) {
531+ ReflectionUtils .makeAccessible ((Method ) this . member );
524532}
525- Object value = ((Method ) member ).invoke (target );
526- return new TypedValue (value , typeDescriptor .narrow (value ));
533+ Object value = ((Method ) this . member ).invoke (target );
534+ return new TypedValue (value , this . typeDescriptor .narrow (value ));
527535}
528536catch (Exception ex ) {
529537throw new AccessException ("Unable to access property '" + name + "' through getter" , ex );
530538}
531539}
532- if (member instanceof Field ) {
540+ if (this . member instanceof Field ) {
533541try {
534- if (needsToBeMadeAccessible ) {
535- ReflectionUtils .makeAccessible ((Field )member );
542+ if (this . needsToBeMadeAccessible ) {
543+ ReflectionUtils .makeAccessible ((Field ) this . member );
536544}
537- Object value = ((Field )member ).get (target );
538- return new TypedValue (value , typeDescriptor .narrow (value ));
545+ Object value = ((Field ) this . member ).get (target );
546+ return new TypedValue (value , this . typeDescriptor .narrow (value ));
539547}
540548catch (Exception ex ) {
541549throw new AccessException ("Unable to access field: " + name , ex );
@@ -544,12 +552,11 @@ public TypedValue read(EvaluationContext context, Object target, String name) th
544552throw new AccessException ("Neither getter nor field found for property '" + name + "'" );
545553}
546554
547- public boolean canWrite (EvaluationContext context , Object target , String name ) throws AccessException {
555+ public boolean canWrite (EvaluationContext context , Object target , String name ) {
548556throw new UnsupportedOperationException ("Should not be called on an OptimalPropertyAccessor" );
549557}
550558
551- public void write (EvaluationContext context , Object target , String name , Object newValue )
552- throws AccessException {
559+ public void write (EvaluationContext context , Object target , String name , Object newValue ) {
553560throw new UnsupportedOperationException ("Should not be called on an OptimalPropertyAccessor" );
554561}
555562}
0 commit comments