Wiring beans that do not implement an tag interface in list using Spring

Viewed 209

I have a set of classes that extends an abstract class Executor. Let's say that these classes are ExecutorOne, ExecutorTwo and ExecutorThree. Then, I have a fourth class extending the Executor type, ExecutorFour, but also implementing the interface NotUsable.

I am using Spring 4.x to inject an instance of all the above beans into a list.

@Autowired
private final List<Executor> executors;

Is there any mechanism that allows me to not inject a bean of type ExecutorFour inside the list executors? I want the list executors to contain only three beans, respectively of type ExecutorOne, ExecutorTwo and ExecutorThree.

I tried to have a look at the @Conditional annotation, but it seems it is no use in this situation.

Thanks in advance.

2 Answers

There is another option, it helps to achieve what you try, but doesn't answer the question directly.

Spring doesn't have an exclusion mechanism like this, after all, all 4 beans are valid spring beans and are created.

However, you can work with Usable interface, instead of NotUsable marker interface. Here is a (pretty much self-explanatory) example:

interface Executor {}

interface UsableExecutor extends Executor {}

class Executor1 implements UsableExecutor{...}
class Executor2 implements UsableExecutor{...}
class Executor3 implements UsableExecutor{...}
class Executor4 implements Executor {}  // note, doesn't implement UsableExecutor

@Component
class SomeClassWithUsableExecutors {

   private final List<UsableExecutor> usableExecutors;

   // an autowired constructor - only 3 elements will be in the list 
   public SomeClassWithUsableExecutors(List<UsableExecutor> usableExecutors) {
      this.usableExecutors = usableExecutors;
   } 
}

While Spring doesn't provide a "exclude these classes" grammar for @Autowired, it provides a "include these classes" support instead, in the form of @Qualifier.

The way this works is to create a custom qualifier that you'll apply at the class level to the Executor classes that you would want to be @Autowired at runtime. Spring does the rest to make sure that the undesired classes don't get into the list:

  1. Create your custom qualifier, to be applied to the desired classes:

    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface Usable {
        String value();
    }
    
  2. Apply your qualifier at the injection point:

    @Autowired
    @Usable
    private final List<Executor> executors;
    

What the above now does is that only Executor classes with the custom @Usable qualifier will be injected into executors

Related