How to make spring data jpa generated methods throw exception on null parameters

Viewed 561

I have this service method which calls a repo method which is in turn generated by spring:

Service method:

 public User findUserByEmail(String email) {
        try {
            Assert.notNull(email,"email is null!");
            Optional<User> userOptional = userRepo.findUserDAOByEmail(email);
            return userOptional.orElseThrow();
        } 
        catch (...){
            ...
        }
    }

Repo:

public interface UserRepo extends JpaRepository<User, Long> {
    Optional<User> findUserByEmail(String email);
}

I wanted the repo method to throw IllegalArgumentException as its friends (the methods that come out of the box with Jparepository do), but instead it accepted the null parameter "email" and searched for it in the database and returned a result that no such user exist (p.s.: email is constrained to be not null in my schema)

So I did Assert.notNull(email,"email is null!");

But I wonder if there is a better way to validate that "email" is not null?

2 Answers

A constraint can be put on the parameter as well like this -

@Validated
@Repository
public interface UserRepo extends JpaRepository<User, Long> {
    Optional<User> findUserByEmail(@NotNull String email);
}

@Validated enables Spring to invoke various Validation Constraints.

Working Example


gradle dependency

    compile 'org.springframework.boot:spring-boot-starter'
    compile 'org.springframework.boot:spring-boot-starter-web'
    compile 'org.springframework.boot:spring-boot-starter-validation'
    compile 'org.springframework.boot:spring-boot-starter-data-jpa'
    compile("mysql:mysql-connector-java:8.0.16")

UserRepository.java

@Validated
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
    Optional<User> findUserByName(@NotEmpty String name);
}

Console Output

javax.validation.ConstraintViolationException: findUserByName.name: must not be empty
    at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:117) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at com.sun.proxy.$Proxy88.findUserByName(Unknown Source) ~[na:na]
    at com.test.validation.controller.UserController.get(UserController.java:18) ~[main/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]

the repositories has no way to access it directly out of services classes so you need to create a service class annotated with @Service then implement your own method to find the user using the UserRepo repository interface then you can inject the service class into the testing unit and make your own tests.

Related