Class ReflectionUtils
- Author:
- John DeRegnaucourt ([email protected])
Copyright (c) Cedar Software LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
License
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
-
Nested Class Summary
Nested Classes -
Method Summary
Modifier and TypeMethodDescriptionstatic Object
Simplifies reflective method invocation by wrapping checked exceptions into runtime exceptions.static Object
Provides a simplified, cached reflection API for method invocation using method name.static Constructor<?>[]
getAllConstructors
(Class<?> clazz) Returns all declared constructors for the given class, storing each one in the existing CONSTRUCTOR_CACHE (keyed by (classLoader + className + paramTypes)).getAllDeclaredFields
(Class<?> c) Retrieves all fields from a class and its complete inheritance hierarchy using the default field filter.getAllDeclaredFields
(Class<?> c, Predicate<Field> fieldFilter) Retrieves all fields from a class and its complete inheritance hierarchy using a custom field filter.getAllDeclaredFieldsMap
(Class<?> c) Returns all Fields from a class (including inherited) as a Map, using the default field filter.getAllDeclaredFieldsMap
(Class<?> c, Predicate<Field> fieldFilter) Returns all Fields from a class (including inherited) as a Map filtered by the provided predicate.static <T extends Annotation>
TgetClassAnnotation
(Class<?> classToCheck, Class<T> annoClass) Searches for a specific annotation on a class, examining the entire inheritance hierarchy.static String
Return the name of the class on the object, or "null" if the object is null.static String
getClassNameFromByteCode
(byte[] byteCode) Given a byte[] of a Java .class file (compiled Java), this code will retrieve the class name from those bytes.static Constructor
<?> getConstructor
(Class<?> clazz, Class<?>... parameterTypes) Gets a constructor for the specified class with the given parameter types, regardless of access level (public, protected, private, or package).getDeclaredFields
(Class<?> c) Retrieves the declared fields of a class (not it's parent) using the default field filter, with caching for performance.static void
getDeclaredFields
(Class<?> c, Collection<Field> fields) Deprecated.getDeclaredFields
(Class<?> c, Predicate<Field> fieldFilter) Retrieves the declared fields of a class (not it's parent) using a custom field filter, with caching for performance.getDeepDeclaredFieldMap
(Class<?> c) Deprecated.As of 3.0.0, replaced bygetAllDeclaredFieldsMap(Class)
.static Collection
<Field> getDeepDeclaredFields
(Class<?> c) Deprecated.As of 3.0.0, replaced bygetAllDeclaredFields(Class)
.static Field
Retrieves a specific field from a class by name, searching through the entire class hierarchy (including superclasses).static Method
Retrieves a method of any access level by name and parameter types, with sophisticated caching for optimal performance.static Method
Retrieves a method by name and argument count from an object instance, using a deterministic selection strategy when multiple matching methods exist.static <T extends Annotation>
TgetMethodAnnotation
(Method method, Class<T> annoClass) Searches for a specific annotation on a method, examining the entire inheritance hierarchy.static Method
getNonOverloadedMethod
(Class<?> clazz, String methodName) Fetches a no-argument method from the specified class, caching the result for subsequent lookups.static void
setClassAnnotationCache
(Map<Object, Annotation> cache) Sets a custom cache implementation for class annotation lookups.static void
setClassFieldsCache
(Map<Object, Collection<Field>> cache) Sets a custom cache implementation for field lookups.static void
setConstructorCache
(Map<Object, Constructor<?>> cache) Sets a custom cache implementation for constructor lookups.static void
setFieldCache
(Map<Object, Field> cache) Sets a custom cache implementation for field lookups.static void
setMethodAnnotationCache
(Map<Object, Annotation> cache) Sets a custom cache implementation for method annotation lookups.static void
setMethodCache
(Map<Object, Method> cache) Sets a custom cache implementation for method lookups.
-
Method Details
-
setMethodCache
Sets a custom cache implementation for method lookups.This method allows switching out the default LRUCache implementation with a custom cache implementation. The provided cache must be thread-safe and should implement the Map interface. This method is typically called once during application initialization.
- Parameters:
cache
- The custom cache implementation to use for storing method lookups. Must be thread-safe and implement Map interface.
-
setClassFieldsCache
Sets a custom cache implementation for field lookups.This method allows switching out the default LRUCache implementation with a custom cache implementation. The provided cache must be thread-safe and should implement the Map interface. This method is typically called once during application initialization.
- Parameters:
cache
- The custom cache implementation to use for storing field lookups. Must be thread-safe and implement Map interface.
-
setFieldCache
Sets a custom cache implementation for field lookups.This method allows switching out the default LRUCache implementation with a custom cache implementation. The provided cache must be thread-safe and should implement the Map interface. This method is typically called once during application initialization.
- Parameters:
cache
- The custom cache implementation to use for storing field lookups. Must be thread-safe and implement Map interface.
-
setClassAnnotationCache
Sets a custom cache implementation for class annotation lookups.This method allows switching out the default LRUCache implementation with a custom cache implementation. The provided cache must be thread-safe and should implement the Map interface. This method is typically called once during application initialization.
- Parameters:
cache
- The custom cache implementation to use for storing class annotation lookups. Must be thread-safe and implement Map interface.
-
setMethodAnnotationCache
Sets a custom cache implementation for method annotation lookups.This method allows switching out the default LRUCache implementation with a custom cache implementation. The provided cache must be thread-safe and should implement the Map interface. This method is typically called once during application initialization.
- Parameters:
cache
- The custom cache implementation to use for storing method annotation lookups. Must be thread-safe and implement Map interface.
-
setConstructorCache
Sets a custom cache implementation for constructor lookups.This method allows switching out the default LRUCache implementation with a custom cache implementation. The provided cache must be thread-safe and should implement the Map interface. This method is typically called once during application initialization.
- Parameters:
cache
- The custom cache implementation to use for storing constructor lookups. Must be thread-safe and implement Map interface.
-
getClassAnnotation
public static <T extends Annotation> T getClassAnnotation(Class<?> classToCheck, Class<T> annoClass) Searches for a specific annotation on a class, examining the entire inheritance hierarchy. Results (including misses) are cached for performance.This method performs an exhaustive search through:
- The class itself
- All superclasses
- All implemented interfaces
- All super-interfaces
Key behaviors:
- Caches both found annotations and misses (nulls)
- Handles different classloaders correctly
- Uses depth-first search through the inheritance hierarchy
- Prevents circular reference issues
- Returns the first matching annotation found
- Thread-safe implementation
Example usage:
JsonObject anno = ReflectionUtils.getClassAnnotation(MyClass.class, JsonObject.class); if (anno != null) { // Process annotation... }
- Type Parameters:
T
- The type of the annotation- Parameters:
classToCheck
- The class to search for the annotationannoClass
- The annotation class to search for- Returns:
- The annotation if found, null otherwise
- Throws:
IllegalArgumentException
- if either classToCheck or annoClass is null
-
getMethodAnnotation
Searches for a specific annotation on a method, examining the entire inheritance hierarchy. Results (including misses) are cached for performance.This method performs an exhaustive search through:
- The method in the declaring class
- Matching methods in all superclasses
- Matching methods in all implemented interfaces
- Matching methods in all super-interfaces
Key behaviors:
- Caches both found annotations and misses (nulls)
- Handles different classloaders correctly
- Uses depth-first search through the inheritance hierarchy
- Matches methods by name and parameter types
- Prevents circular reference issues
- Returns the first matching annotation found
- Thread-safe implementation
Example usage:
Method method = obj.getClass().getMethod("processData", String.class); JsonProperty anno = ReflectionUtils.getMethodAnnotation(method, JsonProperty.class); if (anno != null) { // Process annotation... }
- Type Parameters:
T
- The type of the annotation- Parameters:
method
- The method to search for the annotationannoClass
- The annotation class to search for- Returns:
- The annotation if found, null otherwise
- Throws:
IllegalArgumentException
- if either method or annoClass is null
-
getField
Retrieves a specific field from a class by name, searching through the entire class hierarchy (including superclasses). Results are cached for performance.This method:
- Searches through all fields (public, protected, package, private)
- Includes fields from superclasses
- Excludes static fields
- Makes non-public fields accessible
- Caches results (including misses) for performance
Example usage:
Field nameField = ReflectionUtils.getField(Employee.class, "name"); if (nameField != null) { nameField.set(employee, "John"); }
- Parameters:
c
- The class to search for the fieldfieldName
- The name of the field to find- Returns:
- The Field object if found, null if the field doesn't exist
- Throws:
IllegalArgumentException
- if either the class or fieldName is null
-
getDeclaredFields
Retrieves the declared fields of a class (not it's parent) using a custom field filter, with caching for performance. This method provides direct field access with customizable filtering criteria.Key features:
- Custom field filtering through provided Predicate
- Returns only fields declared directly on the specified class (not from superclasses)
- Caches results for both successful lookups and misses
- Makes non-public fields accessible when possible
- Returns an unmodifiable List to prevent modification
Implementation details:
- Thread-safe caching mechanism
- Handles different classloaders correctly
- Maintains consistent order of fields
- Caches results per class/filter combination
Example usage:
// Get non-static public fields only List<Field> publicFields = getDeclaredFields(MyClass.class, field -> !Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers())); // Get fields with specific names Set<String> allowedNames = Set.of("id", "name", "value"); List<Field> specificFields = getDeclaredFields(MyClass.class, field -> allowedNames.contains(field.getName()));
- Parameters:
c
- The class whose declared fields are to be retrieved (must not be null)fieldFilter
- Predicate to determine which fields should be included (must not be null)- Returns:
- An unmodifiable list of fields that match the filter criteria
- Throws:
IllegalArgumentException
- if either the class or fieldFilter is null- See Also:
-
getDeclaredFields
Retrieves the declared fields of a class (not it's parent) using the default field filter, with caching for performance. This method provides the same functionality asgetDeclaredFields(Class, Predicate)
but uses the default field filter.The default filter excludes:
- Static fields
- Internal enum fields ("internal" and "ENUM$VALUES")
- Enum base class fields ("hash" and "ordinal")
- Groovy's metaClass field
- Parameters:
c
- The class whose complete field hierarchy is to be retrieved- Returns:
- An unmodifiable list of all fields in the class hierarchy that pass the default filter
- Throws:
IllegalArgumentException
- if the class is null- See Also:
-
getAllDeclaredFields
Retrieves all fields from a class and its complete inheritance hierarchy using a custom field filter.Key features:
- Custom field filtering through provided Predicate
- Includes fields from the specified class and all superclasses
- Caches results for performance optimization
- Makes non-public fields accessible when possible
Implementation details:
- Thread-safe caching mechanism
- Maintains consistent order (subclass fields before superclass fields)
- Returns an unmodifiable List to prevent modification
- Uses recursive caching strategy for optimal performance
Example usage:
// Get all non-transient fields in hierarchy List<Field> persistentFields = getAllDeclaredFields(MyClass.class, field -> !Modifier.isTransient(field.getModifiers())); // Get all fields matching specific name pattern List<Field> matchingFields = getAllDeclaredFields(MyClass.class, field -> field.getName().startsWith("customer"));
- Parameters:
c
- The class whose complete field hierarchy is to be retrieved (must not be null)fieldFilter
- Predicate to determine which fields should be included (must not be null)- Returns:
- An unmodifiable list of all matching fields in the class hierarchy
- Throws:
IllegalArgumentException
- if either the class or fieldFilter is null- See Also:
-
getAllDeclaredFields
Retrieves all fields from a class and its complete inheritance hierarchy using the default field filter. The default filter excludes:- Static fields
- Internal enum fields ("internal" and "ENUM$VALUES")
- Enum base class fields ("hash" and "ordinal")
- Groovy's metaClass field
This method is equivalent to calling
getAllDeclaredFields(Class, Predicate)
with the default field filter.- Parameters:
c
- The class whose complete field hierarchy is to be retrieved- Returns:
- An unmodifiable list of all fields in the class hierarchy that pass the default filter
- Throws:
IllegalArgumentException
- if the class is null- See Also:
-
getAllDeclaredFieldsMap
Returns all Fields from a class (including inherited) as a Map filtered by the provided predicate.The returned Map uses String field names as keys and Field objects as values, with special handling for name collisions across the inheritance hierarchy.
Field name mapping rules:
- Simple field names (e.g., "name") are used when no collision exists
- On collision, fully qualified names (e.g., "com.example.Parent.name") are used
- Child class fields take precedence for simple name mapping
- Parent class fields use fully qualified names when shadowed
Example usage:
// Get all non-transient fields Map<String, Field> persistentFields = getAllDeclaredFieldsMap( MyClass.class, field -> !Modifier.isTransient(field.getModifiers()) ); // Get all fields with specific annotation Map<String, Field> annotatedFields = getAllDeclaredFieldsMap( MyClass.class, field -> field.isAnnotationPresent(MyAnnotation.class) );
- Parameters:
c
- Class whose fields are being fetched (must not be null)fieldFilter
- Predicate to determine which fields should be included (must not be null)- Returns:
- Map of filtered fields, keyed by field name (or fully qualified name on collision)
- Throws:
IllegalArgumentException
- if either the class or fieldFilter is null- See Also:
-
getAllDeclaredFieldsMap
Returns all Fields from a class (including inherited) as a Map, using the default field filter. This method provides the same functionality asgetAllDeclaredFieldsMap(Class, Predicate)
but uses the default field filter which excludes:- Static fields
- Internal enum fields ("internal" and "ENUM$VALUES")
- Enum base class fields ("hash" and "ordinal")
- Groovy's metaClass field
- Parameters:
c
- Class whose fields are being fetched- Returns:
- Map of filtered fields, keyed by field name (or fully qualified name on collision)
- Throws:
IllegalArgumentException
- if the class is null- See Also:
-
getDeepDeclaredFields
Deprecated.As of 3.0.0, replaced bygetAllDeclaredFields(Class)
. Note that getAllDeclaredFields() includes transient fields and synthetic fields (like "this$"). If you need the old behavior, filter the additional fields:
This method may be removed in 3.0.0.// Get fields excluding transient and synthetic fields List<Field> fields = getAllDeclaredFields(MyClass.class, field -> DEFAULT_FIELD_FILTER.test(field) && !Modifier.isTransient(field.getModifiers()) && !field.isSynthetic() );
-
getDeepDeclaredFieldMap
Deprecated.As of 3.0.0, replaced bygetAllDeclaredFieldsMap(Class)
. Note that getAllDeclaredFieldsMap() includes transient fields and synthetic fields (like "this$"). If you need the old behavior, filter the additional fields:
This method may be removed in 3.0.0.// Get fields excluding transient and synthetic fields List<Field> fields = getAllDeclaredFieldsMap(MyClass.class, field -> DEFAULT_FIELD_FILTER.test(field) && !Modifier.isTransient(field.getModifiers()) && !field.isSynthetic() );
-
getDeclaredFields
Deprecated.As of 3.0.0, replaced bygetAllDeclaredFields(Class)
. Note that getAllDeclaredFields() includes transient fields and synthetic fields (like "this$"). If you need the old behavior, filter the additional fields:
This method will be removed in 3.0.0 or soon after.// Combine DEFAULT_FIELD_FILTER with additional criteria for legacy behavior Predicate<Field> legacyFilter = field -> DEFAULT_FIELD_FILTER.test(field) && !Modifier.isTransient(field.getModifiers()) && !field.isSynthetic();
-
call
Simplifies reflective method invocation by wrapping checked exceptions into runtime exceptions. This method provides a cleaner API for reflection-based method calls.Key features:
- Converts checked exceptions to runtime exceptions
- Preserves the original exception cause
- Provides clear error messages
- Handles null checking for both method and instance
Exception handling:
- IllegalAccessException → RuntimeException
- InvocationTargetException → RuntimeException (with target exception)
- Null method → IllegalArgumentException
- Null instance → IllegalArgumentException
Example usage:
Method method = ReflectionUtils.getMethod(obj.getClass(), "processData", String.class); Object result = ReflectionUtils.call(obj, method, "input data"); // No need for try-catch blocks for checked exceptions // Just handle RuntimeException if needed
- Parameters:
instance
- The object instance on which to call the methodmethod
- The Method object representing the method to callargs
- The arguments to pass to the method (may be empty)- Returns:
- The result of the method invocation, or null for void methods
- Throws:
IllegalArgumentException
- if either method or instance is nullRuntimeException
- if the method is inaccessible or throws an exception- See Also:
-
call
Provides a simplified, cached reflection API for method invocation using method name. This method combines method lookup and invocation in one step, with results cached for performance.Key features:
- Caches method lookups for improved performance
- Handles different classloaders correctly
- Converts checked exceptions to runtime exceptions
- Caches both successful lookups and misses
- Thread-safe implementation
Limitations:
- Does not distinguish between overloaded methods with same parameter count
- Only matches by method name and parameter count
- Always selects the first matching method found
- Only finds public methods
Exception handling:
- Method not found → IllegalArgumentException
- IllegalAccessException → RuntimeException
- InvocationTargetException → RuntimeException (with target exception)
- Null instance/methodName → IllegalArgumentException
Example usage:
// Simple case - no method overloading Object result = ReflectionUtils.call(myObject, "processData", "input"); // For overloaded methods, use the more specific call() method: Method specific = ReflectionUtils.getMethod(myObject.getClass(), "processData", String.class); Object result = ReflectionUtils.call(myObject, specific, "input");
- Parameters:
instance
- The object instance on which to call the methodmethodName
- The name of the method to callargs
- The arguments to pass to the method (may be empty)- Returns:
- The result of the method invocation, or null for void methods
- Throws:
IllegalArgumentException
- if the method cannot be found, or if instance/methodName is nullRuntimeException
- if the method is inaccessible or throws an exception- See Also:
-
getMethod
Retrieves a method of any access level by name and parameter types, with sophisticated caching for optimal performance. This method searches through the class hierarchy and attempts to make non-public methods accessible.Key features:
- Finds methods of any access level (public, protected, package, private)
- Includes bridge methods (compiler-generated for generic type erasure)
- Includes synthetic methods (compiler-generated for lambdas, inner classes)
- Attempts to make non-public methods accessible
- Caches both successful lookups and misses
- Handles different classloaders correctly
- Thread-safe implementation
- Searches entire inheritance hierarchy
- Parameters:
c
- The class to search for the methodmethodName
- The name of the method to findtypes
- The parameter types for the method (empty array for no-arg methods)- Returns:
- The Method object if found and made accessible, null if not found
- Throws:
IllegalArgumentException
- if class or methodName is null
-
getMethod
Retrieves a method by name and argument count from an object instance, using a deterministic selection strategy when multiple matching methods exist.Key features:
- Finds methods of any access level (public, protected, package, private)
- Uses deterministic method selection strategy
- Attempts to make non-public methods accessible
- Caches both successful lookups and misses
- Handles different classloaders correctly
- Thread-safe implementation
- Searches entire inheritance hierarchy
Method selection priority (when multiple methods match):
- 1. Non-synthetic/non-bridge methods preferred
- 2. Higher accessibility preferred (public > protected > package > private)
- 3. Most specific declaring class in hierarchy preferred
Example usage:
// Will select most accessible, non-synthetic method with two parameters Method method = ReflectionUtils.getMethod(myObject, "processData", 2); // For exact method selection, use getMethod with specific types: Method specific = ReflectionUtils.getMethod( myObject.getClass(), "processData", String.class, Integer.class );
- Parameters:
instance
- The object instance on which to find the methodmethodName
- The name of the method to findargCount
- The number of parameters the method should have- Returns:
- The Method object, made accessible if necessary
- Throws:
IllegalArgumentException
- if the method is not found or if bean/methodName is null- See Also:
-
getConstructor
Gets a constructor for the specified class with the given parameter types, regardless of access level (public, protected, private, or package). Both successful lookups and misses are cached for performance.This method:
- Searches for constructors of any access level
- Attempts to make non-public constructors accessible
- Returns the constructor even if it cannot be made accessible
- Caches both found constructors and misses
- Handles different classloaders correctly
Note: Finding a constructor does not guarantee that the caller has the necessary permissions to invoke it. Security managers or module restrictions may prevent access even if the constructor is found and marked accessible.
- Parameters:
clazz
- The class whose constructor is to be retrievedparameterTypes
- The parameter types for the constructor- Returns:
- The constructor matching the specified parameters, or null if not found
- Throws:
IllegalArgumentException
- if the class is null
-
getAllConstructors
Returns all declared constructors for the given class, storing each one in the existing CONSTRUCTOR_CACHE (keyed by (classLoader + className + paramTypes)).If the constructor is not yet in the cache, we setAccessible(true) when possible and store it. Subsequent calls will retrieve the same Constructor from the cache.
- Parameters:
clazz
- The class whose constructors we want.- Returns:
- An array of all declared constructors for that class.
-
getNonOverloadedMethod
Fetches a no-argument method from the specified class, caching the result for subsequent lookups. This is intended for methods that are not overloaded and require no arguments (e.g., simple getter methods).If the class contains multiple methods with the same name, an
IllegalArgumentException
is thrown.- Parameters:
clazz
- the class that contains the desired methodmethodName
- the name of the no-argument method to locate- Returns:
- the
Method
instance found on the given class - Throws:
IllegalArgumentException
- if the method is not found or if multiple methods with the same name exist
-
getClassName
Return the name of the class on the object, or "null" if the object is null.- Parameters:
o
- Object to get the class name.- Returns:
- String name of the class or "null"
-
getClassNameFromByteCode
Given a byte[] of a Java .class file (compiled Java), this code will retrieve the class name from those bytes. This method supports class files up to the latest JDK version.- Parameters:
byteCode
- byte[] of compiled byte code- Returns:
- String fully qualified class name
- Throws:
IOException
- if there are problems reading the byte codeIllegalStateException
- if the class file format is not recognized
-
getAllDeclaredFields(Class)
.