Open JelmenGuhlke opened 6 months ago
I would suggest implementing a custom annotation with custom validator which throws a custom NullParameterException. However, the topic with domain specific exceptions is discussed in #593. I would suggest first to design the exception handling and then revisit this issue.
Describe the bug The
jakarta.validation.constraints.NotNull
validation constrain is heavily used in the Essencium project on method parameter level. This is true for the controller, service and repository layer. When anull
value is passed to a method with a@NotNull
annotated parameter, no exception is thrown. Instead the code simple continues with the normal execution flow.By default the
@NotNull
is only a hint, like the passed parameter should not benull
and the implementation of the method should take care of anynull
values - e.g. withAs written above, in general the
@NotNull
does nothing if the passed value isnull
until a validator is executed against the given value. This happens for example if the@NotNull
is set on a JPA entity parameter during the JPA commit and flush process. It also happens for controller methods - in these cases the@NotNull
is often redundant, since a@RequestBody
or@PathParam
/@RequestParam
can not benull
.@Service
and@Repository
classes do not execute any validation against method parameter. So for all@NotNull
annotated parameters anull
value can be passed.To Reproduce Steps to reproduce the behavior: Since the validation of method parameters are part of interaction two components with each other, a simple integration test can demonstrate the behavior:
// in AbstractUserController.java public void publicNullMethod(@NotNull final String token) { var userToUpdate = userRepository .findByPasswordResetToken(token) .orElseThrow(() -> new BadCredentialsException("Invalid reset token")); }
// in BaseUserRepository.java Optional findByPasswordResetToken(@NotNull String passwordResetToken);
Execute simple integration test
Expected behavior As a user of the API I would assume, that any passed
null
should throw a validation exception. But in the given example above the thrown exception is "jakarta.servlet.ServletException: Request processing failed: org.springframework.dao.IncorrectResultSizeDataAccessException: Query did not return a unique result: 2 results were returned" and is thrown infindByPasswordResetToken
execution of the repository proxy. The passednull
value to the service is passed to the repository and the SQL query is executed with aselect *** where token is null;
, although on the service method and the repository method a@NotNull
is present.To enable the validation execution, a
@Validated
can be added to the class. Since all the@NotNull
annotations lead to a false sense of security during development, all usages on parameter level should be checked and if possible and needed:@Validated
at class level@NotNull
if it is not needed@Validated
at the class, a programmaticallyObjects.requireNonNull(value)
should be used in exchange to the@NotNull
annotation@Validated
classes do not call a validation of a method parameter if the method call comes from the class itself. The reason for this is, that Spring hooks the validation into the communication with the AOP proxy; so any call of a method within the same class, is not communicating over the the proxy, so no validation will be executed. In all of these cases, the@NotNull
needs to be exchanged toObjects.requireNonNull(value)