【问题标题】:How to avoid cross dependency between layers because of @Constraint validatedBy?由于@ConstraintvalidateBy,如何避免层之间的交叉依赖?
【发布时间】:2012-07-30 11:35:30
【问题描述】:

在我们的项目中,我们在不同的 Maven 模块中有服务和 DAO 层。服务模块依赖于 DAO 模块并与它的实体一起工作。问题是我们不能在 DAO 实体中放置使用来自服务层的一些服务的自定义 jsr 303 约束,因为这会创建从 DAO 层到服务层的反向引用,因为验证器类需要在自定义的 validBy 属性中引用@约束。

有没有办法(使用标准 jsr 303 api)在运行时指定一些自定义约束的验证器类(或以任何其他方式解决我们的问题)?内置约束有空的validateBy属性,但我不知道是否有一些API。

【问题讨论】:

    标签: java maven bean-validation


    【解决方案1】:

    我们在基于 Spring 的项目中遇到了同样的问题。为了以最好的 Spring 方式解决它,我们拆分了 ConstraintValidator 接口和实现。例如在领域层我们只有接口:

    public interface UniqueValidator extends ConstraintValidator<Unique, String> {
    }
    

    在服务层我们实现了这个接口:

    public class UniqueValidatorJpaImpl implements UniqueValidator {
        private EntityManager entityManager;
        ...
    }
    

    接下来我们在 Spring Context 中为 UniqueValidatorJpaImpl 声明一个 bean。

    最后,为了让所有员工都能正常工作,我们扩展了 SpringConstraintValidatorFactory。默认情况下,它只创建在validateBy中指定的类的新实例。我们通过首先在 spring 上下文中查找相应类型的 bean 来扩展它:

    public class SpringConstraintValidatorFactoryEx implements ConstraintValidatorFactory {
    
        private final Logger logger = LoggerFactory.getLogger(SpringConstraintValidatorFactoryEx.class);
    
        @Autowired
        private AutowireCapableBeanFactory beanFactory;
    
        public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
            T bean = null;
    
            try {
                logger.info("Trying to find a validator bean of class " + key.getSimpleName());
                bean = this.beanFactory.getBean(key);
            } catch (BeansException exc) {
                logger.info("Failed to find a bean of class " + key.getSimpleName());
            }
    
            if (bean == null) {
                try {
                    logger.info("Creating a new validator bean of class " + key.getSimpleName());
                    bean = this.beanFactory.createBean(key);
                } catch (BeansException exc) {
                    logger.info("Failed to create a validator of class " + key.getSimpleName());
                }
            }
    
            if (bean == null) {
                logger.warn("Failed to get validator of class " + key.getSimpleName());
            }
    
            return bean;
        }
    
    }
    

    【讨论】:

    • Pure Java EE 项目在这里(没有 Spring),类似的解决方案可以工作。只是稍微简单一些:你只需要实现一个带有验证方法的接口(不需要扩展任何东西),在服务层实现它,然后直接将它注入到领域层的验证器中。
    • Pure Java EE 项目在这里(没有 Spring),类似的解决方案可以工作。只是稍微简单一些:你只需要实现一个带有验证方法的接口(不需要扩展任何东西),在服务层实现它,然后直接将它注入到领域层的验证器中。
    • @Aliaksei 你能详细说明一下bean配置吗?我仍然让它工作。我添加了一个配置@Bean public UniqueUsernameValidator uniqueUsernameValidator() {return new UniqueUsernameValidatorImpl();} 和@Bean public ConstraintValidatorFactory constraintValidatorFactory() {return new SpringConstraintValidatorFactoryEx();} 但它仍然不起作用或者我误解了一些东西。
    【解决方案2】:

    您可以使用XML based constraint mapping 为您的约束分配一个验证器,以避免从注释引用到验证器实现。

    BV 1.1 EG 也是discussing 在该领域的一些改进。请随时在mailing list 上就该问题发表意见。

    【讨论】:

    • 在使用 Hibernate Validator 时,您还可以使用服务加载器机制来find constraint validators,避免从约束注释类型到其验证器的任何链接。
    猜你喜欢
    • 1970-01-01
    • 2020-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-12
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多