Skip to content
Switch branches/tags
Go to file

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

CI Maven Central Apache 2.0 Coverage Status

cronn reflection-util

Utility classes that simplify common use cases of Java Reflection.

We ship the utility classes PropertyUtils, ClassUtils, and ImmutableProxy that are described in the following sections.


Replacement for org.apache.commons.beanutils.PropertyUtils with deterministic behaviour and support to retrieve PropertyDescriptors via Java 8 method references.


class MyPojo
    private Long number;
    // getters and setters
PropertyDescriptor numberProperty = PropertyUtils.getPropertyDescriptor(MyPojo.class, MyPojo::getNumber);
MyPojo pojo = new MyPojo();
PropertyUtils.write(pojo, numberProperty, 12345L);
Long number =, numberProperty);
assertEquals(12345L, number);


interface MyInterface
    void doSomething();

    int getSomething();
String methodName = ClassUtils.getMethodName(MyInterface.class, MyInterface::doSomething);
assertEquals("doSomething", methodName);
String methodName = ClassUtils.getMethodName(MyInterface.class, MyInterface::getSomething);
assertEquals("getSomething", methodName);
Class<?>[] interfaces = { MyInterface.class };
Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), interfaces, (p, method, args) -> null);
assertEquals(MyInterface.class, ClassUtils.getRealClass(proxy));


It’s sometimes desirable to make objects immutable to prevent programming mistakes, such as the accidental modification of an object that is passed to another method.

In some cases the class itself cannot be made immutable. For example, because mutability is required by the JPA provider, the JSON serialization library, or the class is not owned by you.

Creating deep clones might come to the rescue, however, the negative performance impact might not be acceptable and you cannot detect that the clone is accidentally modified.

In such cases, ImmutableProxy can be used to create a deep but lightweight read-only view of a POJO that follows the JavaBean conventions. Invocation of getters and read-only methods is allowed but other methods such as setters are rejected by default.


class MyPojo
    private String name;
    private List<MyPojo> children = new ArrayList<>();
    // getters and setters
MyPojo original = new MyPojo();
MyPojo immutableProxy = ImmutableProxy.create(original);
immutableProxy.getName()    // ✔ returns "original"
immutableProxy.setName("") // ✖ throws UnsupportedOperationException

By default, ImmutableProxy wraps the return value of a getter in a immutable proxy:

original.getChildren().add(new MyPojo("child"));
immutableProxy.getChildren().size()  // ✔ returns 1

MyPojo firstChild = immutableProxy.getChildren().get(0);
firstChild.getName()    // ✔ returns "child"
firstChild.setName("") // ✖ throws UnsupportedOperationException

immutableProxy.getChildren().clear() // ✖ throws UnsupportedOperationException

Some methods need to be annotated with @ReadOnly if ImmutableProxy incorrectly considers the method as mutating:

class MyPojo
    List<String> elements;

    int size() {
        return elements.size();

As a final word of warning, please note that ImmutableProxy follows a best-effort approach but cannot guarantee to detect all possible modifications. For example, it cannot detect that a getter actually modifies the state as a side-effect.


Add the following Maven dependency to your project:



  • Java 8+

Related Work