@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2002 - 2018 the original author or authors .
* Copyright 2002 - 2019 the original author or authors .
*
* Licensed under the Apache License , Version 2 . 0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
@ -61,13 +61,13 @@ public abstract class ReflectionUtils {
@@ -61,13 +61,13 @@ public abstract class ReflectionUtils {
* @since 3 . 0 . 5
* /
public static final MethodFilter USER_DECLARED_METHODS =
( method - > ( ! method . isBridge ( ) & & ! method . isSynthetic ( ) & & method . getDeclaringClass ( ) ! = Object . class ) ) ;
( method - > ! method . isBridge ( ) & & ! method . isSynthetic ( ) & & method . getDeclaringClass ( ) ! = Object . class ) ;
/ * *
* Pre - built FieldFilter that matches all non - static , non - final fields .
* /
public static final FieldFilter COPYABLE_FIELDS =
field - > ! ( Modifier . isStatic ( field . getModifiers ( ) ) | | Modifier . isFinal ( field . getModifiers ( ) ) ) ;
( field - > ! ( Modifier . isStatic ( field . getModifiers ( ) ) | | Modifier . isFinal ( field . getModifiers ( ) ) ) ) ;
/ * *
@ -76,9 +76,9 @@ public abstract class ReflectionUtils {
@@ -76,9 +76,9 @@ public abstract class ReflectionUtils {
* /
private static final String CGLIB_RENAMED_METHOD_PREFIX = "CGLIB$" ;
private static final Method [ ] NO_METHODS = { } ;
private static final Method [ ] EMPTY_METHOD_ARRAY = new Method [ 0 ] ;
private static final Field [ ] NO_FIELDS = { } ;
private static final Field [ ] EMPTY_FIELD_ARRAY = new Field [ 0 ] ;
/ * *
@ -93,209 +93,7 @@ public abstract class ReflectionUtils {
@@ -93,209 +93,7 @@ public abstract class ReflectionUtils {
private static final Map < Class < ? > , Field [ ] > declaredFieldsCache = new ConcurrentReferenceHashMap < > ( 256 ) ;
/ * *
* Attempt to find a { @link Field field } on the supplied { @link Class } with the
* supplied { @code name } . Searches all superclasses up to { @link Object } .
* @param clazz the class to introspect
* @param name the name of the field
* @return the corresponding Field object , or { @code null } if not found
* /
@Nullable
public static Field findField ( Class < ? > clazz , String name ) {
return findField ( clazz , name , null ) ;
}
/ * *
* Attempt to find a { @link Field field } on the supplied { @link Class } with the
* supplied { @code name } and / or { @link Class type } . Searches all superclasses
* up to { @link Object } .
* @param clazz the class to introspect
* @param name the name of the field ( may be { @code null } if type is specified )
* @param type the type of the field ( may be { @code null } if name is specified )
* @return the corresponding Field object , or { @code null } if not found
* /
@Nullable
public static Field findField ( Class < ? > clazz , @Nullable String name , @Nullable Class < ? > type ) {
Assert . notNull ( clazz , "Class must not be null" ) ;
Assert . isTrue ( name ! = null | | type ! = null , "Either name or type of the field must be specified" ) ;
Class < ? > searchType = clazz ;
while ( Object . class ! = searchType & & searchType ! = null ) {
Field [ ] fields = getDeclaredFields ( searchType ) ;
for ( Field field : fields ) {
if ( ( name = = null | | name . equals ( field . getName ( ) ) ) & &
( type = = null | | type . equals ( field . getType ( ) ) ) ) {
return field ;
}
}
searchType = searchType . getSuperclass ( ) ;
}
return null ;
}
/ * *
* Set the field represented by the supplied { @link Field field object } on the
* specified { @link Object target object } to the specified { @code value } .
* In accordance with { @link Field # set ( Object , Object ) } semantics , the new value
* is automatically unwrapped if the underlying field has a primitive type .
* < p > Thrown exceptions are handled via a call to { @link # handleReflectionException ( Exception ) } .
* @param field the field to set
* @param target the target object on which to set the field
* @param value the value to set ( may be { @code null } )
* /
public static void setField ( Field field , @Nullable Object target , @Nullable Object value ) {
try {
field . set ( target , value ) ;
}
catch ( IllegalAccessException ex ) {
handleReflectionException ( ex ) ;
throw new IllegalStateException (
"Unexpected reflection exception - " + ex . getClass ( ) . getName ( ) + ": " + ex . getMessage ( ) ) ;
}
}
/ * *
* Get the field represented by the supplied { @link Field field object } on the
* specified { @link Object target object } . In accordance with { @link Field # get ( Object ) }
* semantics , the returned value is automatically wrapped if the underlying field
* has a primitive type .
* < p > Thrown exceptions are handled via a call to { @link # handleReflectionException ( Exception ) } .
* @param field the field to get
* @param target the target object from which to get the field
* @return the field ' s current value
* /
@Nullable
public static Object getField ( Field field , @Nullable Object target ) {
try {
return field . get ( target ) ;
}
catch ( IllegalAccessException ex ) {
handleReflectionException ( ex ) ;
throw new IllegalStateException (
"Unexpected reflection exception - " + ex . getClass ( ) . getName ( ) + ": " + ex . getMessage ( ) ) ;
}
}
/ * *
* Attempt to find a { @link Method } on the supplied class with the supplied name
* and no parameters . Searches all superclasses up to { @code Object } .
* < p > Returns { @code null } if no { @link Method } can be found .
* @param clazz the class to introspect
* @param name the name of the method
* @return the Method object , or { @code null } if none found
* /
@Nullable
public static Method findMethod ( Class < ? > clazz , String name ) {
return findMethod ( clazz , name , new Class < ? > [ 0 ] ) ;
}
/ * *
* Attempt to find a { @link Method } on the supplied class with the supplied name
* and parameter types . Searches all superclasses up to { @code Object } .
* < p > Returns { @code null } if no { @link Method } can be found .
* @param clazz the class to introspect
* @param name the name of the method
* @param paramTypes the parameter types of the method
* ( may be { @code null } to indicate any signature )
* @return the Method object , or { @code null } if none found
* /
@Nullable
public static Method findMethod ( Class < ? > clazz , String name , @Nullable Class < ? > . . . paramTypes ) {
Assert . notNull ( clazz , "Class must not be null" ) ;
Assert . notNull ( name , "Method name must not be null" ) ;
Class < ? > searchType = clazz ;
while ( searchType ! = null ) {
Method [ ] methods = ( searchType . isInterface ( ) ? searchType . getMethods ( ) : getDeclaredMethods ( searchType ) ) ;
for ( Method method : methods ) {
if ( name . equals ( method . getName ( ) ) & &
( paramTypes = = null | | Arrays . equals ( paramTypes , method . getParameterTypes ( ) ) ) ) {
return method ;
}
}
searchType = searchType . getSuperclass ( ) ;
}
return null ;
}
/ * *
* Invoke the specified { @link Method } against the supplied target object with no arguments .
* The target object can be { @code null } when invoking a static { @link Method } .
* < p > Thrown exceptions are handled via a call to { @link # handleReflectionException } .
* @param method the method to invoke
* @param target the target object to invoke the method on
* @return the invocation result , if any
* @see # invokeMethod ( java . lang . reflect . Method , Object , Object [ ] )
* /
@Nullable
public static Object invokeMethod ( Method method , @Nullable Object target ) {
return invokeMethod ( method , target , new Object [ 0 ] ) ;
}
/ * *
* Invoke the specified { @link Method } against the supplied target object with the
* supplied arguments . The target object can be { @code null } when invoking a
* static { @link Method } .
* < p > Thrown exceptions are handled via a call to { @link # handleReflectionException } .
* @param method the method to invoke
* @param target the target object to invoke the method on
* @param args the invocation arguments ( may be { @code null } )
* @return the invocation result , if any
* /
@Nullable
public static Object invokeMethod ( Method method , @Nullable Object target , @Nullable Object . . . args ) {
try {
return method . invoke ( target , args ) ;
}
catch ( Exception ex ) {
handleReflectionException ( ex ) ;
}
throw new IllegalStateException ( "Should never get here" ) ;
}
/ * *
* Invoke the specified JDBC API { @link Method } against the supplied target
* object with no arguments .
* @param method the method to invoke
* @param target the target object to invoke the method on
* @return the invocation result , if any
* @throws SQLException the JDBC API SQLException to rethrow ( if any )
* @see # invokeJdbcMethod ( java . lang . reflect . Method , Object , Object [ ] )
* @deprecated as of 5 . 0 . 11 , in favor of custom SQLException handling
* /
@Deprecated
@Nullable
public static Object invokeJdbcMethod ( Method method , @Nullable Object target ) throws SQLException {
return invokeJdbcMethod ( method , target , new Object [ 0 ] ) ;
}
/ * *
* Invoke the specified JDBC API { @link Method } against the supplied target
* object with the supplied arguments .
* @param method the method to invoke
* @param target the target object to invoke the method on
* @param args the invocation arguments ( may be { @code null } )
* @return the invocation result , if any
* @throws SQLException the JDBC API SQLException to rethrow ( if any )
* @see # invokeMethod ( java . lang . reflect . Method , Object , Object [ ] )
* @deprecated as of 5 . 0 . 11 , in favor of custom SQLException handling
* /
@Deprecated
@Nullable
public static Object invokeJdbcMethod ( Method method , @Nullable Object target , @Nullable Object . . . args )
throws SQLException {
try {
return method . invoke ( target , args ) ;
}
catch ( IllegalAccessException ex ) {
handleReflectionException ( ex ) ;
}
catch ( InvocationTargetException ex ) {
if ( ex . getTargetException ( ) instanceof SQLException ) {
throw ( SQLException ) ex . getTargetException ( ) ;
}
handleInvocationTargetException ( ex ) ;
}
throw new IllegalStateException ( "Should never get here" ) ;
}
// Exception handling
/ * *
* Handle the given reflection exception . Should only be called if no
@ -375,161 +173,184 @@ public abstract class ReflectionUtils {
@@ -375,161 +173,184 @@ public abstract class ReflectionUtils {
throw new UndeclaredThrowableException ( ex ) ;
}
/ * *
* Determine whether the given method explicitly declares the given
* exception or one of its superclasses , which means that an exception
* of that type can be propagated as - is within a reflective invocation .
* @param method the declaring method
* @param exceptionType the exception to throw
* @return { @code true } if the exception can be thrown as - is ;
* { @code false } if it needs to be wrapped
* /
public static boolean declaresException ( Method method , Class < ? > exceptionType ) {
Assert . notNull ( method , "Method must not be null" ) ;
Class < ? > [ ] declaredExceptions = method . getExceptionTypes ( ) ;
for ( Class < ? > declaredException : declaredExceptions ) {
if ( declaredException . isAssignableFrom ( exceptionType ) ) {
return true ;
}
}
return false ;
}
// Constructor handling
/ * *
* Determine whether the given field is a "public static final" constant .
* @param field the field to check
* Obtain an accessible constructor for the given class and parameters .
* @param clazz the clazz to check
* @param parameterTypes the parameter types of the desired constructor
* @return the constructor reference
* @throws NoSuchMethodException if no such constructor exists
* @since 5 . 0
* /
public static boolean isPublicStaticFinal ( Field field ) {
int modifiers = field . getModifiers ( ) ;
return ( Modifier . isPublic ( modifiers ) & & Modifier . isStatic ( modifiers ) & & Modifier . isFinal ( modifiers ) ) ;
public static < T > Constructor < T > accessibleConstructor ( Class < T > clazz , Class < ? > . . . parameterTypes )
throws NoSuchMethodException {
Constructor < T > ctor = clazz . getDeclaredConstructor ( parameterTypes ) ;
makeAccessible ( ctor ) ;
return ctor ;
}
/ * *
* Determine whether the given method is an "equals" method .
* @see java . lang . Object # equals ( Object )
* Make the given constructor accessible , explicitly setting it accessible
* if necessary . The { @code setAccessible ( true ) } method is only called
* when actually necessary , to avoid unnecessary conflicts with a JVM
* SecurityManager ( if active ) .
* @param ctor the constructor to make accessible
* @see java . lang . reflect . Constructor # setAccessible
* /
public static boolean isEqualsMethod ( @Nullable Method method ) {
if ( method = = null | | ! method . getName ( ) . equals ( "equals" ) ) {
return false ;
@SuppressWarnings ( "deprecation" ) // on JDK 9
public static void makeAccessible ( Constructor < ? > ctor ) {
if ( ( ! Modifier . isPublic ( ctor . getModifiers ( ) ) | |
! Modifier . isPublic ( ctor . getDeclaringClass ( ) . getModifiers ( ) ) ) & & ! ctor . isAccessible ( ) ) {
ctor . setAccessible ( true ) ;
}
Class < ? > [ ] paramTypes = method . getParameterTypes ( ) ;
return ( paramTypes . length = = 1 & & paramTypes [ 0 ] = = Object . class ) ;
}
/ * *
* Determine whether the given method is a "hashCode" method .
* @see java . lang . Object # hashCode ( )
* /
public static boolean isHashCodeMethod ( @Nullable Method method ) {
return ( method ! = null & & method . getName ( ) . equals ( "hashCode" ) & & method . getParameterCount ( ) = = 0 ) ;
}
// Method handling
/ * *
* Determine whether the given method is a "toString" method .
* @see java . lang . Object # toString ( )
* Attempt to find a { @link Method } on the supplied class with the supplied name
* and no parameters . Searches all superclasses up to { @code Object } .
* < p > Returns { @code null } if no { @link Method } can be found .
* @param clazz the class to introspect
* @param name the name of the method
* @return the Method object , or { @code null } if none found
* /
public static boolean isToStringMethod ( @Nullable Method method ) {
return ( method ! = null & & method . getName ( ) . equals ( "toString" ) & & method . getParameterCount ( ) = = 0 ) ;
@Nullable
public static Method findMethod ( Class < ? > clazz , String name ) {
return findMethod ( clazz , name , new Class < ? > [ 0 ] ) ;
}
/ * *
* Determine whether the given method is originally declared by { @link java . lang . Object } .
* Attempt to find a { @link Method } on the supplied class with the supplied name
* and parameter types . Searches all superclasses up to { @code Object } .
* < p > Returns { @code null } if no { @link Method } can be found .
* @param clazz the class to introspect
* @param name the name of the method
* @param paramTypes the parameter types of the method
* ( may be { @code null } to indicate any signature )
* @return the Method object , or { @code null } if none found
* /
public static boolean isObjectMethod ( @Nullable Method method ) {
if ( method = = null ) {
return false ;
}
try {
Object . class . getDeclaredMethod ( method . getName ( ) , method . getParameterTypes ( ) ) ;
return true ;
}
catch ( Exception ex ) {
return false ;
@Nullable
public static Method findMethod ( Class < ? > clazz , String name , @Nullable Class < ? > . . . paramTypes ) {
Assert . notNull ( clazz , "Class must not be null" ) ;
Assert . notNull ( name , "Method name must not be null" ) ;
Class < ? > searchType = clazz ;
while ( searchType ! = null ) {
Method [ ] methods = ( searchType . isInterface ( ) ? searchType . getMethods ( ) : getDeclaredMethods ( searchType ) ) ;
for ( Method method : methods ) {
if ( name . equals ( method . getName ( ) ) & &
( paramTypes = = null | | Arrays . equals ( paramTypes , method . getParameterTypes ( ) ) ) ) {
return method ;
}
}
searchType = searchType . getSuperclass ( ) ;
}
return null ;
}
/ * *
* Determine whether the given method is a CGLIB ' renamed ' method ,
* following the pattern "CGLIB$methodName$0" .
* @param renamedMethod the method to check
* @see org . springframework . cglib . proxy . Enhancer # rename
* Invoke the specified { @link Method } against the supplied target object with no arguments .
* The target object can be { @code null } when invoking a static { @link Method } .
* < p > Thrown exceptions are handled via a call to { @link # handleReflectionException } .
* @param method the method to invoke
* @param target the target object to invoke the method on
* @return the invocation result , if any
* @see # invokeMethod ( java . lang . reflect . Method , Object , Object [ ] )
* /
public static boolean isCglibRenamedMethod ( Method renamedMethod ) {
String name = renamedMethod . getName ( ) ;
if ( name . startsWith ( CGLIB_RENAMED_METHOD_PREFIX ) ) {
int i = name . length ( ) - 1 ;
while ( i > = 0 & & Character . isDigit ( name . charAt ( i ) ) ) {
i - - ;
}
return ( ( i > CGLIB_RENAMED_METHOD_PREFIX . length ( ) ) & &
( i < name . length ( ) - 1 ) & & name . charAt ( i ) = = '$' ) ;
}
return false ;
@Nullable
public static Object invokeMethod ( Method method , @Nullable Object target ) {
return invokeMethod ( method , target , new Object [ 0 ] ) ;
}
/ * *
* Make the given field accessible , explicitly setting it accessible if
* necessary . The { @code setAccessible ( true ) } method is only called
* when actually necessary , to avoid unnecessary conflicts with a JVM
* SecurityManager ( if active ) .
* @param field the field to make accessible
* @see java . lang . reflect . Field # setAccessible
* Invoke the specified { @link Method } against the supplied target object with the
* supplied arguments . The target object can be { @code null } when invoking a
* static { @link Method } .
* < p > Thrown exceptions are handled via a call to { @link # handleReflectionException } .
* @param method the method to invoke
* @param target the target object to invoke the method on
* @param args the invocation arguments ( may be { @code null } )
* @return the invocation result , if any
* /
@SuppressWarnings ( "deprecation" ) // on JDK 9
public static void makeAccessible ( Field field ) {
if ( ( ! Modifier . isPublic ( field . getModifiers ( ) ) | |
! Modifier . isPublic ( field . getDeclaringClass ( ) . getModifiers ( ) ) | |
Modifier . isFinal ( field . getModifiers ( ) ) ) & & ! field . isAccessible ( ) ) {
field . setAccessible ( true ) ;
@Nullable
public static Object invokeMethod ( Method method , @Nullable Object target , @Nullable Object . . . args ) {
try {
return method . invoke ( target , args ) ;
}
catch ( Exception ex ) {
handleReflectionException ( ex ) ;
}
throw new IllegalStateException ( "Should never get here" ) ;
}
/ * *
* Make the given method accessible , explicitly setting it accessible if
* necessary . The { @code setAccessible ( true ) } method is only called
* when actually necessary , to avoid unnecessary conflicts with a JVM
* SecurityManager ( if active ) .
* @param method the method to make accessible
* @see java . lang . reflect . Method # setAccessible
* Invoke the specified JDBC API { @link Method } against the supplied target
* object with no arguments .
* @param method the method to invoke
* @param target the target object to invoke the method on
* @return the invocation result , if any
* @throws SQLException the JDBC API SQLException to rethrow ( if any )
* @see # invokeJdbcMethod ( java . lang . reflect . Method , Object , Object [ ] )
* @deprecated as of 5 . 0 . 11 , in favor of custom SQLException handling
* /
@SuppressWarnings ( "deprecation" ) // on JDK 9
public static void makeAccessible ( Method method ) {
if ( ( ! Modifier . isPublic ( method . getModifiers ( ) ) | |
! Modifier . isPublic ( method . getDeclaringClass ( ) . getModifiers ( ) ) ) & & ! method . isAccessible ( ) ) {
method . setAccessible ( true ) ;
}
@Deprecated
@Nullable
public static Object invokeJdbcMethod ( Method method , @Nullable Object target ) throws SQLException {
return invokeJdbcMethod ( method , target , new Object [ 0 ] ) ;
}
/ * *
* Make the given constructor accessible , explicitly setting it accessible
* if necessary . The { @code setAccessible ( true ) } method is only called
* when actually necessary , to avoid unnecessary conflicts with a JVM
* SecurityManager ( if active ) .
* @param ctor the constructor to make accessible
* @see java . lang . reflect . Constructor # setAccessible
* Invoke the specified JDBC API { @link Method } against the supplied target
* object with the supplied arguments .
* @param method the method to invoke
* @param target the target object to invoke the method on
* @param args the invocation arguments ( may be { @code null } )
* @return the invocation result , if any
* @throws SQLException the JDBC API SQLException to rethrow ( if any )
* @see # invokeMethod ( java . lang . reflect . Method , Object , Object [ ] )
* @deprecated as of 5 . 0 . 11 , in favor of custom SQLException handling
* /
@SuppressWarnings ( "deprecation" ) // on JDK 9
public static void makeAccessible ( Constructor < ? > ctor ) {
if ( ( ! Modifier . isPublic ( ctor . getModifiers ( ) ) | |
! Modifier . isPublic ( ctor . getDeclaringClass ( ) . getModifiers ( ) ) ) & & ! ctor . isAccessible ( ) ) {
ctor . setAccessible ( true ) ;
@Deprecated
@Nullable
public static Object invokeJdbcMethod ( Method method , @Nullable Object target , @Nullable Object . . . args )
throws SQLException {
try {
return method . invoke ( target , args ) ;
}
catch ( IllegalAccessException ex ) {
handleReflectionException ( ex ) ;
}
catch ( InvocationTargetException ex ) {
if ( ex . getTargetException ( ) instanceof SQLException ) {
throw ( SQLException ) ex . getTargetException ( ) ;
}
handleInvocationTargetException ( ex ) ;
}
throw new IllegalStateException ( "Should never get here" ) ;
}
/ * *
* Obtain an accessible constructor for the given class and parameters .
* @param clazz the clazz to check
* @param parameterTypes the parameter types of the desired constructor
* @return the constructor reference
* @throws NoSuchMethodException if no such constructor exists
* @since 5 . 0
* Determine whether the given method explicitly declares the given
* exception or one of its superclasses , which means that an exception
* of that type can be propagated as - is within a reflective invocation .
* @param method the declaring method
* @param exceptionType the exception to throw
* @return { @code true } if the exception can be thrown as - is ;
* { @code false } if it needs to be wrapped
* /
public static < T > Constructor < T > accessibleConstructor ( Class < T > clazz , Class < ? > . . . parameterTypes )
throws NoSuchMethodException {
Constructor < T > ctor = clazz . getDeclaredConstructor ( parameterTypes ) ;
makeAccessible ( ctor ) ;
return ctor ;
public static boolean declaresException ( Method method , Class < ? > exceptionType ) {
Assert . notNull ( method , "Method must not be null" ) ;
Class < ? > [ ] declaredExceptions = method . getExceptionTypes ( ) ;
for ( Class < ? > declaredException : declaredExceptions ) {
if ( declaredException . isAssignableFrom ( exceptionType ) ) {
return true ;
}
}
return false ;
}
/ * *
@ -611,7 +432,7 @@ public abstract class ReflectionUtils {
@@ -611,7 +432,7 @@ public abstract class ReflectionUtils {
public static Method [ ] getAllDeclaredMethods ( Class < ? > leafClass ) {
final List < Method > methods = new ArrayList < > ( 32 ) ;
doWithMethods ( leafClass , methods : : add ) ;
return methods . toArray ( new Method [ 0 ] ) ;
return methods . toArray ( EMPTY_METHOD_ARRAY ) ;
}
/ * *
@ -647,7 +468,7 @@ public abstract class ReflectionUtils {
@@ -647,7 +468,7 @@ public abstract class ReflectionUtils {
methods . add ( method ) ;
}
} ) ;
return methods . toArray ( new Method [ 0 ] ) ;
return methods . toArray ( EMPTY_METHOD_ARRAY ) ;
}
/ * *
@ -679,7 +500,7 @@ public abstract class ReflectionUtils {
@@ -679,7 +500,7 @@ public abstract class ReflectionUtils {
else {
result = declaredMethods ;
}
declaredMethodsCache . put ( clazz , ( result . length = = 0 ? NO_METHODS : result ) ) ;
declaredMethodsCache . put ( clazz , ( result . length = = 0 ? EMPTY_METHOD_ARRAY : result ) ) ;
}
catch ( Throwable ex ) {
throw new IllegalStateException ( "Failed to introspect Class [" + clazz . getName ( ) +
@ -705,6 +526,168 @@ public abstract class ReflectionUtils {
@@ -705,6 +526,168 @@ public abstract class ReflectionUtils {
return result ;
}
/ * *
* Determine whether the given method is an "equals" method .
* @see java . lang . Object # equals ( Object )
* /
public static boolean isEqualsMethod ( @Nullable Method method ) {
if ( method = = null | | ! method . getName ( ) . equals ( "equals" ) ) {
return false ;
}
Class < ? > [ ] paramTypes = method . getParameterTypes ( ) ;
return ( paramTypes . length = = 1 & & paramTypes [ 0 ] = = Object . class ) ;
}
/ * *
* Determine whether the given method is a "hashCode" method .
* @see java . lang . Object # hashCode ( )
* /
public static boolean isHashCodeMethod ( @Nullable Method method ) {
return ( method ! = null & & method . getName ( ) . equals ( "hashCode" ) & & method . getParameterCount ( ) = = 0 ) ;
}
/ * *
* Determine whether the given method is a "toString" method .
* @see java . lang . Object # toString ( )
* /
public static boolean isToStringMethod ( @Nullable Method method ) {
return ( method ! = null & & method . getName ( ) . equals ( "toString" ) & & method . getParameterCount ( ) = = 0 ) ;
}
/ * *
* Determine whether the given method is originally declared by { @link java . lang . Object } .
* /
public static boolean isObjectMethod ( @Nullable Method method ) {
if ( method = = null ) {
return false ;
}
try {
Object . class . getDeclaredMethod ( method . getName ( ) , method . getParameterTypes ( ) ) ;
return true ;
}
catch ( Exception ex ) {
return false ;
}
}
/ * *
* Determine whether the given method is a CGLIB ' renamed ' method ,
* following the pattern "CGLIB$methodName$0" .
* @param renamedMethod the method to check
* /
public static boolean isCglibRenamedMethod ( Method renamedMethod ) {
String name = renamedMethod . getName ( ) ;
if ( name . startsWith ( CGLIB_RENAMED_METHOD_PREFIX ) ) {
int i = name . length ( ) - 1 ;
while ( i > = 0 & & Character . isDigit ( name . charAt ( i ) ) ) {
i - - ;
}
return ( i > CGLIB_RENAMED_METHOD_PREFIX . length ( ) & & ( i < name . length ( ) - 1 ) & & name . charAt ( i ) = = '$' ) ;
}
return false ;
}
/ * *
* Make the given method accessible , explicitly setting it accessible if
* necessary . The { @code setAccessible ( true ) } method is only called
* when actually necessary , to avoid unnecessary conflicts with a JVM
* SecurityManager ( if active ) .
* @param method the method to make accessible
* @see java . lang . reflect . Method # setAccessible
* /
@SuppressWarnings ( "deprecation" ) // on JDK 9
public static void makeAccessible ( Method method ) {
if ( ( ! Modifier . isPublic ( method . getModifiers ( ) ) | |
! Modifier . isPublic ( method . getDeclaringClass ( ) . getModifiers ( ) ) ) & & ! method . isAccessible ( ) ) {
method . setAccessible ( true ) ;
}
}
// Field handling
/ * *
* Attempt to find a { @link Field field } on the supplied { @link Class } with the
* supplied { @code name } . Searches all superclasses up to { @link Object } .
* @param clazz the class to introspect
* @param name the name of the field
* @return the corresponding Field object , or { @code null } if not found
* /
@Nullable
public static Field findField ( Class < ? > clazz , String name ) {
return findField ( clazz , name , null ) ;
}
/ * *
* Attempt to find a { @link Field field } on the supplied { @link Class } with the
* supplied { @code name } and / or { @link Class type } . Searches all superclasses
* up to { @link Object } .
* @param clazz the class to introspect
* @param name the name of the field ( may be { @code null } if type is specified )
* @param type the type of the field ( may be { @code null } if name is specified )
* @return the corresponding Field object , or { @code null } if not found
* /
@Nullable
public static Field findField ( Class < ? > clazz , @Nullable String name , @Nullable Class < ? > type ) {
Assert . notNull ( clazz , "Class must not be null" ) ;
Assert . isTrue ( name ! = null | | type ! = null , "Either name or type of the field must be specified" ) ;
Class < ? > searchType = clazz ;
while ( Object . class ! = searchType & & searchType ! = null ) {
Field [ ] fields = getDeclaredFields ( searchType ) ;
for ( Field field : fields ) {
if ( ( name = = null | | name . equals ( field . getName ( ) ) ) & &
( type = = null | | type . equals ( field . getType ( ) ) ) ) {
return field ;
}
}
searchType = searchType . getSuperclass ( ) ;
}
return null ;
}
/ * *
* Set the field represented by the supplied { @link Field field object } on the
* specified { @link Object target object } to the specified { @code value } .
* In accordance with { @link Field # set ( Object , Object ) } semantics , the new value
* is automatically unwrapped if the underlying field has a primitive type .
* < p > Thrown exceptions are handled via a call to { @link # handleReflectionException ( Exception ) } .
* @param field the field to set
* @param target the target object on which to set the field
* @param value the value to set ( may be { @code null } )
* /
public static void setField ( Field field , @Nullable Object target , @Nullable Object value ) {
try {
field . set ( target , value ) ;
}
catch ( IllegalAccessException ex ) {
handleReflectionException ( ex ) ;
throw new IllegalStateException (
"Unexpected reflection exception - " + ex . getClass ( ) . getName ( ) + ": " + ex . getMessage ( ) ) ;
}
}
/ * *
* Get the field represented by the supplied { @link Field field object } on the
* specified { @link Object target object } . In accordance with { @link Field # get ( Object ) }
* semantics , the returned value is automatically wrapped if the underlying field
* has a primitive type .
* < p > Thrown exceptions are handled via a call to { @link # handleReflectionException ( Exception ) } .
* @param field the field to get
* @param target the target object from which to get the field
* @return the field ' s current value
* /
@Nullable
public static Object getField ( Field field , @Nullable Object target ) {
try {
return field . get ( target ) ;
}
catch ( IllegalAccessException ex ) {
handleReflectionException ( ex ) ;
throw new IllegalStateException (
"Unexpected reflection exception - " + ex . getClass ( ) . getName ( ) + ": " + ex . getMessage ( ) ) ;
}
}
/ * *
* Invoke the given callback on all locally declared fields in the given class .
* @param clazz the target class to analyze
@ -778,7 +761,7 @@ public abstract class ReflectionUtils {
@@ -778,7 +761,7 @@ public abstract class ReflectionUtils {
if ( result = = null ) {
try {
result = clazz . getDeclaredFields ( ) ;
declaredFieldsCache . put ( clazz , ( result . length = = 0 ? NO_FIELDS : result ) ) ;
declaredFieldsCache . put ( clazz , ( result . length = = 0 ? EMPTY_FIELD_ARRAY : result ) ) ;
}
catch ( Throwable ex ) {
throw new IllegalStateException ( "Failed to introspect Class [" + clazz . getName ( ) +
@ -808,6 +791,35 @@ public abstract class ReflectionUtils {
@@ -808,6 +791,35 @@ public abstract class ReflectionUtils {
} , COPYABLE_FIELDS ) ;
}
/ * *
* Determine whether the given field is a "public static final" constant .
* @param field the field to check
* /
public static boolean isPublicStaticFinal ( Field field ) {
int modifiers = field . getModifiers ( ) ;
return ( Modifier . isPublic ( modifiers ) & & Modifier . isStatic ( modifiers ) & & Modifier . isFinal ( modifiers ) ) ;
}
/ * *
* Make the given field accessible , explicitly setting it accessible if
* necessary . The { @code setAccessible ( true ) } method is only called
* when actually necessary , to avoid unnecessary conflicts with a JVM
* SecurityManager ( if active ) .
* @param field the field to make accessible
* @see java . lang . reflect . Field # setAccessible
* /
@SuppressWarnings ( "deprecation" ) // on JDK 9
public static void makeAccessible ( Field field ) {
if ( ( ! Modifier . isPublic ( field . getModifiers ( ) ) | |
! Modifier . isPublic ( field . getDeclaringClass ( ) . getModifiers ( ) ) | |
Modifier . isFinal ( field . getModifiers ( ) ) ) & & ! field . isAccessible ( ) ) {
field . setAccessible ( true ) ;
}
}
// Cache handling
/ * *
* Clear the internal method / field cache .
* @since 4 . 2 . 4