I have created a validator component in spring boot and I am keeping a regex expression in the application.properties
. I have used @Value
annotation to get the value of regex in my component and I am compiling the Pattern outside any method or constructor and that is giving me null pointer exception as the regex is not getting it's value at that time. But when I move the pattern to some method, it's working fine. Why is that?
Why is @Value not working even though object is created using @Component
Look at the code below:
Code returning NullPointerException:
@Component
public class ValidString implements ConstraintValidator<ValidString, String> {
@Value("${user.input.regex}")
private String USER_INPUT_REGEX;
private Pattern USER_INPUT_PATTERN = Pattern.compile(USER_INPUT_REGEX);
@Override
public boolean validate(String userInput, ConstraintValidatorContext constraintValidatorContext) {
return USER_INPUT_PATTERN.matcher(userInput).find();
}
}
Code working fine:
@Component
public class ValidString implements ConstraintValidator<ValidString, String> {
@Value("${user.input.regex}")
private String USER_INPUT_REGEX;
private Pattern USER_INPUT_PATTERN;
@Override
public boolean validate(String userInput, ConstraintValidatorContext constraintValidatorContext) {
USER_INPUT_PATTERN = Pattern.compile(USER_INPUT_REGEX);
return USER_INPUT_PATTERN.matcher(userInput).find();
}
}
Also if you could explain why the first one is not working and second one is working, that'd be great.
application.properties
user.input.regex = ^[a-zA-Z0-9/\\-_ \\s+]*$
Field initializers (first example in question) are executed during the class constructor execution. @Value
is injected by Spring after the constructor returns, using reflection. This means that you cannot have initializers using @Value
-injected values.
The issue can be resolved by constructor or setter injection:
// Inject using constructor
@Component
public class ValidString implements ConstraintValidator<ValidString, String> {
private Pattern USER_INPUT_PATTERN;
@Autowired
public ValidString(@Value("${user.input.regex}") String regex) {
this.USER_INPUT_PATTERN = Pattern.compile(regex);
}
// Inject using setter method
@Component
public class ValidString implements ConstraintValidator<ValidString, String> {
private Pattern USER_INPUT_PATTERN;
@Autowired
private void setUserInputRegex(@Value("${user.input.regex}") String regex) {
this.USER_INPUT_PATTERN = Pattern.compile(regex);
}