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

Support constructor binding on 3rd party classes #23607

Open
snicoll opened this issue Oct 7, 2020 · 7 comments
Open

Support constructor binding on 3rd party classes #23607

snicoll opened this issue Oct 7, 2020 · 7 comments
Labels
type: enhancement A general enhancement

Comments

@snicoll
Copy link
Member

snicoll commented Oct 7, 2020

We had a first attempt in #23172 that we decided to revert due to a number of inconsistencies the proposal brings.

Using a declarative model as proposed in #23172 means that we need to figure out whether the user expects the binder to use constructor binding or regular JavaBean conventions. Ignoring that a Kotlin data class (or Java record) could provide us extra metadata, we didn't manage to find an acceptable solution for @EnableConfigurationProperties.

Binding to 3rd party classes so far has been a niche. The way to do this is by declaring a @Bean method with @ConfigurationProperties. For a constructor-based approach, this isn't possible but we could provide a shortcut where one needs to inject a component we'd register in the context, something like:

@Bean
public MyCustomObject myCustomObject(SomeBinder binder) {
    return binder.bind(MyCustomObject.class, "example.acme");
}

The definition above would bind MyCustomObject using the example.acme namespace. Rather than a Class you may provide a supplier for the instance and/or a mode to determine how you want the binder to operate.

Doing things this way means that the annotation processor won't be able to easily detect that it has to generate properties for this. Considering the metadata isn't going to contain default values and description anyway (since the code sits in a different module), this can be considered as a limitation (and one of the reason we may want to keep this niche).

@tomfi
Copy link

tomfi commented Oct 8, 2020

@snicoll just to clarify, in this suggestion the annotation processor will or will not create the meta-data in order to have auto-complete in the yaml editor in intellij/eclipse?

In general, the reason I opened the original ticket was:

  1. I wanted to have the ability to bind 3rd party classes with constructor biding, which was covered by the Binder.bind(...)
  2. As we build an SDK in the company I work for, the meta-data and auto-complete is very important for our customers so having those 3rd party classes registered in a more spring-native way is great (which was solved by the reverted feature)

@snicoll
Copy link
Member Author

snicoll commented Oct 8, 2020

It's another go to what was reverted so the answer to your question is obviously yes.

That being said, we may or may not make it. Binding to third party types (especially with metadata) is not the primary use case and while I have some sympathy for being able to bind types that don't know anything about Spring, it feels to me this is less valid when you want proper metadata as this is a concept that's definitely linked to Spring Boot.

Your current approach does not provide description and default values for keys. IMO, if metadata is important, that's something you should make sure is generated as well.

@tomfi
Copy link

tomfi commented Oct 8, 2020

@snicoll that makes sense, thanks for the clarifications.

@CXwudi
Copy link

CXwudi commented Feb 17, 2023

Not sure if it could be an alternative "solution", but in the library, we create an interface which contains declaration of getters only. Then in the consumer module, the data class implements the interface with constructor binding.

interface MyConfig {
  val confA: Int
}

// in consumer module
@ConfigurationProperties(my.module.config)
data class AppMyConfig(
  override val confA: Int
) : MyConfig 

@david-grew-activeviam
Copy link

Please could I add a plus 1 for this feature. My team prefer to use constructor binding for Configuration Properties classes so that we can rely on the immutability of the object. It would be great if we could use bean construction methods for these objects and benefit from the same metadata.

@frecco75
Copy link

frecco75 commented Nov 6, 2023

@david-grew-activeviam I think you don't need anymore this feature because since Spring Boot 3 you don't need to put anymore @ConstructorBinding annotation on classes and Spring chooses the right constructor to use by reflection.

@david-grew-activeviam
Copy link

david-grew-activeviam commented Dec 4, 2023

@frecco75 - I don't think this addresses the issue. Even in Spring 3 I don't believe you can have an immutable Configuration Properties object (i.e. without setters) and create it using a method in an @Configuration class annotated with @ConfigurationProperties.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

5 participants