Конфигурация Spring Boot JSR-303/349

В моем Spring Boot 1.5.1 приложении я пытаюсь настроить поддержку проверки JSR-303 / JSR-349.

Я добавил к своему методу следующие аннотации @NotNull @Size(min = 1):

@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) {
        ...
    }

}

Я пытаюсь вызвать этот метод из своего теста, но он не дает сбоев при проверке ограничений.

Это мой тест и конфиги:

@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 {
}

Что я делаю не так и как там настроить JSR-303?

ОБНОВЛЕНО

я добавил

public Decision create(@Valid @NotNull @Size(min = 1) String name, String description, Decision parentDecision, Tenant tenant, User author) {

но это все еще не работает

Я добавил @Validated в свой DecisionDaoImpl, но теперь он не работает за следующим исключением:

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

Я также добавил аннотацию @Lazy в места, где я автоматически подключаю свой DecisionDao, но сейчас мой тест не проходит со следующим исключением:

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)

person alexanoid    schedule 02.02.2017    source источник
comment
Что касается последнего исключения с OverridingMethodMustNotAlterParameterConstraints, интересно, решит ли это применение тех же аннотаций, связанных с JSR 303, к базовому интерфейсу DecisionDao. Возможно, вы могли бы попробовать применить их только на уровне интерфейса.   -  person    schedule 03.02.2017
comment
Я переместил ограничения проверки в базовый интерфейс, но затем проверка перестала работать, как раньше, без каких-либо исключений.   -  person alexanoid    schedule 03.02.2017
comment
А если применить одни и те же аннотации точно и в интерфейсе, и в имп?   -  person    schedule 03.02.2017
comment
Наконец-то у меня все заработало. У меня есть набор перегруженных методов создания, поэтому я применил ограничения проверки ко всем из них в базовом интерфейсе. Теперь все работает нормально.   -  person alexanoid    schedule 03.02.2017


Ответы (3)


Перенесите валидацию в интерфейс, как показано ниже:

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);
}

Добавьте аннотацию к своему DecisionDaoImpl с помощью @Validated < / a> следующим образом:

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();
    }

}

Измените свой тестовый пример, чтобы проверить javax.validation.ConstraintViolationException, используя assertj или ExpectedException следующим образом:

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();
        }
    }
}

Убедитесь, что у вас есть hibernate-validator в пути к классам вместе с ответом @StanislavL:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>

И необязательная зависимость для org.assertj.core.api.Assertions.assertThatExceptionOfType, например:

<dependency>
     <groupId>org.assertj</groupId>
     <artifactId>assertj-core</artifactId>
     <version>3.3.0</version>
     <scope>test</scope>
</dependency>

В качестве примера вы можете обратиться к arpitaggarwal / jsr-303.

person Arpit Aggarwal    schedule 02.02.2017
comment
Да, есть - hibernate-validator 5.2.4.Final. Не работает - person alexanoid; 02.02.2017
comment
спасибо за Ваш ответ. Я добавил @Validated в свой 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. - person alexanoid; 03.02.2017
comment
Надеюсь, это поможет вам - stackoverflow.com/questions/28985144/ - person Arpit Aggarwal; 03.02.2017
comment
Спасибо. Я добавил аннотацию @Lazy в места, где я автоматически подключаю свой DecisionDao, но сейчас мой тест не проходит с другим исключением. См. Мой обновленный вопрос для получения более подробной информации. - person alexanoid; 03.02.2017
comment
Вы должны упомянуть, что ожидаете исключения при запуске @Test, как я сделал в моем примере @Test - expectedException.expect(ConstraintDeclarationException.class); - person Arpit Aggarwal; 03.02.2017
comment
Да, но это также не удается с тем же исключением, если параметр имени не является нулем или пустым - person alexanoid; 03.02.2017
comment
Большое Вам спасибо. Наконец-то у меня все заработало. У меня есть набор перегруженных методов создания, поэтому я применил ограничения проверки ко всем из них в базовом интерфейсе. Теперь все работает нормально. - person alexanoid; 03.02.2017
comment
Я также переместил аннотацию Validated в базовый интерфейс. Это нормально ? - person alexanoid; 03.02.2017

Вам нужна @Valid аннотация

Помечает свойство, параметр метода или возвращаемый тип метода для каскадной проверки. Ограничения, определенные для объекта и его свойств, проверяются при проверке свойства, параметра метода или типа возвращаемого значения метода.

person StanislavL    schedule 02.02.2017
comment
Я добавил аннотацию @Valid к параметру моего метода, но она по-прежнему не работает. Я обновил свой вопрос этим. - person alexanoid; 02.02.2017
comment
Не могли бы вы добавить параметр результата BindingResult в конец метода и проверить result.hasErrors () в методе? Похоже, вы ожидаете исключения, но оно не вызывает исключение, но выдает некоторые ошибки. - person StanislavL; 02.02.2017
comment
Какая реализация BindingResult должна быть предоставлена ​​во время вызова метода? Я, например, не вызываю метод из Spring MVC. - person alexanoid; 02.02.2017

Аннотации ограничений предназначены для применения к JavaBeans. См. http://beanvalidation.org/1.0/spec/#constraintsdefinitionimplementation-constraintdefinition

У вас есть аннотация ограничения @NotNull, @Size и т. Д., Примененная в DAO. Вы должны создать Java Bean, например. «Человек», который обертывает эти атрибуты (имя, описание и т. Д.), Затем передает «Человек» в качестве параметра методу контроллера. Если вам нужно использовать DAO вместо контроллера, его необходимо оснастить инструментарием для выполнения проверки. Вы можете быть сами по себе в отношении АОП и т.д., если что-то не изменилось после этого сообщения: http://forum.spring.io/forum/spring-projects/container/82643-annotation-driven-jsr-303-validation-on-service-and-dao-tier

Обновление: похоже, это (проверка на уровне метода JSR-349) теперь поддерживается, см. http://blog.codeleak.pl/2012/03/how-to-method-level-validation-in.html в качестве примера. , аналогично ответу Арпита. Обновлен заголовок вопроса, чтобы отразить этот последний JSR.

person Community    schedule 03.02.2017