代码之家  ›  专栏  ›  技术社区  ›  Sebastian S.

Quarkus Live重新加载后Vaadin Bean验证不起作用

  •  0
  • Sebastian S.  · 技术社区  · 1 年前

    我在玩Quarkus 3.6.3和Vaadin 24.3.0。我的问题是,当quarkus应用程序在开发模式下实时重新加载时,由于任何类文件的更改,强制字段的必需指示符不再显示。

    Java类

    我有一个显示一些文本字段的视图,我使用 BeanValidationBinder 将字段绑定到JPA实体类的实例 User 。这个类很简单,看起来是这样的:

    @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    public class User {
    
        @NotNull
        @Column
        private String firstName;
    
        @NotNull
        @Column
        private String lastName;
    
        // Getters and Setters
    }
    

    为了简单起见,视图类如下所示:

    @Route(value = "user", layout = MainLayout.class)
    public class UserFormView extends VerticalLayout {
    
        private final TextField firstName = new TextField("First name");
    
        private final TextField lastName = new TextField("Last name");
    
        private final Binder<User> binder = new BeanValidationBinder<>(User.class);
    
        public UserFormView() {
    
            binder.forField(firstName).withNullRepresentation("").bind("firstName");
            binder.forField(lastName).withNullRepresentation("").bind("lastName");
            binder.readBean(new User());
    
            add(firstName, lastName);
        }
    }
    

    这个问题

    实时重新加载变量后 propertyDescriptor 在方法中 BeanValidationBinder#configureRequired null 因此,域类的bean验证注释不被处理用于设置所需的指示符和用于绑定器的验证。

    现在,我想知道在实时重新加载后,所需的指示器是否也应该正确显示。

    调试

    通过调试,我发现:

    • 在最初启动应用程序时,的实例 PredefinedScopeBeanMetaDataManager 创建并保存类的beanMetaDataMap,该类具有作为实例的bean验证注释 BeanMetaDataImpl 。此实例保存在的实例中 CloseAsNoopValidatorFactoryWrapper 在常数内 LazyFactoryInitializer#FACTORY .
    • 在实时重新加载后,此实例的beanMetaDataMap被清除,并且的新实例 预定义的ScopeBeanMetaDataManager 它再次保存了带有bean验证注释的类映射。但是这个新实例不用于进一步查找,而是 老的 使用具有空映射的实例,因为它保持在上面描述的常量中。
    0 回复  |  直到 1 年前
        1
  •  1
  •   Guillaume Smet    1 年前

    谢谢你的侦探工作。这肯定是个错误。

    据我所见,在夸克中我们没什么可做的。Vaadin Flow应避免存储 ValidatorFactory 在静态场中 LazyFactoryInitializer#FACTORY 。或者至少在应用程序停止时清理一下,然后创建一个新的应用程序。当前的代码会导致类加载器泄漏,任何服务器都会重新加载应用程序。

    以下是Ivan Kaliuzhnyi在流量跟踪器中的评论 https://github.com/vaadin/flow/issues/4481#issuecomment-1712720926 ,即使它一点都不漂亮,你也应该能够解决它。

    粘贴评论以保留历史:

    @Configuration
    public class ValidatorConfig implements InitializingBean {
    
        @Autowired
        private ValidatorFactory validatorFactory;
    
        @Bean
        public ValidatorFactory validatorFactory(MessageSource messageSource) {
            var bean = new LocalValidatorFactoryBean();
            bean.setValidationMessageSource(messageSource);
            return bean;
        }
    
        @Bean
        public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(ValidatorFactory validatorFactory) {
            // AvailableSettings.JPA_VALIDATION_FACTORY -> javax.persistence.validation.factory
            // AvailableSettings.JAKARTA_VALIDATION_FACTORY -> jakarta.persistence.validation.factory
            return hibernateProperties ->
                hibernateProperties.put(AvailableSettings.JAKARTA_VALIDATION_FACTORY, validatorFactory);
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
    
            var className = "com.vaadin.flow.data.validator.BeanValidator.LazyFactoryInitializer";
            var fieldName = "FACTORY";
            var field = FieldUtils.getDeclaredField(ClassUtils.getClass(className), fieldName, true);
    
            var unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
            unsafeField.setAccessible(true);
            var unsafe = (Unsafe) unsafeField.get(null);
    
            unsafe.putObject(unsafe.staticFieldBase(field),
                    unsafe.staticFieldOffset(field),
                    validatorFactory);
    
        }
    }
    
    推荐文章