Dans mon application Spring Boot 1.5.1
, j'essaie de configurer la prise en charge de la validation JSR-303/JSR-349.
J'ai ajouté les annotations suivantes @NotNull @Size(min = 1)
à ma méthode:
@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) {
...
}
}
J'essaie d'invoquer cette méthode à partir de mon test, mais cela n'échoue pas sur les contraintes de validation.
Ceci est mon test et configs:
@SpringBootTest(classes = { TestConfig.class, Neo4jTestConfig.class })
@RunWith(SpringRunner.class)
@Transactional
public class TenantTest {
@Test
public void testCreateDecision() {
User user1 = userService.createUser("test1", "test1", "[email protected]", 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", null, tenant1, user1);
...
@Configuration
@ComponentScan("com.example")
@SpringBootApplication(exclude={Neo4jDataAutoConfiguration.class})
public class TestConfig {
}
Qu'est-ce que je fais de travers et comment configurer le JSR-303?
MIS À JOUR
J'ai ajouté
public Decision create(@Valid @NotNull @Size(min = 1) String name, String description, Decision parentDecision, Tenant tenant, User author) {
mais ça ne marche toujours pas
J'ai ajouté @Validated
à ma DecisionDaoImpl
mais cela échoue maintenant avec une exception suivante:
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
J'ai également ajouté l'annotation @Lazy
dans des endroits où je transfère automatiquement ma DecisionDao
mais pour l'instant, mon test échoue avec une exception suivante:
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.String,Java.lang.String,Java.lang.Long,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,Java.lang.String,Java.lang.String,Java.lang.String,Java.lang.Long,Java.lang.Long,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)
Déplacez votre validation vers l'interface, comme suit:
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 description, String url, String imageUrl);
}
Annotez votre DecisionDaoImpl
avec @Validated
, comme suit:
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 description, String url, String imageUrl) {
System.out.println(name);
return new Decision();
}
}
Modifiez votre scénario de test pour vérifier la présence de javax.validation.ConstraintViolationException
à l'aide de assertj ou ExpectedException , comme suit:
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,
"Root decision 1 description", null, null));
}
@Test
public void testCreateDecision() {
expectedException.expect(ConstraintViolationException.class);
decisionDao.create(null, "Root decision 1 description", null, null);
}
@Configuration
public static class Config {
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
@Bean
public DecisionDao decisionDao() {
return new DecisionDaoImpl();
}
}
}
Assurez-vous que vous avez hibernate-validator dans votre chemin de classe avec la réponse @StanislavL:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
Et une dépendance optionnelle pour org.assertj.core.api.Assertions.assertThatExceptionOfType
, comme:
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.3.0</version>
<scope>test</scope>
</dependency>
Pour un exemple, vous pouvez vous référer arpitaggarwal/jsr-303
Les annotations de contrainte sont destinées à être appliquées à JavaBeans. Voir http://beanvalidation.org/1.0/spec/#constraintsdefinitionimplementation-constraintdefinition
Les annotations de contrainte @NotNull
, @Size
, etc. sont appliquées dans DAO. Vous devez créer un Java Bean, par exemple. "Personne", qui encapsule ces attributs (nom, description, etc.), puis passe "Personne" en tant que paramètre à la méthode Controller. Si vous devez utiliser un DAO au lieu d'un contrôleur, il devra être instrumenté pour effectuer la validation. Vous pouvez être autonome à cet égard en ce qui concerne AOP, etc., sauf si quelque chose a changé depuis ce poste: http://forum.spring.io/forum/spring-projects/container/82643-annotation-driven -jsr-303-validation-on-service-and-dao-tier
Update : Eh bien, on dirait que ça (la validation au niveau de la méthode JSR-349) est supportée maintenant voir http://blog.codeleak.pl/2012/03/how-to-meto--lehod-validation -in.html pour un exemple, similaire à la réponse d'Arpit. Le titre de la question a été mis à jour pour refléter cette dernière RSC.
Vous avez besoin d'une annotation @Valid
Marque une propriété, un paramètre de méthode ou un type de retour de méthode pour la validation en cascade. Les contraintes définies sur l'objet et ses propriétés sont validées lorsque le type de retour de la propriété, du paramètre ou de la méthode Est validé.