In Spring, when I inject a list of beans, I only want to inject specific implementations of the interface, when used from different places. Is this possible to do? What would be the cleanest way to configure this? For example, I have the following validators:
public interface Validator {
Optional<Error> validate(MultipartFile file);
}
public class Validator1 implements Validator {
public Optional<Error> validate(MultipartFile file) {
// do stuff
}
}
public class Validator2 implements Validator {
public Optional<Error> validate(MultipartFile file) {
// do stuff
}
}
public class Validator3 implements Validator {
public Optional<Error> validate(MultipartFile file) {
// do stuff
}
}
And then I have a validation service which looks similar to this:
public class ValidationService {
@Autowired
private List<Validator> validators;
public List<Error> validate(MultipartFile file) {
List<Error> errors = new ArrayList<>();
validators.forEach(v -> {
Optional<Error> error = v.validate(file);
if (error.isPresent()) {
errors.add(error.get());
}
});
return errors;
}
}
And then I have some services, which use the ValidationService, e.g:
public class Service1 {
@Autowired
private ValidationService validationService;
public void doStuff(MultipartFile file) {
...
validationService.validate(file);
...
}
}
public class Service2 {
@Autowired
private ValidationService validationService;
public void doStuff(MultipartFile file) {
...
validationService.validate(file);
...
}
}
When Service1 calls validate, I only want Validator1 and Validator2 to have been injected into the ValidatorService. When Service2 calls validate, I only want Validator2 and Validator3 to have been injected into the ValidatorService.
Hope I have explained this clearly enough. Thanks in advance for any help offered.
CodePudding user response:
Create the bean like this with @Qualifier annotations --
@Qualifier("validator1")
public class Validator1 implements Validator {
public Optional<Error> validate(MultipartFile file) {
// do stuff
}
}
@Qualifier("validator2")
public class Validator2 implements Validator {
public Optional<Error> validate(MultipartFile file) {
// do stuff
}
}
@Qualifier("validator3")
public class Validator3 implements Validator {
public Optional<Error> validate(MultipartFile file) {
// do stuff
}
}
and inject it like this ---
@Autowired("validator1")
private ValidationService validationService;
Update
You can also create a bean collection for all the validators like this -
@Bean("validators")
public List<Validator> validatorList(Validator1 validator1, Validator2 validator2, Validator3 validator3) {
return Arrays.asList(validator1, validator2, validator3);
}
and the inject the list bean as --
@Autowired("validators")
private List<Validator> validators;
Check this page fore a detailed example - https://www.baeldung.com/spring-injecting-collections
CodePudding user response:
This is likely not the best way to do this. Here is how I would do it, based on my current understanding of Spring.
Summary:
- Create a bean method for each collection of implementations.
In your case, create a bean method for a
List<Validator>
that contains Validator1 and Validator2 and create a secondList<Validator>
that contains Validator2 and Validator3. - Inject the desired List using @Qualifier.
The code should be something like this:
@Configuration
public class ValidatorLists
{
private void getAndAddBean(
final ApplicationContext applicationContext,
final List<Validator> list,
final String beanName)
{
final Validator bean;
bean = applicationContext.getBean(beanName);
if (bean != null)
{
list.add(bean);
}
}
@Bean("ValidatorList1")
public List<Validator> validatorList1(final ApplicationContext applicationContext)
{
Validator bean;
final List<Validator> returnValue = new LinkedList<>();
getAndAddBean(applicationContext, returnValue, "ValidatorImpl1");
getAndAddBean(applicationContext, returnValue, "ValidatorImpl2");
return returnValue;
}
@Bean("ValidatorList2")
public List<Validator> validatorList2(final ApplicationContext applicationContext)
{
Validator bean;
final List<Validator> returnValue = new LinkedList<>();
getAndAddBean(applicationContext, returnValue, "ValidatorImpl2");
getAndAddBean(applicationContext, returnValue, "ValidatorImpl3");
return returnValue;
}
}
Then reference the list by qualifier.
@Autowired
@Qualifier("ValidatorList1")
private List<Validator> validators;