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 ;
@@ -546,6 +561,19 @@ public void doWith(Method method) {
546561		return  methods .toArray (new  Method [methods .size ()]);
547562	}
548563
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+ 
549577	/** 
550578	 * Invoke the given callback on all fields in the target class, going up the 
551579	 * class hierarchy to get all declared fields. 
0 commit comments