Nespony
Nespony

Reputation: 1371

Spring bean not being picked up?

I have a java spring project with the below service:

@Slf4j
public class DialogFlowService {

    private String projectId;
    private String sessionId;
    private String languageCode;

    public DialogFlowService(DialogFlowConfig dialogFlowConfig) {
        log.info("aaa" + dialogFlowConfig.languageCode);
        this.projectId = dialogFlowConfig.projectId;
        this.sessionId = dialogFlowConfig.sessionId;
        this.languageCode = dialogFlowConfig.languageCode;
    }
}

The constructor takes the below class as an argument:

@Configuration
@ConfigurationProperties(prefix = "dialog-flow")
public class DialogFlowConfig {

    @NotNull
    public String projectId;

    @NotNull
    public String sessionId;

    @NotNull
    public String languageCode;
}

In theory, this should be instantiated by the below bean:

@Bean
public DialogFlowService dialogFlowService() {
   return new DialogFlowService(new DialogFlowConfig());
}

However in practice, when I try to log one of the constructor arguments, it comes up as null. Am I missing something?

Upvotes: 2

Views: 1476

Answers (3)

Savior
Savior

Reputation: 3531

This is similar to what's being described here: Why is my Spring @Autowired field null?

Essentially, by instantiating the DialogFlowConfig instance yourself and not handing it over to Spring, you're preventing Spring from post processing it and injecting ConfigurationProperties property values.

Instead create a @Bean method for DialogFlowConfig and use the corresponding Spring bean to create your DialogFlowService. For example

@Bean
public DialogFlowService dialogFlowService(DialogFlowConfig dialogFlowConfig) {
    return new DialogFlowService(dialogFlowConfig);
}

@Bean
public DialogFlowConfig dialogFlowConfig() {
    return new DialogFlowConfig();
}

Spring will use the @Bean annotated dialogFlowConfig() factory bean method to instantiate and process the corresponding instance (setting its fields). It'll then use it with the dialogFlowService() factory method.

Note: If you do it this way, you'll need to remove @Configuration annotation from DialogFlowConfig, assuming you were previously component scanning it. Alternatively, if you were correctly component scanning, you don't even need the additional @Bean annotated dialogFlowConfig() factory method I proposed. Just inject the DialogFlowConfig bean declared by its @Configuration annotation in the dialogFlowService method.

Upvotes: 1

roushan kumar Singh
roushan kumar Singh

Reputation: 384

First of all you need to use either setter getter in DialogFlowConfig or @Value annotation on all properties. You also need to annotate your service class DialogFlowService with @Service stereotype

Upvotes: -1

Dilini Peiris
Dilini Peiris

Reputation: 456

I think changing your third code snippet like this would do the trick.

@Bean
public DialogFlowService dialogFlowService(DialogFlowConfig  dialogFlowConfig) {
    return new DialogFlowService(dialogFlowConfig);
}

The DialogFlowConfig class is already marked as @Configuration. Hence it is managed by the Spring Application context. So you dont have to explicitly make an object using the new keyword. You can just take it as a parameter

Try putting @EnableConfigurationProperties(DialogFlowConfig.class) into you Spring Application class.

Upvotes: 2

Related Questions