1
1
/*
2
- * Copyright 2002-2014 the original author or authors.
2
+ * Copyright 2002-2015 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
58
58
*/
59
59
public class ReflectivePropertyAccessor implements PropertyAccessor {
60
60
61
+ private static final Set <Class <?>> ANY_TYPES = Collections .emptySet ();
62
+
61
63
private static final Set <Class <?>> BOOLEAN_TYPES ;
64
+
62
65
static {
63
66
Set <Class <?>> booleanTypes = new HashSet <Class <?>>();
64
67
booleanTypes .add (Boolean .class );
65
68
booleanTypes .add (Boolean .TYPE );
66
69
BOOLEAN_TYPES = Collections .unmodifiableSet (booleanTypes );
67
70
}
68
71
69
- private static final Set <Class <?>> ANY_TYPES = Collections .emptySet ();
70
-
71
72
72
73
private final Map <CacheKey , InvokerPair > readerCache = new ConcurrentHashMap <CacheKey , InvokerPair >(64 );
73
74
@@ -120,9 +121,9 @@ public boolean canRead(EvaluationContext context, Object target, String name) th
120
121
}
121
122
return false ;
122
123
}
123
-
124
+
124
125
public Member getLastReadInvokerPair () {
125
- return lastReadInvokerPair .member ;
126
+ return this . lastReadInvokerPair .member ;
126
127
}
127
128
128
129
@ Override
@@ -165,7 +166,7 @@ public TypedValue read(EvaluationContext context, Object target, String name) th
165
166
return new TypedValue (value , invoker .typeDescriptor .narrow (value ));
166
167
}
167
168
catch (Exception ex ) {
168
- throw new AccessException ("Unable to access property '" + name + "' through getter" , ex );
169
+ throw new AccessException ("Unable to access property '" + name + "' through getter method " , ex );
169
170
}
170
171
}
171
172
}
@@ -187,12 +188,12 @@ public TypedValue read(EvaluationContext context, Object target, String name) th
187
188
return new TypedValue (value , invoker .typeDescriptor .narrow (value ));
188
189
}
189
190
catch (Exception ex ) {
190
- throw new AccessException ("Unable to access field: " + name , ex );
191
+ throw new AccessException ("Unable to access field ' " + name + "'" , ex );
191
192
}
192
193
}
193
194
}
194
195
195
- throw new AccessException ("Neither getter nor field found for property '" + name + "'" );
196
+ throw new AccessException ("Neither getter method nor field found for property '" + name + "'" );
196
197
}
197
198
198
199
@ Override
@@ -240,7 +241,7 @@ public void write(EvaluationContext context, Object target, String name, Object
240
241
newValue , TypeDescriptor .forObject (newValue ), typeDescriptor );
241
242
}
242
243
catch (EvaluationException evaluationException ) {
243
- throw new AccessException ("Type conversion failure" ,evaluationException );
244
+ throw new AccessException ("Type conversion failure" , evaluationException );
244
245
}
245
246
}
246
247
CacheKey cacheKey = new CacheKey (type , name , target instanceof Class );
@@ -262,7 +263,7 @@ public void write(EvaluationContext context, Object target, String name, Object
262
263
return ;
263
264
}
264
265
catch (Exception ex ) {
265
- throw new AccessException ("Unable to access property '" + name + "' through setter" , ex );
266
+ throw new AccessException ("Unable to access property '" + name + "' through setter method " , ex );
266
267
}
267
268
}
268
269
}
@@ -283,12 +284,12 @@ public void write(EvaluationContext context, Object target, String name, Object
283
284
return ;
284
285
}
285
286
catch (Exception ex ) {
286
- throw new AccessException ("Unable to access field: " + name , ex );
287
+ throw new AccessException ("Unable to access field ' " + name + "'" , ex );
287
288
}
288
289
}
289
290
}
290
291
291
- throw new AccessException ("Neither setter nor field found for property '" + name + "'" );
292
+ throw new AccessException ("Neither setter method nor field found for property '" + name + "'" );
292
293
}
293
294
294
295
private TypeDescriptor getTypeDescriptor (EvaluationContext context , Object target , String name ) {
@@ -469,11 +470,11 @@ public PropertyAccessor createOptimalAccessor(EvaluationContext evalContext, Obj
469
470
InvokerPair invocationTarget = this .readerCache .get (cacheKey );
470
471
471
472
if (invocationTarget == null || invocationTarget .member instanceof Method ) {
472
- Method method = (Method ) (invocationTarget == null ? null : invocationTarget .member );
473
+ Method method = (Method ) (invocationTarget != null ? invocationTarget .member : null );
473
474
if (method == null ) {
474
475
method = findGetterForProperty (name , type , target );
475
476
if (method != null ) {
476
- invocationTarget = new InvokerPair (method ,new TypeDescriptor (new MethodParameter (method ,-1 )));
477
+ invocationTarget = new InvokerPair (method , new TypeDescriptor (new MethodParameter (method , -1 )));
477
478
ReflectionUtils .makeAccessible (method );
478
479
this .readerCache .put (cacheKey , invocationTarget );
479
480
}
@@ -497,6 +498,7 @@ public PropertyAccessor createOptimalAccessor(EvaluationContext evalContext, Obj
497
498
return new OptimalPropertyAccessor (invocationTarget );
498
499
}
499
500
}
501
+
500
502
return this ;
501
503
}
502
504
@@ -577,16 +579,8 @@ public static class OptimalPropertyAccessor implements CompilablePropertyAccesso
577
579
OptimalPropertyAccessor (InvokerPair target ) {
578
580
this .member = target .member ;
579
581
this .typeDescriptor = target .typeDescriptor ;
580
- if (this .member instanceof Field ) {
581
- Field field = (Field ) this .member ;
582
- this .needsToBeMadeAccessible = (!Modifier .isPublic (field .getModifiers ()) ||
583
- !Modifier .isPublic (field .getDeclaringClass ().getModifiers ())) && !field .isAccessible ();
584
- }
585
- else {
586
- Method method = (Method ) this .member ;
587
- this .needsToBeMadeAccessible = ((!Modifier .isPublic (method .getModifiers ()) ||
588
- !Modifier .isPublic (method .getDeclaringClass ().getModifiers ())) && !method .isAccessible ());
589
- }
582
+ this .needsToBeMadeAccessible = (!Modifier .isPublic (this .member .getModifiers ()) ||
583
+ !Modifier .isPublic (this .member .getDeclaringClass ().getModifiers ()));
590
584
}
591
585
592
586
@ Override
@@ -599,10 +593,12 @@ public boolean canRead(EvaluationContext context, Object target, String name) th
599
593
if (target == null ) {
600
594
return false ;
601
595
}
596
+
602
597
Class <?> type = (target instanceof Class ? (Class <?>) target : target .getClass ());
603
598
if (type .isArray ()) {
604
599
return false ;
605
600
}
601
+
606
602
if (this .member instanceof Method ) {
607
603
Method method = (Method ) this .member ;
608
604
String getterName = "get" + StringUtils .capitalize (name );
@@ -621,30 +617,31 @@ public boolean canRead(EvaluationContext context, Object target, String name) th
621
617
@ Override
622
618
public TypedValue read (EvaluationContext context , Object target , String name ) throws AccessException {
623
619
if (this .member instanceof Method ) {
620
+ Method method = (Method ) this .member ;
624
621
try {
625
- if (this .needsToBeMadeAccessible ) {
626
- ReflectionUtils . makeAccessible (( Method ) this . member );
622
+ if (this .needsToBeMadeAccessible && ! method . isAccessible () ) {
623
+ method . setAccessible ( true );
627
624
}
628
- Object value = (( Method ) this . member ) .invoke (target );
625
+ Object value = method .invoke (target );
629
626
return new TypedValue (value , this .typeDescriptor .narrow (value ));
630
627
}
631
628
catch (Exception ex ) {
632
- throw new AccessException ("Unable to access property '" + name + "' through getter" , ex );
629
+ throw new AccessException ("Unable to access property '" + name + "' through getter method " , ex );
633
630
}
634
631
}
635
- if (this .member instanceof Field ) {
632
+ else {
633
+ Field field = (Field ) this .member ;
636
634
try {
637
- if (this .needsToBeMadeAccessible ) {
638
- ReflectionUtils . makeAccessible (( Field ) this . member );
635
+ if (this .needsToBeMadeAccessible && ! field . isAccessible () ) {
636
+ field . setAccessible ( true );
639
637
}
640
- Object value = (( Field ) this . member ) .get (target );
638
+ Object value = field .get (target );
641
639
return new TypedValue (value , this .typeDescriptor .narrow (value ));
642
640
}
643
641
catch (Exception ex ) {
644
- throw new AccessException ("Unable to access field: " + name , ex );
642
+ throw new AccessException ("Unable to access field ' " + name + "'" , ex );
645
643
}
646
644
}
647
- throw new AccessException ("Neither getter nor field found for property '" + name + "'" );
648
645
}
649
646
650
647
@ Override
@@ -656,7 +653,7 @@ public boolean canWrite(EvaluationContext context, Object target, String name) {
656
653
public void write (EvaluationContext context , Object target , String name , Object newValue ) {
657
654
throw new UnsupportedOperationException ("Should not be called on an OptimalPropertyAccessor" );
658
655
}
659
-
656
+
660
657
@ Override
661
658
public boolean isCompilable () {
662
659
return (Modifier .isPublic (this .member .getModifiers ()) &&
@@ -665,34 +662,43 @@ public boolean isCompilable() {
665
662
666
663
@ Override
667
664
public Class <?> getPropertyType () {
668
- if (this .member instanceof Field ) {
669
- return ((Field ) this .member ).getType ();
665
+ if (this .member instanceof Method ) {
666
+ return ((Method ) this .member ).getReturnType ();
670
667
}
671
668
else {
672
- return ((Method ) this .member ).getReturnType ();
669
+ return ((Field ) this .member ).getType ();
673
670
}
674
671
}
675
672
676
673
@ Override
677
674
public void generateCode (String propertyName , MethodVisitor mv , CodeFlow cf ) {
678
675
boolean isStatic = Modifier .isStatic (this .member .getModifiers ());
679
676
String descriptor = cf .lastDescriptor ();
680
- String memberDeclaringClassSlashedDescriptor = this .member .getDeclaringClass ().getName ().replace ('.' , '/' );
677
+ String classDesc = this .member .getDeclaringClass ().getName ().replace ('.' , '/' );
678
+
681
679
if (!isStatic ) {
682
680
if (descriptor == null ) {
683
681
cf .loadTarget (mv );
684
682
}
685
- if (descriptor == null || !memberDeclaringClassSlashedDescriptor .equals (descriptor .substring (1 ))) {
686
- mv .visitTypeInsn (CHECKCAST , memberDeclaringClassSlashedDescriptor );
683
+ if (descriptor == null || !classDesc .equals (descriptor .substring (1 ))) {
684
+ mv .visitTypeInsn (CHECKCAST , classDesc );
687
685
}
688
686
}
689
- if (this .member instanceof Field ) {
690
- mv .visitFieldInsn (isStatic ? GETSTATIC : GETFIELD , memberDeclaringClassSlashedDescriptor ,
691
- this .member .getName (), CodeFlow .toJvmDescriptor (((Field ) this .member ).getType ()));
687
+ else {
688
+ if (descriptor != null ) {
689
+ // A static field/method call will not consume what is on the stack,
690
+ // it needs to be popped off.
691
+ mv .visitInsn (POP );
692
+ }
693
+ }
694
+
695
+ if (this .member instanceof Method ) {
696
+ mv .visitMethodInsn ((isStatic ? INVOKESTATIC : INVOKEVIRTUAL ), classDesc , this .member .getName (),
697
+ CodeFlow .createSignatureDescriptor ((Method ) this .member ), false );
692
698
}
693
699
else {
694
- mv .visitMethodInsn ( isStatic ? INVOKESTATIC : INVOKEVIRTUAL , memberDeclaringClassSlashedDescriptor ,
695
- this . member . getName (), CodeFlow .createSignatureDescriptor (( Method ) this .member ), false );
700
+ mv .visitFieldInsn (( isStatic ? GETSTATIC : GETFIELD ), classDesc , this . member . getName () ,
701
+ CodeFlow .toJvmDescriptor ((( Field ) this .member ). getType ()) );
696
702
}
697
703
}
698
704
}
0 commit comments