Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConfigurationProperties beans should be embeddable #42179

Closed
neshkeev opened this issue Sep 8, 2024 · 3 comments
Closed

ConfigurationProperties beans should be embeddable #42179

neshkeev opened this issue Sep 8, 2024 · 3 comments
Labels
status: duplicate A duplicate of another issue

Comments

@neshkeev
Copy link

neshkeev commented Sep 8, 2024

Motivation

ConfigurationProperties has many of out-of-box implementations for different technologies, like Apache Kafka, DataSource, JMS, etc.

Software Developers often combine a bunch of technologies in a single application with results in several @ConfigurationProperties Spring Beans one for each in use technologies.

Proposal

It would be great to have a way to combine all the @ConfigurationProperties beans in a single @ConfigurationProperties Spring Bean and keep all the auto-configuration abilities at the same time

Example

There is an application.properties file with two Apache Kafka Clusters and two Data Sources:

myapp.first-cluster.spring.kafka.bootstrap-servers=first:9092
myapp.second-cluster.spring.kafka.bootstrap-servers=second:9092

myapp.first-datasource.spring.datasource.name=FirstDS
myapp.first-datasource.spring.datasource.url=jdbc:postgresql://first:5432/first
myapp.first-datasource.spring.datasource.username=first
myapp.first-datasource.spring.datasource.password=first

myapp.second-datasource.spring.datasource.name=SecondDS
myapp.second-datasource.spring.datasource.url=jdbc:postgresql://second:5432/second
myapp.second-datasource.spring.datasource.username=second
myapp.second-datasource.spring.datasource.password=second

It would be nice to be able to define a bean that reads all the properties into a single bean like this:

@ConfigurationProperties(prefix="myapp")
public class MyAppProperties {

    private KafkaProperties firstCluster;
    private KafkaProperties secondCluster;

    private DataSourceProperties firstDatasource;
    private DataSourceProperties secondDatasource;

    // getters + setters
}

So then I can inject this single bean instead of a bunch of @ConfigurationProperties beans:

@Controller
public class MyController {
    private final MyAppProperties myAppProperties;
    private MyController(MyAppProperties myAppProperties) {
        this.myAppProperties = myAppProperties;
    }
}

Alternatives

It's possible to manually construct such an bean like:

  1. The class for the app's properties:
public class MyAppProperties {

    private final KafkaProperties firstCluster;
    private final KafkaProperties secondCluster;

    private final DataSourceProperties firstDatasource;
    private final DataSourceProperties secondDatasource;

    public MyAppProperties(KafkaProperties firstCluster, KafkaProperties secondCluster, DataSourceProperties firstDatasource, DataSourceProperties secondDatasource) {
        this.firstCluster = firstCluster;
        this.secondCluster = secondCluster;

        this.firstDatasource = firstDatasource;
        this.secondDatasource = secondDatasource;
    }
}
  1. A @Configuration bean that construct a bean for the app's properties:
@Configuration
public class MyAppConfiguration {

    @Bean
    public MyAppProperties() {
        return new MyAppProperties(firstCluster(), secondCluster(), firstDatasource(), secondDatasource());
    }

    @Bean
    @ConfigurationProperties(prefix = "myapp.first-cluster.spring.kafka")
    public KafkaProperties firstCluster() {
        return new KafkaProperties();
    }

    @Bean
    @ConfigurationProperties(prefix = "myapp.second-cluster.spring.kafka")
    public KafkaProperties secondCluster() {
        return new KafkaProperties();
    }
    
    @Bean
    @ConfigurationProperties(prefix = "myapp.first-datasource.spring.datasource")
    public DataSourceProperties firstDatasource() {
        return new DataSourceProperties();
    }
    
    @Bean
    @ConfigurationProperties(prefix = "myapp.second-datasource.spring.datasource")
    public DataSourceProperties secondDatasource() {
        return new DataSourceProperties();
    }
}
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Sep 8, 2024
@neshkeev neshkeev changed the title ConfigurationProperties should be embeddable ConfigurationProperties beans should be embeddable Sep 8, 2024
@snicoll
Copy link
Member

snicoll commented Sep 8, 2024

Software Developers often combine a bunch of technologies in a single application with results in several @ConfigurationProperties Spring Beans one for each in use technologies.

That's the expected behavior as the scope of these are quite different, even in the scope of an application.

AFAIK flagging the four fields in MyAppProperties with @NestedConfigurationProperty should do pretty much that, except the repetition of the prefix, so something like myapp.first-datasource.name instead of myapp.first-datasource.spring.datasource.name.

I don't really understand why you'd want the prefix to be repeated.

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Sep 8, 2024
@neshkeev
Copy link
Author

neshkeev commented Sep 8, 2024

If @ConfigurationProperties beans are embeddable then I can reuse the @ConfigurationProperties classes from Spring Boot to compose my app's own @ConfigurationProperties bean with an arbitrary structure that suits my needs the most.

flagging the four fields in MyAppProperties with @NestedConfigurationProperty should do pretty much that

Using NestedConfigurationProperty can do the trick, but at the same time I lose all the auto-configuration abilities. So in addition to getting a custom @ConfigurationProperties bean that might consist of Spring Boot's own @ConfigurationProperties beans I also would like to keep automatic configuration of Datasources, JMS connections and so on.

It would be nice for Spring Boot to handle the following case:

  1. a prefix of a @ConfigurationProperties bean is nested inside another @ConfigurationProperties bean
  2. the prefix of the later bean is stripped from the property keys
  3. a @ConfigurationProperty Spring bean for the former bean is created
  4. Spring Boot's auto-configuration abilities kick in and a Datasource, JMS Connection, etc. of the former bean is automatically configured as well

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 8, 2024
@snicoll
Copy link
Member

snicoll commented Sep 9, 2024

Thanks, it was far from obvious to me that you expected auto-configuration to apply to those. I think the embedded bits is by far a detail compared to having auto-configuration deal with multiple beans of the same type.

I am going to close this in favor of #15732 where that feature is discussed at length.

@snicoll snicoll closed this as not planned Won't fix, can't repro, duplicate, stale Sep 9, 2024
@snicoll snicoll added status: duplicate A duplicate of another issue and removed status: waiting-for-triage An issue we've not yet triaged status: feedback-provided Feedback has been provided labels Sep 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

3 participants