2626import java .util .ArrayList ;
2727import java .util .Arrays ;
2828import java .util .List ;
29+ import java .util .Map ;
2930import java .util .regex .Pattern ;
3031
3132/**
4445 */
4546public abstract class ReflectionUtils {
4647
48+ /**
49+ * Naming prefix for CGLIB-renamed methods.
50+ * @see #isCglibRenamedMethod
51+ */
52+ private static final String CGLIB_RENAMED_METHOD_PREFIX = "CGLIB$" ;
53+
4754 /**
4855 * Pattern for detecting CGLIB-renamed methods.
4956 * @see #isCglibRenamedMethod
5057 */
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 );
5265
5366
5467 /**
@@ -156,7 +169,7 @@ public static Method findMethod(Class<?> clazz, String name, Class<?>... paramTy
156169 Assert .notNull (name , "Method name must not be null" );
157170 Class <?> searchType = clazz ;
158171 while (searchType != null ) {
159- Method [] methods = (searchType .isInterface () ? searchType .getMethods () : searchType . getDeclaredMethods ());
172+ Method [] methods = (searchType .isInterface () ? searchType .getMethods () : getDeclaredMethods (searchType ));
160173 for (Method method : methods ) {
161174 if (name .equals (method .getName ()) &&
162175 (paramTypes == null || Arrays .equals (paramTypes , method .getParameterTypes ()))) {
@@ -397,7 +410,9 @@ public static boolean isObjectMethod(Method method) {
397410 * @see org.springframework.cglib.proxy.Enhancer#rename
398411 */
399412 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 ());
401416 }
402417
403418 /**
@@ -424,8 +439,8 @@ public static void makeAccessible(Field field) {
424439 * @see java.lang.reflect.Method#setAccessible
425440 */
426441 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 ()) {
429444 method .setAccessible (true );
430445 }
431446 }
@@ -439,8 +454,8 @@ public static void makeAccessible(Method method) {
439454 * @see java.lang.reflect.Constructor#setAccessible
440455 */
441456 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 ()) {
444459 ctor .setAccessible (true );
445460 }
446461 }
@@ -471,7 +486,7 @@ public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter
471486 throws IllegalArgumentException {
472487
473488 // Keep backing up the inheritance hierarchy.
474- Method [] methods = clazz . getDeclaredMethods ();
489+ Method [] methods = getDeclaredMethods (clazz );
475490 for (Method method : methods ) {
476491 if (mf != null && !mf .matches (method )) {
477492 continue ;
@@ -544,6 +559,19 @@ public void doWith(Method method) {
544559 return methods .toArray (new Method [methods .size ()]);
545560 }
546561
562+ /**
563+ * This method retrieves {@link Class#getDeclaredMethods()} from a local cache
564+ * in order to avoid the JVM's SecurityManager check and defensive array copying.
565+ */
566+ private static Method [] getDeclaredMethods (Class <?> clazz ) {
567+ Method [] result = declaredMethodsCache .get (clazz );
568+ if (result == null ) {
569+ result = clazz .getDeclaredMethods ();
570+ declaredMethodsCache .put (clazz , result );
571+ }
572+ return result ;
573+ }
574+
547575 /**
548576 * Invoke the given callback on all fields in the target class, going up the
549577 * class hierarchy to get all declared fields.
0 commit comments