web-dev-qa-db-fra.com

Configuration Spring Boot JSR-303/349

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)
7
alexanoid

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

2
Arpit

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.

1
user2066936

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é.

1
StanislavL