I'm trying to build an Spring example application but I'm facing something strange. I'm using Netbeans 8.2 with a fresh Maven Java Application project. The only dependency (on the pom file) is spring-context 4.3.5.RELEASE (which triggers other necessary dependencies for the project).
I have the following simple main class in the main package (testdi):
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
Restaurant r = context.getBean(Restaurant.class);
r.ListWaiters();
r.ListTables();
}
}
Config Class, which is in the same package as Main, contains the Spring Java Configuration, along with the creation of some Beans:
@Configuration
@ComponentScan(basePackageClasses=testdi.model.ComponentScan.class)
public class Config {
@Bean
public List<Waiter> waiters() {
List<Waiter> waiters = new ArrayList<>();
for(int i = 0; i < 6; i++) {
waiters.add(waiter());
}
waiters.get(0).setName("Anna");
waiters.get(1).setName("John");
waiters.get(2).setName("Jane");
waiters.get(3).setName("Bob");
waiters.get(4).setName("Pam");
waiters.get(5).setName("Lou");
return waiters;
}
@Bean
@Scope("prototype")
public Waiter waiter() {
return new Waiter();
}
@Bean
public List<Table> tables() {
List<Table> tables = new ArrayList<>();
for(int i = 0; i < 5; i++) {
tables.add(table());
tables.get(i).setNumber(i + 1);
}
return tables;
}
@Bean
@Scope("prototype")
public Table table() {
return new Table();
}
}
Waiter and Table classes are pretty simple POJO classes just containing a property String name (for Waiter) and Int number (for Table), and resides in the testdi.model package. testdi.model.ComponentScan is just an Interface for basePackageClasses to work. The Restaurant class is also in the testdi.model package and is marked as component. Since it contains the most relevant code related to the problem, here it is:
@Component
public class Restaurant {
@Autowired
//@Qualifier("waiters")
List<Waiter> waiters;
@Autowired
//@Qualifier("tables")
List<Table> tables;
public void ListWaiters() {
System.out.println("List of waiters:");
for(Waiter w : waiters) {
System.out.println("Waiter " + w.getName());
}
}
public void ListTables() {
System.out.println("List of tables:");
for(Table t : tables) {
System.out.println("Table " + t.getNumber());
}
}
}
Now the problem: If I run the code as it is (with @Qualifier labels commented), waiters and tables fields contains ArrayList objects of size 1 with one object each initialized with default values (name=null for Waiter and number=0 for Table), but if I uncomment the @Qualifier labels, waiters and tables fields are correctly autowired to the Beans defined in the Config class. If I comment out the creation of the Waiter and Table List Beans on the Config class (and leave the @Qualifier labels commented out), the applications runs exactly as in the first case (ArrayList objects of size 1 ...).
It seems that Spring is creating List and List Beans on its own and using them as principal in case other Beans of the same class exists. I don't know if this is right but I was expecting the application to fail to run when I commented out the creation of this Beans on my Config class, since no beans of any of this two types should exist.
Am I understanding something wrong?
Regards.
Edit: Well, yes, I was understanding something wrong. According to this and this posts, this is the expected behavior of Spring. For me, it would be clearer Spring no auto creating collections for the declaration of collection variables and getting into the way of autowired; but well, at least I know how it works now.
As requested, here is the code for Waiter and Table classes:
public class Waiter {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Table {
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}