Reputation: 391
I have an application.yml file that has the list of objects as below:
outlook:
mailboxes:
- id: m1
name: mailbox1
- id: m2
name: mailbox2
I have created a spring configuration class called MailBoxProperties to have these properties in a bean as below:
MailBoxProperties.java
@ConfigurationProperties(prefix = "outlook")
@Configuration
public class MailBoxProperties {
private List<MailBox> mailboxes;
public MailBoxProperties() {
}
public MailBoxProperties(List<MailBox> mailboxes) {
this.mailboxes = mailboxes;
}
public void setMailBoxes(List<MailBox> mailboxes) {
this.mailboxes = mailboxes;
}
public List<MailBox> getMailBoxes() {
return mailboxes;
}
public static class MailBox {
public String getName() {
return this.name;
}
public String getId() {
return this.id;
}
private String id, name;
public MailBox() {
}
public MailBox(String id, String name) {
this.id = id;
this.name = name;
}
}
}
I would like to inject the above config bean into another config class as below:
OutlookConnectionManager.java
@Configuration
@EnableConfigurationProperties
public class OutlookConnectionManager{
@Autowired
private MailBoxProperties mailBoxProperties;
private List<String> names;
@Bean
public OutlookConnectionManager getOutlookConnectionManager() {
OutlookConnectionManager outlookConnectionManager = new OutlookConnectionManager();
outlookConnectionManager.getMailBoxProperties();
return outlookConnectionManager;
}
public void getMailBoxProperties() {
names = new ArrayList<String> ();
for(MailBox mail: mailBoxProperties.getMailBoxes()) {
this.names.add(mail.getName());
}
}
}
However, MailBoxProperties is always null and throws null pointer exception on calling mailBoxProperties.getMailBoxes() from getMailBoxProperties.
(I have tried giving @Configuration @EnableConfigurationProperties(MailBoxProperties.class). It throws an exception stating that 2 beans are created. One with the actual path and the other with null). I have tried @Import(){MailBoxProperties.class}.
But, the injection perfectly works in my main application class as below: It fetches the bean and prints the mailbox name correctly.
MailApplication.java
@SpringBootApplication
public class MailApplication {
public static void main(String[] args) {
ApplicationContext context = new SpringApplicationBuilder(MailApplication.class).run(args);
MailBoxProperties props = context.getBean(MailBoxProperties.class);
props. getMailBoxes()
.forEach(cc -> System.out.println(cc.getName()));
}
}
Am I missing any configuration in OutlookConnectionManager.java ? Please help.
Note: I am using Spring boot 1.5.7.RELEASE
Thank you.
Upvotes: 2
Views: 10403
Reputation: 14731
I think there are 2 things you can fix:
First you have some strange getter and setter names in your MailBoxProperties
(like setMailBoxes
for field mailboxes
should be setMailboxes
) and i don't think MailBoxProperties will take values from yaml file with custom setter names. Use default getters and setters
@ConfigurationProperties("outlook")
public class MailBoxProperties {
private List<MailBox> mailboxes;
public List<MailBox> getMailboxes() {
return mailboxes;
}
public void setMailboxes(List<MailBox> mailboxes) {
this.mailboxes = mailboxes;
}
public static class MailBox {
private String id, name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
Second, i don't know what is your goal in OutlookConnectionManager
, but as @M. Deinum mentioned you are trying to call getMailBoxProperties
before spring has had a chance to auto wire the fields.
And i think you can achieve similar behavior with
@Component
public class OutlookConnectionManager{
private final MailBoxProperties mailBoxProperties;
private List<String> names;
@Autowired
public OutlookConnectionManager(MailBoxProperties mailBoxProperties) {
this.mailBoxProperties = mailBoxProperties;
this.names = getNames();
}
public List<String> getNames() {
List<String> names = new ArrayList<>();
for(MailBoxProperties.MailBox mail: mailBoxProperties.getMailboxes()) {
names.add(mail.getName());
}
return names;
}
}
Upvotes: 0
Reputation: 7905
Basically your MailBoxProperties
should be as @varren suggested. And there is no need to annotate with @Configuration
this properties class.
So :
@ConfigurationProperties(prefix = "outlook")
public class MailBoxProperties {
private List<MailBox> mailboxes;
public List<MailBox> getMailboxes() {
return mailboxes;
}
public void setMailboxes(List<MailBox> mailboxes) {
this.mailboxes = mailboxes;
}
public static class MailBox {
private String id, name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
Then you can keep your OutlookConnectionManager
annotated with @Configuration
but what are you trying to do inside it is a little anorthodox (you are re-instantiating the same configuration class with the new
keyword).
However you could make it work by changing your @Bean
method to:
OutlookConnectionManager:
@Bean
public OutlookConnectionManager getOutlookConnectionManager() {
OutlookConnectionManager outlookConnectionManager = new OutlookConnectionManager();
//this call will set this.names
this.getMailBoxProperties();
//set this.names to the names variable of outlookConnectionManager instance
outlookConnectionManager.names = this.names;
return outlookConnectionManager;
}
Upvotes: 2
Reputation: 2269
As @m-deinum pointed out, the properties are still null. Try doing the initialization in a method annotated with @PostConstruct
. All autowired fields should be populated by that point.
More details about @PostConstruct
here: How to call a method after bean initialization is complete?
Upvotes: 0