Back to results for “Reflection API”
Java › Annotations

How would you implement annotation-based validation (similar to Bean Validation's @NotNull, @Size) using a custom annotation and a reflection-based validator?

Advanced

Answer

Define a custom annotation with RUNTIME retention targeting FIELD, then write a validator class that uses reflection to iterate an object's fields, checking for the presence of your validation annotations and applying the corresponding validation logic (e.g., checking a String field's length against a @Size annotation's min/max elements), collecting any violations into a result list -- this pattern is exactly how Jakarta Bean Validation (Hibernate Validator) implements its own constraint annotations under the hood.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MinLength {
    int value();
}

public class Validator {
    public static List<String> validate(Object obj) throws Exception {
        List<String> errors = new ArrayList<>();
        for (Field field : obj.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(MinLength.class)) {
                field.setAccessible(true);
                String value = (String) field.get(obj);
                int min = field.getAnnotation(MinLength.class).value();
                if (value == null || value.length() < min) {
                    errors.add(field.getName() + " must be at least " + min + " characters");
                }
            }
        }
        return errors;
    }
}
Real-world example A lightweight internal validation utility implements a simplified @MinLength annotation processed via reflection, mirroring (at a smaller scale) exactly how Hibernate Validator's @Size annotation works internally to enforce field-level constraints declaratively.

Common follow-ups: What are the performance implications of using field.setAccessible(true) and reflective field access at scale?;How does this reflection-based approach compare to a compile-time annotation processor generating validation code instead?