javaadvanced

Reflection Utilities — Inspect and Invoke

Inspect classes at runtime: list fields/methods, invoke methods, get annotations, and create instances.

java
import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Collectors;

public class ReflectionUtils {

    // List all fields (including inherited)
    public static List<Field> getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        while (clazz != null && clazz != Object.class) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        return fields;
    }

    // Get field value by name
    public static Object getFieldValue(Object obj, String fieldName) {
        try {
            Field field = findField(obj.getClass(), fieldName);
            field.setAccessible(true);
            return field.get(obj);
        } catch (Exception e) {
            throw new RuntimeException("Cannot access field: " + fieldName, e);
        }
    }

    // Set field value
    public static void setFieldValue(Object obj, String fieldName, Object value) {
        try {
            Field field = findField(obj.getClass(), fieldName);
            field.setAccessible(true);
            field.set(obj, value);
        } catch (Exception e) {
            throw new RuntimeException("Cannot set field: " + fieldName, e);
        }
    }

    private static Field findField(Class<?> clazz, String name) {
        while (clazz != null) {
            try { return clazz.getDeclaredField(name); }
            catch (NoSuchFieldException e) { clazz = clazz.getSuperclass(); }
        }
        throw new RuntimeException("Field not found: " + name);
    }

    // Invoke method by name
    public static Object invoke(Object obj, String methodName, Object... args) {
        try {
            Class<?>[] paramTypes = Arrays.stream(args)
                .map(Object::getClass).toArray(Class[]::new);
            Method method = obj.getClass().getMethod(methodName, paramTypes);
            return method.invoke(obj, args);
        } catch (Exception e) {
            throw new RuntimeException("Cannot invoke: " + methodName, e);
        }
    }

    // Object to Map (shallow)
    public static Map<String, Object> toMap(Object obj) {
        return getAllFields(obj.getClass()).stream()
            .peek(f -> f.setAccessible(true))
            .collect(Collectors.toMap(
                Field::getName,
                f -> {
                    try { return f.get(obj); }
                    catch (Exception e) { return "<error>"; }
                }
            ));
    }

    // Create instance from class name
    @SuppressWarnings("unchecked")
    public static <T> T createInstance(String className, Object... args) {
        try {
            Class<?> clazz = Class.forName(className);
            if (args.length == 0) {
                return (T) clazz.getDeclaredConstructor().newInstance();
            }
            Class<?>[] types = Arrays.stream(args)
                .map(Object::getClass).toArray(Class[]::new);
            return (T) clazz.getDeclaredConstructor(types).newInstance(args);
        } catch (Exception e) {
            throw new RuntimeException("Cannot instantiate: " + className, e);
        }
    }

    // Demo
    static class Person {
        private String name;
        private int age;
        Person() {}
        Person(String name, int age) { this.name = name; this.age = age; }
        public String greet() { return "Hi, I'm " + name; }
    }

    public static void main(String[] args) {
        var person = new Person("Alice", 30);

        System.out.println(getFieldValue(person, "name")); // Alice
        setFieldValue(person, "name", "Bob");
        System.out.println(invoke(person, "greet")); // Hi, I'm Bob
        System.out.println(toMap(person)); // {name=Bob, age=30}

        getAllFields(Person.class).forEach(f ->
            System.out.printf("%s %s %s%n", Modifier.toString(f.getModifiers()),
                f.getType().getSimpleName(), f.getName()));
    }
}

Use Cases

  • Framework and library development
  • Object mapping and serialization
  • Testing utilities for accessing private fields

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.