So I have custom validator and when I set return
value to false
then it works -
import com.vhealth.api.service.UserService; import com.vhealth.api.utils.exceptions.InvalidPayloadException; import org.springframework.beans.factory.annotation.Autowired; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class UserNameUniqueValidator implements ConstraintValidator<UserNameUnique, String> { @Autowired UserService userService; @Override public void initialize(UserNameUnique constraintAnnotation) { } @Override public boolean isValid(String userName, ConstraintValidatorContext context) { if (userService.findByUserName(userName) != null) { throw new InvalidPayloadException("Creating user requires unique userName new"); //return false; } return true; } }
But when I try throw exception in that section I get error that problem is caused by my custom exception:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ValidationException: Unexpected exception during isValid call at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:932) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:827) at javax.servlet.http.HttpServlet.service(HttpServlet.java:688) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:801) at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:66) at javax.servlet.http.HttpServlet.service(HttpServlet.java:770) at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:168) at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:136) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:201) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:91) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:136) at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:134) at com.vhealth.api.controller.ApiUserControllerTest.shouldReturnErrorMessageToAdminWhenCreatingUserWithUsedUserName(ApiUserControllerTest.java:53) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) at org.junit.runner.JUnitCore.run(JUnitCore.java:157) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) Caused by: javax.validation.ValidationException: Unexpected exception during isValid call at org.hibernate.validator.engine.ConstraintTree.validateSingleConstraint(ConstraintTree.java:281) at org.hibernate.validator.engine.ConstraintTree.validateConstraints(ConstraintTree.java:153) at org.hibernate.validator.engine.ConstraintTree.validateConstraints(ConstraintTree.java:117) at org.hibernate.validator.metadata.MetaConstraint.validateConstraint(MetaConstraint.java:84) at org.hibernate.validator.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:452) at org.hibernate.validator.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:397) at org.hibernate.validator.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:361) at org.hibernate.validator.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:313) at org.hibernate.validator.engine.ValidatorImpl.validate(ValidatorImpl.java:139) at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:102) at org.springframework.validation.DataBinder.validate(DataBinder.java:772) at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.validate(RequestResponseBodyMethodProcessor.java:115) at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:101) at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77) at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:123) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:920) ... 68 more Caused by: com.vhealth.api.utils.exceptions.InvalidPayloadException: Creating user requires unique userName new at com.vhealth.api.utils.validators.UserNameUniqueValidator.isValid(UserNameUniqueValidator.java:22) at com.vhealth.api.utils.validators.UserNameUniqueValidator.isValid(UserNameUniqueValidator.java:11) at org.hibernate.validator.engine.ConstraintTree.validateSingleConstraint(ConstraintTree.java:278) ... 90 more
Exception is placed in @Controller ExceptionResolover
@ExceptionHandler(InvalidPayloadException.class) public ResponseEntity handleEmptyFieldException(InvalidPayloadException ex) { return new ResponseEntity(ex.getMessage(), HttpStatus.BAD_REQUEST); }
Edit: Throwing InvalidPayloadException
exception in UserNameUniqueValidator
returns custom message so I avoid to use BindingResult
in main controller for extraction default message from validaor
If you want to display custom message try this piece of code.
@Override public boolean isValid(String userName, ConstraintValidatorContext context) { if (userService.findByUserName(userName) != null) { context.disableDefaultConstraintViolation(); context .buildConstraintViolationWithTemplate("User " + userName + "already exists!") .addConstraintViolation(); return false; } return true; }
I had the same problem (need to get just exception to handle it in exceptionMapper). so, You can extend your custom exception from 'ConstraintDeclarationException':
public class BusinessValidationException extends ConstraintDeclarationException { private ValidationErrorDto validationErrorDto; public BusinessValidationException(ValidationErrorDto validationErrorDto) { super(); this.validationErrorDto = validationErrorDto; } public BusinessValidationException(ValidationErrorDto validationErrorDto, String message, Object... args) { super(String.format(message, args)); this.validationErrorDto = validationErrorDto; } ... }
below, you can see how to use it:
@Override public boolean isValid(RequestDto dto, ConstraintValidatorContext context) { ... if (some condition) { ... throw new BusinessValidationException(validationErrorDto, "Duplicate transaction T[%s]", dto.getTrace()); } return true; }
and, how to catch it in exceptionMapper:
@ExceptionHandler(BusinessValidationException.class) public ResponseDto handleBusinessValidationExceptions(BusinessValidationException ex) { logger.info(ex.getMessage()); return new ...; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With