有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用RESTeasy 3验证程序实现Spring 4依赖项注入

为了成功利用Spring的依赖注入,我在尝试获取自定义Bean验证约束时遇到了很多麻烦

例如,我可以定义一个约束:

@Constraint(validatedBy = { CustomConstraintValidator.class })
@Documented
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomConstraint {
    String message() default "custom.constraint.error";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

验证程序实现

@Component
public class CustomConstraint implements ConstraintValidator<CustomConstraint, String> {

    @Autowired
    private SomeSpringBean someSpringBean;

    @Override
    public void initialize(CustomConstraint constraintAnnotation) {
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {

        if (value != null) {
            SomeObject storedValue = someSpringBean.find(value);

                    return storedValue != null;
        }

        return true;
    }

}

使用RESTeasy设置Bean验证的标准方法是: 组织。jboss。resteasy:resteasy-validator-provider-11:3.0.6。决赛

但是,在运行时执行验证时,任何@Autowired字段都始终为空

版本
春季:4.0.4。释放
RESTeasy:3.0.6。决赛


共 (1) 个答案

  1. # 1 楼答案

    我已经找到了一个解决方案,它还不理想,但它确实有效,并可能演变成一个合适的解决方案

    在阅读了许多StackOverflow问题和各种web文章后,我几乎找不到任何关于让Spring和Resteasy使用验证的参考资料。关于Spring和Bean验证的参考文献很多,但一旦引入Resteasy,讨论就消失了。从其他讨论中可以清楚地看到,Spring提供了一个名为LocalValidatorFactoryBean的验证器工厂实现,它将在验证器实现中启用Spring依赖项注入

    调查组织。jboss。resteasy:resteasy-validator-provider-11:3.0.6。最后,我发现它主要是设置一个@Provider实例,提供Resteasy用来解析Bean验证的GeneralValidator。我注意到的问题是,提供程序类ValidatorContextResolver实际上没有提供任何方法来设置不同版本的ValidatorFactory。它尝试通过CDI/JNDI加载,如果失败,则默认为硬编码的验证器工厂实现。在我的例子中,我不能依赖JNDI查找,因此无法提供Spring的LocalValidatoryFactoryBean作为工厂

    另一方面,resteasy-validator-provider-11是一个非常小的库,需要更改以使用Spring的LocalValidatoryBean的代码非常少。您可以删除resteasy-validator-provider-11依赖项,并重新实现库以使用Spring。我将在下面展示相关代码,这些代码将使这项工作正常进行,而不包括我没有更改的resteasy-validator-provider-11库中的类

    验证上下文解析器
    您需要获取Spring引导的LocalValidatoryFactoryBean的副本,您不能在这里用new来实例化它:

    @Component
    @Provider
    public class ValidatorContextResolver implements ContextResolver<GeneralValidator> {
        private final static Logger log = Logger.getLogger(ValidatorContextResolver.class);
        private volatile ValidatorFactory validatorFactory;
        final static Object RD_LOCK = new Object();
    
        @Autowired
        private ValidatorFactory springValidatorFactoryBean;
    
        // this used to be initialized in a static block, but I was having trouble class loading the context resolver in some
        // environments. So instead of failing and logging a warning when the resolver is instantiated at deploy time
        // we log any validation warning when trying to obtain the ValidatorFactory.
        ValidatorFactory getValidatorFactory() {
            ValidatorFactory tmpValidatorFactory = validatorFactory;
            if (tmpValidatorFactory == null) {
                synchronized (RD_LOCK) {
                    tmpValidatorFactory = validatorFactory;
                    if (tmpValidatorFactory == null) {
                        log.info("Obtaining Spring-bean enabled validator factory");
                        validatorFactory = tmpValidatorFactory = springValidatorFactoryBean;
                    }
                }
            }
            return validatorFactory;
        }
    
        @Override
        public GeneralValidator getContext(Class<?> type) {
            try {
                Configuration<?> config = Validation.byDefaultProvider().configure();
                BootstrapConfiguration bootstrapConfiguration = config.getBootstrapConfiguration();
                boolean isExecutableValidationEnabled = bootstrapConfiguration.isExecutableValidationEnabled();
                Set<ExecutableType> defaultValidatedExecutableTypes = bootstrapConfiguration.getDefaultValidatedExecutableTypes();
                return new GeneralValidatorImpl(getValidatorFactory(), isExecutableValidationEnabled, defaultValidatedExecutableTypes);
            } catch (Exception e) {
                throw new ValidationException("Unable to load Validation support", e);
            }
        }
    }
    

    SpringValidationConfig
    在春季设置LocalValidatoryFactoryBean。你可以想怎么做就怎么做,我更喜欢用编程的方式

    @Configuration
    public class DatabaseConfig
    {
        @Bean
        public ValidatorFactory validator() {
            LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
           // localValidatorFactoryBean.setValidationMessageSource(getValidationMessageSource());
            return localValidatorFactoryBean;
        }
    }
    

    最后配置Spring来加载这两个类。我在Spring配置中通过组件扫描来实现,比如:

    <context:component-scan base-package="org.example.resteasy.spring.validation.config" />
    

    按照这些步骤,我能够让@Autowired依赖项注入在我的自定义验证约束实现中工作,如问题中所述

    理想的前进道路是有一个备用的resteasy-validator-provider-11与Spring一起工作