Sitemap
Samuelgbenga

Samuelgbenga

Technical Writer || Backend Engineer || Java Developer

Custom Validators in Java

2 min readApr 5, 2025

--

Press enter or click to view image in full size
neat

So, you’ve got a signup form, and someone tries to register as kingkong123 for the 14th time. What do you do? Throw the whole server away? Nope. You create a custom validator to ensure usernames are unique.

Get Samuelgbenga’s stories in your inbox

Join Medium for free to get updates from this writer.

Let’s go step by step — short, sweet, and practical.

1. Entity Setup

@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@UniqueUsername // <- Our custom annotation
private String username;
private String email;
private String password;
// Getters and setters
}

2. Custom Annotation

@Constraint(validatedBy = UniqueUsernameValidator.class)
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueUsername {
String message() default "Username already exists";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

3. Validator Class

@Component
@RequiredArgsConstructor
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {

private final UserRepository userRepository;

@Override
public boolean isValid(String username, ConstraintValidatorContext context) {
return username != null && !userRepository.existsByUsername(username);
}
}

4. Repository Layer

public interface UserRepository extends JpaRepository<User, Long> {
boolean existsByUsername(String username);
}

5. Controller Layer

@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {

private final UserService userService;

@PostMapping("/register")
public ResponseEntity<String> registerUser(@Valid @RequestBody User user) {
userService.saveUser(user);
return ResponseEntity.ok("User registered successfully!");
}
}

6. Service Layer

@Service
@RequiredArgsConstructor
public class UserService {

private final UserRepository userRepository;
public void saveUser(User user) {
userRepository.save(user);
}
}

7. Global Exception Handling (Make it Reusable)

@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Object> handleValidationException(MethodArgumentNotValidException ex) {
Map<String, Object> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage()));
return buildErrorResponse(HttpStatus.BAD_REQUEST, "Validation failed", errors);
}
private ResponseEntity<Object> buildErrorResponse(HttpStatus status, String message, Map<String, Object> errors) {
Map<String, Object> response = new HashMap<>();
response.put("status", status.value());
response.put("message", message);
response.put("errors", errors);
return new ResponseEntity<>(response, status);
}
}

Final Words

There you go. You now have a working custom validator in Java. Say goodbye to duplicate usernames and hello to clean data.

--

--

Samuelgbenga
Samuelgbenga