The ReflectoType class is a cornerstone of the Cariochi Reflecto library, offering a rich and intuitive interface for comprehensive type introspection and manipulation in Java. It simplifies accessing detailed information about any given type, making reflective programming more accessible and powerful.
Complete Type Information
ReflectoType provides a unified approach to access a wealth of information about types:
Actual Type and Arguments: Discern the actual type, including generic type arguments, enabling precise type manipulation and inspection.
Fields and Methods: Access detailed information about fields and methods, including their types, visibility, and whether they are static or instance members. Choose between declared members or all class members.
Modifiers: Examine a type's modifiers, such as visibility (public, private), abstraction (abstract classes, interfaces), and more.
Constructors: List a type's constructors, facilitating dynamic object instantiation.
Super Type and Interfaces: Identify a type's superclass and implemented interfaces, preserving generic type information.
Special Types: Special handling for arrays and enums, including component type access and enum constant retrieval.
Utility Methods: Includes methods like is(), as(), isAssignableFrom(), and isInstance() to query type properties and relationships intuitively.
Example Usage
Here are some practical examples demonstrating the power of ReflectoType:
Constructors
// ArrayList<String> type to discoverType type =Types.type(ArrayList.class,String.class);ReflectoType reflection =reflect(type);List<ReflectoConstructor> constructors =reflection.constructors().list();List<ReflectoConstructor> declaredConstructors =reflection.constructors().declared().list();// find constructor by arguments typesReflectoConstructor constructor =reflection.constructors().get(Collection.class);Object instance =constructor.newInstance(Set.of(1));
Methods
// lists all methodsList<ReflectoMethod> methods =type.methods().list();// lists declared methodsList<ReflectoMethod> declaredMethods =type.methods().declared().list();// retrieves the ReflectoMethod for the "setUsername" method with a String parameter from the type.ReflectoMethod method =type.methods().get("setUsername(?)",String.class);// binds the ReflectoMethod to the target object (user) and creates a TargetMethod.TargetMethod targetMethod =method.withTarget(user);// invokes the "setUsername" method on the target object (user) with "test_user" as the argument.targetMethod.invoke("test_user");// filter methods with multiple criteriaList<ReflectoMethods> postProcessors =type.methods().declared().stream().filter(method ->method.modifiers().isPublic()).filter(method ->method.annotations().contains(PostProcessor.class)).filter(method ->method.returnType().is(void.class)).filter(method ->method.parameters().size() ==1).collect(Collectors.toList());// retrieves the ReflectoMethod for the static "sayHello" method with a String parameter from the type.ReflectoMethod method =type.methods().get("sayHello(?)",String.class);// converts the ReflectoMethod into a static method representation, as it doesn't require a target instance.TargetMethod staticMethod =method.asStatic();// invokes the static "sayHello" method with the argument "World" and stores the result.String result =staticMethod.invoke("World");
Fields
// list all fieldsList<ReflectoField> fields =type.fields().list();// list declared fieldsList<ReflectoField> declaredFields =type.fields().declared().list();// find fieldReflectoField field =type.fields().get("username");// binds the ReflectoField to the target object (user) and creates a TargetField.TargetField targetField =field.withTarget(user);// retrieves the current value of the 'username' field from the target object (user).String username =targetField.getValue();// sets a new value ("test_user") for the 'username' field on the target object (user).targetField.setValue("test_user");// filter fieldsList<ReflectoField> fields =type.fields().declared().stream().filter(field ->field.modifiers().isPrivate()).filter(field ->field.annotations().contains(NotNull.class)).filter(field ->field.type().is(String.class)).collect(toList());// Retrieves the ReflectoField for the static field "NAME" of type String from the type.ReflectoField field =type.fields().get("NAME",String.class);// Converts the ReflectoField into a static field representation, as it doesn't require a target instance.TargetField staticField =field.asStatic();// Retrieves the current value of the static field "NAME".String name =staticField.getValue();// Sets a new value ("New Name") for the static field "NAME".staticField.setValue("New Name");
This example demonstrates how to use the Reflecto library to introspect generic types in Java, using a Dto<T> class as the case study.
// Example Dto class with genericspublicstaticclassDto<T> {privateT value;privateDto<T> child;privateSet<Dto<T>> set;privateMap<String,Set<Dto<T>>> map;}Type type =Types.type(Dto.class,Integer.class);ReflectoType reflectoType =Reflecto.reflect(type);// Get the actual type of the first generic argument (T), which is IntegerClass<?> firstGenericArgumentType =reflectoType.arguments().get(0).actualType(); // Integer.classClass<?> firstArgumentFromPath =reflectoType.reflect("[0]").actualType(); // Integer.class// Get the actual type of the 'value' field, which is Integer (matches T)Class<?> valueFieldType =reflectoType.reflect("value").actualType(); // Integer.class// Get the actual type of the 'child.value' field, which is Integer (nested access of generic field)Class<?> childValueType =reflectoType.reflect("child.value").actualType(); // Integer.class// Get the actual type of the first argument (T) of the first element in the 'set' (Set<Dto<T>>), which is IntegerClass<?> setElementType =reflectoType.reflect("set[0][0]").actualType(); // Integer.class// Get the actual type of the 'value' field (T) within the first element of 'set' (Set<Dto<T>>), which is IntegerClass<?> setElementValueType =reflectoType.reflect("set[0].value").actualType(); // Integer.class// Get the actual type of the first generic argument (String) in the 'child.map' field (Map<String, Set<Dto<T>>>)Class<?> mapKeyType =reflectoType.reflect("child.map[0]").actualType(); // String.class// Get the actual type of the 'value' field (T) within the first element of the second generic argument (Set<Dto<T>>) in the 'child.map' field, which is Integer
Class<?> mapElementValueType =reflectoType.reflect("child.map[1][0].value").actualType(); // Integer.class
Conclusion
The ReflectoType class from Cariochi Reflecto offers a comprehensive toolkit for working with Java types reflectively. It simplifies obtaining detailed information about types, their relationships, and their members, enabling developers to write more dynamic, type-safe, and intuitive reflective code. Whether dealing with complex generic types, navigating type hierarchies, or performing runtime type checks and conversions, ReflectoType provides all the necessary functionalities in an accessible manner.