问题
I'm trying to implement a custom validator for my model classes that autowires a custom bean of mine (declared via @Component
).
In this, I followed the Spring documentation on that topic. My AuthenticationFacade
object is implemented according to this tutorial.
When running my tests, however, the autowired attribute in the Validator
object is always null
. Why is that?
Here are the relevant parts of my code:
My custom bean, AuthenticationFacadeImpl.java
@Component
public class AuthenticationFacadeImpl implements AuthenticationFacade {
boolean hasAnyRole(Collection<String> roles) {
// checks currently logged in user roles
}
}
My custom constraint, HasAnyRoleConstraint.java
@Constraint(validatedBy = HasAnyRoleConstraintValidator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface HasAnyRole {
String[] value();
String message() default "{HasAnyRole}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
My custom validator, HasAnyRoleConstraintValidator.java
@Component
public class HasAnyRoleConstraintValidator implements ConstraintValidator<HasAnyRole, Object> {
@Autowired
AuthenticationFacade authenticationFacade;
private String[] roles;
@Override
public void initialize(HasAnyRole hasAnyRole) {
this.roles = hasAnyRole.value();
}
@Override
public boolean isValid(Object target, ConstraintValidatorContext constraintValidatorContext) {
return target == null || authenticationFacade.hasAnyRole(Arrays.asList(this.roles));
}
}
The model class, Article.java
@Entity
public class Article {
// ...
@HasAnyRole({"EDITOR", "ADMIN"})
private String title;
// ...
}
The service object, ArticleServiceImpl.java
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleRepository articleRepository;
@Autowired
private AuthenticationFacade authenticationFacade;
@Autowired
private Validator validator;
@Override
@PreAuthorize("hasAnyRole('ADMIN', 'EDITOR')")
public boolean createArticle(Article article, Errors errors) {
articleRepository.save(article);
return true;
}
The Errors
object that gets fed into the createArticle
method is intended to come from the Spring controller, which gets fed a model object with the @Valid
annotation.
The repository, ArticleRepository.java
, uses Spring Data JPA's JpaRepository
public interface ArticleRepository extends JpaRepository<Article, Long> {
}
回答1:
I solved this for now by ditching Dependency Injection for the Validator class, instead instantiating an instance of AuthenticationFacadeImpl
in the constructor.
Would still be interesting, though how to combine the use of @Valid
in the Controllers with custom validators + @Autowired
attributes in the Model without explicitely calling the Validator in the code...
回答2:
If your validator is instantiated outside the Spring context, then you can use Spring’s AOP @Configurable magic to register it in context and get autowiring work. All what you need is to annotate HasAnyRoleConstraintValidator
with @Configurable
and enable compile time, or load time aspects weaving.
来源:https://stackoverflow.com/questions/19592779/using-autowired-component-in-custom-jsr-303-validator