Java – spring boot jsr-303 / 349 configuration
In my spring boot 1.5 In the application, I am trying to configure support for JSR - 303 / JSR - 349 authentication
I added the following comment @ notnull @ size (min = 1) to my method:
@Service @Transactional public class DecisionDaoImpl extends BaseDao implements DecisionDao { @Override public Decision create(@NotNull @Size(min = 1) String name,String description,String url,String imageUrl,Decision parentDecision,Tenant tenant,User user) { ... } }
I tried calling this method from my test, but it would not fail on the validation constraint.
This is my test and configuration:
@SpringBootTest(classes = { TestConfig.class,Neo4jTestConfig.class }) @RunWith(SpringRunner.class) @Transactional public class TenantTest { @Test public void testCreateDecision() { User user1 = userService.createUser("test1","test1","test1@test.com",null,null); Tenant tenant1 = tenantDao.create("Tenant 1","Tenant 1 description",false,user1); // the following line should fail on the validation constraint because name parameter is null but it doesn't final Decision rootDecision = decisionDao.create(null,"Root decision 1 description",tenant1,user1); ... @Configuration @ComponentScan("com.example") @SpringBootApplication(exclude={Neo4jDataAutoConfiguration.class}) public class TestConfig { }
What did I do wrong and how did I configure jsr-303 there?
to update
I've added
public Decision create(@Valid @NotNull @Size(min = 1) String name,User author) {
But it still doesn't work
I added @ validated to my decisiondaoimpl, but it now fails with the following exception:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'decisionDaoImpl': Bean with name 'decisionDaoImpl' has been injected into other beans [criterionGroupDaoImpl,characteristicGroupDaoImpl,tenantDaoImpl] in its raw version as part of a circular reference,but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off,for example. at org.springframework.beans.factory.support.AbstractAutowireCapablebeanfactory.doCreateBean(AbstractAutowireCapablebeanfactory.java:585) at org.springframework.beans.factory.support.AbstractAutowireCapablebeanfactory.createBean(AbstractAutowireCapablebeanfactory.java:483) at org.springframework.beans.factory.support.Abstractbeanfactory$1.getObject(Abstractbeanfactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.Abstractbeanfactory.doGetBean(Abstractbeanfactory.java:302) at org.springframework.beans.factory.support.Abstractbeanfactory.getBean(Abstractbeanfactory.java:202) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) at org.springframework.beans.factory.support.DefaultListablebeanfactory.doResolveDependency(DefaultListablebeanfactory.java:1138) at org.springframework.beans.factory.support.DefaultListablebeanfactory.resolveDependency(DefaultListablebeanfactory.java:1066) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 43 common frames omitted
I also added @ lazy annotation where I automatically assemble decisiondao, but now my test fails with the following exception:
javax.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not alter the parameter constraint configuration,but method public com.example.domain.model.entity.decision.Decision com.example.domain.dao.decision.DecisionDaoImpl.create(java.lang.String,java.lang.String,java.lang.Long,com.example.domain.model.entity.user.User) changes the configuration of public abstract com.example.domain.model.entity.decision.Decision com.example.domain.dao.decision.DecisionDao.create(java.lang.String,com.example.domain.model.entity.user.User). at org.hibernate.validator.internal.Metadata.aggregated.rule.OverridingMethodMustNotAlterParameterConstraints.apply(OverridingMethodMustNotAlterParameterConstraints.java:24) at org.hibernate.validator.internal.Metadata.aggregated.ExecutableMetaData$Builder.assertCorrectnessOfConfiguration(ExecutableMetaData.java:456)
Solution
Move the verification to the interface as follows:
import javax.validation.Valid; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; public interface DecisionDao { Decision create(@Valid @NotNull @Size(min = 1) String name,String imageUrl); }
Annotate decisiondaoimpl with @ validated as follows:
import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @Service @Validated public class DecisionDaoImpl extends BaseDao implements DecisionDao { @Override public Decision create(String name,String imageUrl) { System.out.println(name); return new Decision(); } }
Modify the test case with assertj or expectedexception to validate javax validation. Constraintviolationexception, as follows:
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import javax.validation.ConstraintViolationException; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; @ContextConfiguration(classes = { TenantTest.Config.class }) @RunWith(SpringRunner.class) public class TenantTest { @Autowired private DecisionDao decisionDao; @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void testCreateDecisionUsingAssertj() { assertThatExceptionOfType(ConstraintViolationException.class) .isThrownBy( () -> decisionDao.create(null,null)); } @Test public void testCreateDecision() { expectedException.expect(ConstraintViolationException.class); decisionDao.create(null,null); } @Configuration public static class Config { @Bean public MethodValidationPostProcessor methodValidationPostProcessor() { return new MethodValidationPostProcessor(); } @Bean public DecisionDao decisionDao() { return new DecisionDaoImpl(); } } }
Make sure there are hibernate validator and @ stanislavl answers in your classpath:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> </dependency>
And org assertj. core. api. Assertions. Optional dependencies of assertthatexceptionoftype, such as:
<dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.3.0</version> <scope>test</scope> </dependency>
For examples, you can refer to arpitaggarwal / jsr-303