【问题标题】:@Value field is showing null when second time the class method is called第二次调用类方法时,@Value 字段显示为空
【发布时间】:2019-11-16 12:44:49
【问题描述】:

在我的自定义注释中,我使用了允许邮件发送的域

@Documented
@Constraint(validatedBy = ValidEmail.CheckIfValidMail.class)
//@Constraint(validatedBy = {})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
//@Repeatable(List.class)
@Retention(RUNTIME)
@Component
public @interface ValidEmail {

    String message() default "Invalid String !!";

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

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

    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Documented
    @interface List {

        ValidEmail[] value();
    }

    @Component
    public class CheckIfValidMail implements ConstraintValidator<ValidEmail, String> {

        @Autowired
        UserServiceImplOld userServiceImpl;

//      @Value("${app.mail.allowedDomains:gmail}")
        private String[] allowedDomainsForMail;

        @Value("${app.mail.allowedDomains:gmail}")
        public void setAllowedDomainsForMail(String[] allowedDomainsForMail) {
            this.allowedDomainsForMail = allowedDomainsForMail;
        }

//      private String[] allowedDomainsForMail = new String[] { "gmail", "rediffmail", "yahoo" };

        protected String message;

        @Override
        public void initialize(ValidEmail validEmail) {
            this.message = validEmail.message() + "  Allowed Domain(s): " + Arrays.toString(allowedDomainsForMail);
        }

        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            if (value == null)
                return true;
            String allowedDomainRegEx = String.join("|", allowedDomainsForMail);
            String mailRegex = "^(?i)[A-Za-z0-9+_.-]+@(?:" + allowedDomainRegEx + ")\\.(?:.*)$";
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
            return value.matches(emailRegex);
        }

    }
}

如果我从 rest API 调用它,每次值都在那里,但是 如果我从代码中显式调用验证,我可以在调试中看到 allowedMailDomains 值为 null

但是,如果我不从属性文件和硬编码中获取,它在这样的时间里都可以工作

Dto 对象

@Data //lombok
public class UserDto{
    @ValidEmail(message = "Wrong emailId format !!")
    private String emailId;

    @NotNull
    private Boolean isLoginAllowed;

}

实施中

UserDto addUserDto = new UserDto();
addUserDto.setEmailId("satish");
addUserDto.setisLoginAllowed(false);
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
System.out.println("Validating :-\n" + validator.validate(addUserDto));

因此,在验证时转到 ValidMail 接口,并且 allowedMailDomains 值为 null

【问题讨论】:

  • 当你得到null时请分享代码?
  • @dassum 添加了代码,在创建 dto 的对象时,有 ValidEmail 注释

标签: java spring-boot spring-properties


【解决方案1】:

尝试注册LocalValidatorFactoryBean 并使用它来代替Validation.buildDefaultValidatorFactory()。 LocalValidatorFactoryBean 应该允许您在验证器中获得依赖注入的好处。

更新:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#validation-beanvalidation-spring-constraints

默认情况下,LocalValidatorFactoryBean 配置一个 SpringConstraintValidatorFactory,它使用 Spring 创建 ConstraintValidator 实例。这让您的自定义 ConstraintValidators 可以像任何其他 Spring bean 一样从依赖注入中受益。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

@Configuration
public class ValidatorConfiguration {
    @Bean
    public ValidatorFactory localValidatorFactoryBean() {
        return new LocalValidatorFactoryBean();
    }
}

然后在你的实现类中自动装配这个 bean:

@Autowired
private ValidatorFactory validatorFactory;

并用它代替DefaultValidatorFactory:

Validator validator = validatorFactory.getValidator();
validator.validate(addUserDto);

【讨论】:

    【解决方案2】:

    要注入属性 allowedMailDomains,您的类 CheckIfValidMail 必须是 bean。因此,如果您将 @Component 注释(例如)添加到您的类中,问题将得到解决。

    【讨论】:

    • @Component 到接口注释?从我调用它的地方开始,它已经有了组件和服务,但是在 ValidMail 接口中,我仍然得到 null
    • 我用@Component注解把它交给了接口内部的类,仍然为空
    • 类(实现)应该是一个bean。事实上,你需要注入它的属性。如果不是 bean,Spring Container 如何注入值?
    • CheckIfValidMail 是一个内部类?我不明白它是如何在接口内部的?请解释一下。
    • @zouari 编辑你的答案,这样我就可以删除我的反对票,你是对的,我会在我的答案中解释它。
    【解决方案3】:

    那么问题来了:

      1234563它需要。
    • 当您以编程方式初始化它时,它不会被初始化为 Component,也没有 Container 来获取 @Value,我什至怀疑 Properties 是否已加载在第二种情况下(我看不到整个代码,所以我不确定)。

    如果没有完整的上下文,这是我头顶的解决方案:

    在验证器中这样做:

    private String[] allowedMailDomains;
    
    @Value("${poss.mail.allowedDomains:gmail}")
    public void setAllowedMailDomains(String[] allowedMailDomains) {
        this.allowedMailDomains = allowedMailDomains;
    }
    

    然后在您的程序验证中设置该值,然后应该可以工作。

    否则,只需在容器中初始化它即可修复它。

    【讨论】:

    • 添加了完整代码。在 setter 中尝试了 @Value。仍然为空。如何分配容器?有什么有用的链接吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-05
    • 1970-01-01
    • 2017-08-10
    相关资源
    最近更新 更多