Custom Annotation for Validating a Bean in Java
This example validates that bean fields are not null using a custom class-level annotation.
Step 1: Define Annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNullAndNotEmpty {
}
Step 2: Validator Using Reflection
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class NotNullAndNotEmptyValidator {
public static List<String> validate(Object obj) {
List<String> errors = new ArrayList<>();
if (obj.getClass().getAnnotation(NotNullAndNotEmpty.class) == null) {
return errors;
}
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
if (field.get(obj) == null) {
errors.add(field.getName() + " is null or empty");
}
} catch (IllegalAccessException e) {
errors.add("Cannot access field " + field.getName());
}
}
return errors;
}
}
Step 3: Use on Model
@NotNullAndNotEmpty
public class Employee {
private String name;
private String address;
public Employee(String name, String address) {
this.name = name;
this.address = address;
}
}
Step 4: Run
Employee emp = new Employee("Sandeep", null);
System.out.println(NotNullAndNotEmptyValidator.validate(emp));
Output:
[address is null or empty]
For production, prefer Jakarta Bean Validation (@NotNull, @NotBlank) unless custom behavior is required.
Production API Equivalent (Jakarta Bean Validation)
import jakarta.validation.constraints.NotBlank;
public class EmployeeRequest {
@NotBlank
private String name;
@NotBlank
private String address;
// getters/setters
}
Spring Boot controller usage:
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
@RestController
class EmployeeController {
@PostMapping("/employees")
public String create(@Valid @RequestBody EmployeeRequest request) {
return "created";
}
}
This gives standard validation error handling and integrates cleanly with modern Java 21+ service stacks.
JDK 11 and Java 17 Notes
- JDK 11 projects often use
javax.validationnamespace. - Java 17 era projects (especially Spring Boot 3+) commonly use
jakarta.validation. - Validation concepts are the same; package namespace is the key migration point.
Key Takeaways
- Prefer simple APIs and explicit behavior.
- Document edge cases and failure modes early.
- Keep examples small, testable, and production-oriented.