【问题标题】:Spring Boot JSR-303/349 configurationSpring Boot JSR-303/349 配置
【发布时间】:2017-02-03 23:30:32
【问题描述】:

在我的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", "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", 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

我还在自动装配DecisionDao 的地方添加了@Lazy 注释,但现在我的测试失败,出现以下异常:

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)

【问题讨论】:

  • 关于 OverridingMethodMustNotAlterParameterConstraints 的最后一个异常,想知道将相同的 JSR 303 相关注释应用于基本接口 DecisionDao 是否可以解决该问题。也许您可以尝试仅在界面级别应用它们。
  • 我已将验证约束移至基本接口,但随后验证停止工作,没有任何异常
  • 如果你在接口和实现中都应用相同的注释呢?
  • 我终于让它工作了。我有一组重载的创建方法,所以我在基本接口上对所有这些方法应用了验证约束。现在,一切正常。

标签: java spring spring-boot bean-validation jsr


【解决方案1】:

将验证移至界面,如下:

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

@Validated注释你的DecisionDaoImpl,如下:

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

}

修改您的测试用例以使用assertjExpectedException 验证javax.validation.ConstraintViolationException,如下所示:

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

【讨论】:

  • 是的,我有 - hibernate-validator 5.2.4.Final。不工作
  • 感谢您的回答。我已将@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.
  • 希望对您有所帮助 - stackoverflow.com/questions/28985144/…
  • 谢谢。我在自动装配 DecisionDao 的地方添加了 @Lazy 注释,但现在我的测试因另一个异常而失败。有关详细信息,请参阅我更新的问题。
  • 非常感谢。最后我让它工作了。我有一组重载的创建方法,所以我在基本接口上对所有这些方法应用了验证约束。现在,一切正常。
【解决方案2】:

你需要@Valid注解

标记验证级联的属性、方法参数或方法返回类型。 在对象及其属性上定义的约束条件在 验证属性、方法参数或方法返回类型。

【讨论】:

  • 我已经在我的方法参数中添加了@Valid 注释,但它仍然不起作用。我已经用这个更新了我的问题。
  • 能否在方法末尾添加 , BindingResult 结果参数并检查方法中的 result.hasErrors() ?看起来您期望异常,但它不会抛出异常但会提供一些错误。
  • 方法调用时应该提供什么BindingResult实现?例如,我没有调用 Spring MVC 中的方法。
【解决方案3】:

约束注解旨在应用于 JavaBeans。见http://beanvalidation.org/1.0/spec/#constraintsdefinitionimplementation-constraintdefinition

您在 DAO 中应用了约束注释 @NotNull@Size 等。您必须创建一个 Java Bean,例如“Person”,包装了这些属性(名称、描述等),然后将“Person”作为参数传递给 Controller 方法。如果您需要使用 DAO 而不是控制器,则需要对其进行检测以执行验证。在 AOP 等方面,你可能需要靠自己,除非这篇文章之后发生了一些变化: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 的示例,类似于 Arpit 的答案。 更新了问题的标题以反映最新的 JSR。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-15
    • 2013-11-23
    • 2013-12-27
    • 1970-01-01
    • 2011-07-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多