During work on my current project I tried to find the optimal solution how to validate the arguments of some service level methods. I don't want to write every time an if
clause for nullcheck or add additional validation logic, for example ensure a numeric value not to be less then 0.
I added jakarta.validation
annotations as you can see below, but first on the implementations of the functions. During the build this error was thrown:
HV000151: A method overriding another method must not redefine the parameter constraint configuration ...
This occurs when you define validation annotations on a method parameter that overrides a method from an interface or superclass that already has validation constraints. Jakarta Bean Validation enforces constraints defined by interfaces or base classes and does not allow the redefinition of constraints on overridden methods.
Why does this happen?
Bean Validation requires consistency in method-level constraints between interfaces (or parent classes) and their implementations. If your interface method parameters have no constraints, your implementation methods cannot introduce them. If the interface method parameters have constraints, your implementation must match them exactly.
How to fix it:
You have a couple of choices:
1. Move constraints to the interface (recommended):
Define your validation annotations directly in the interface.
public interface MyService {
void performAction(@NotNull String input);
}
public class MyServiceImpl implements MyService {
@Override
public void performAction(String input) {
// Implementation code
}
}
This clearly defines constraints at the interface level and ensures all implementations have consistent constraints.
2. Use constraints only in the implementation class:
If your interface doesn't specify constraints, and you still want constraints in your implementation, you should avoid parameter constraints on overridden methods. Instead, you can use field-level validation or manually validate parameters within the method body.
Example using manual validation:
public class MyServiceImpl implements MyService {
@Override
public void performAction(String input) {
if (input == null) {
throw new IllegalArgumentException("input must not be null");
}
// Implementation code
}
}
Alternatively, move constraints to fields or separate objects.
3. Separate constraints into DTOs or dedicated validated objects:
This is a robust, widely used approach.
public interface MyService {
void performAction(ActionRequest request);
}
public class ActionRequest {
@NotNull
private String input;
// getters, setters
}
public class MyServiceImpl implements MyService {
@Override
public void performAction(@Valid ActionRequest request) {
// Implementation
}
}
This approach clearly separates concerns and validation logic into dedicated classes, avoiding the original issue.
Recommended Best Practice:
Usually, constraints belong clearly at the interface or domain model level, or within DTOs/request objects. Defining constraints in interfaces or separate request objects ensures clear, reusable, and maintainable validation logic.
Summary of the best solution:
- Define constraints in interfaces if they logically apply to all implementations.
- Use DTO/request classes with annotations if constraints vary or if method signatures should remain clean.
- Avoid redefining constraints at the implementation method directly.
This will effectively resolve the error and ensure a clear, maintainable validation strategy.
Top comments (0)