26
26
import java .util .ArrayList ;
27
27
import java .util .Arrays ;
28
28
import java .util .List ;
29
+ import java .util .Map ;
29
30
import java .util .regex .Pattern ;
30
31
31
32
/**
44
45
*/
45
46
public abstract class ReflectionUtils {
46
47
48
+ /**
49
+ * Naming prefix for CGLIB-renamed methods.
50
+ * @see #isCglibRenamedMethod
51
+ */
52
+ private static final String CGLIB_RENAMED_METHOD_PREFIX = "CGLIB$" ;
53
+
47
54
/**
48
55
* Pattern for detecting CGLIB-renamed methods.
49
56
* @see #isCglibRenamedMethod
50
57
*/
51
- private static final Pattern CGLIB_RENAMED_METHOD_PATTERN = Pattern .compile ("CGLIB\\ $(.+)\\ $\\ d+" );
58
+ private static final Pattern CGLIB_RENAMED_METHOD_PATTERN = Pattern .compile ("(.+)\\ $\\ d+" );
59
+
60
+ /**
61
+ * Cache for {@link Class#getDeclaredMethods()}, allowing for fast resolution.
62
+ */
63
+ private static final Map <Class <?>, Method []> declaredMethodsCache =
64
+ new ConcurrentReferenceHashMap <Class <?>, Method []>(256 );
52
65
53
66
54
67
/**
@@ -156,7 +169,7 @@ public static Method findMethod(Class<?> clazz, String name, Class<?>... paramTy
156
169
Assert .notNull (name , "Method name must not be null" );
157
170
Class <?> searchType = clazz ;
158
171
while (searchType != null ) {
159
- Method [] methods = (searchType .isInterface () ? searchType .getMethods () : searchType . getDeclaredMethods ());
172
+ Method [] methods = (searchType .isInterface () ? searchType .getMethods () : getDeclaredMethods (searchType ));
160
173
for (Method method : methods ) {
161
174
if (name .equals (method .getName ()) &&
162
175
(paramTypes == null || Arrays .equals (paramTypes , method .getParameterTypes ()))) {
@@ -397,7 +410,9 @@ public static boolean isObjectMethod(Method method) {
397
410
* @see org.springframework.cglib.proxy.Enhancer#rename
398
411
*/
399
412
public static boolean isCglibRenamedMethod (Method renamedMethod ) {
400
- return CGLIB_RENAMED_METHOD_PATTERN .matcher (renamedMethod .getName ()).matches ();
413
+ String name = renamedMethod .getName ();
414
+ return (name .startsWith (CGLIB_RENAMED_METHOD_PREFIX ) &&
415
+ CGLIB_RENAMED_METHOD_PATTERN .matcher (name .substring (CGLIB_RENAMED_METHOD_PREFIX .length ())).matches ());
401
416
}
402
417
403
418
/**
@@ -424,8 +439,8 @@ public static void makeAccessible(Field field) {
424
439
* @see java.lang.reflect.Method#setAccessible
425
440
*/
426
441
public static void makeAccessible (Method method ) {
427
- if ((!Modifier .isPublic (method .getModifiers ()) || !Modifier .isPublic (method .getDeclaringClass ().getModifiers ()))
428
- && !method .isAccessible ()) {
442
+ if ((!Modifier .isPublic (method .getModifiers ()) || !Modifier .isPublic (method .getDeclaringClass ().getModifiers ())) &&
443
+ !method .isAccessible ()) {
429
444
method .setAccessible (true );
430
445
}
431
446
}
@@ -439,8 +454,8 @@ public static void makeAccessible(Method method) {
439
454
* @see java.lang.reflect.Constructor#setAccessible
440
455
*/
441
456
public static void makeAccessible (Constructor <?> ctor ) {
442
- if ((!Modifier .isPublic (ctor .getModifiers ()) || !Modifier .isPublic (ctor .getDeclaringClass ().getModifiers ()))
443
- && !ctor .isAccessible ()) {
457
+ if ((!Modifier .isPublic (ctor .getModifiers ()) || !Modifier .isPublic (ctor .getDeclaringClass ().getModifiers ())) &&
458
+ !ctor .isAccessible ()) {
444
459
ctor .setAccessible (true );
445
460
}
446
461
}
@@ -471,7 +486,7 @@ public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter
471
486
throws IllegalArgumentException {
472
487
473
488
// Keep backing up the inheritance hierarchy.
474
- Method [] methods = clazz . getDeclaredMethods ();
489
+ Method [] methods = getDeclaredMethods (clazz );
475
490
for (Method method : methods ) {
476
491
if (mf != null && !mf .matches (method )) {
477
492
continue ;
@@ -546,6 +561,19 @@ public void doWith(Method method) {
546
561
return methods .toArray (new Method [methods .size ()]);
547
562
}
548
563
564
+ /**
565
+ * This method retrieves {@link Class#getDeclaredMethods()} from a local cache
566
+ * in order to avoid the JVM's SecurityManager check and defensive array copying.
567
+ */
568
+ private static Method [] getDeclaredMethods (Class <?> clazz ) {
569
+ Method [] result = declaredMethodsCache .get (clazz );
570
+ if (result == null ) {
571
+ result = clazz .getDeclaredMethods ();
572
+ declaredMethodsCache .put (clazz , result );
573
+ }
574
+ return result ;
575
+ }
576
+
549
577
/**
550
578
* Invoke the given callback on all fields in the target class, going up the
551
579
* class hierarchy to get all declared fields.
0 commit comments