-
Notifications
You must be signed in to change notification settings - Fork 40.5k
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 #23172
Comments
Adding an option to @RegisterConfigurationPropertiesBean(value=FooProperties.class, prefix="myproperties") As things stand, I think you can almost do what you want by using the @Bean
public FooProperties fooProperties(Environment env) {
return Binder.get(env).bindOrCreate("my.foo", FooProperties.class);
} |
@philwebb - yes a dedicated annotation will be perfect, I forgot about the prefix. It will make it easier to register the data classes with the correct prefix and to enable constructor binding. I will try the 2nd option as a temporary solution. Another thing, in case there will be a dedicated annotation, will it also be picked by |
If we'd created a separate annotation we'd have to update the annotation processor to handle it I guess. The contract for third party classes so far was to expose them as a |
@snicoll the problem comes when you want to use And in both cases I think the annotation processor won't catch them in order to create the meta-data for the yaml editors which is very important for people like me that create libraries for other developers. I think there should be an easy way to register immutable data classes (with constructor binding) of 3rd party classes with all the benefits of normal classes (e.g. annotation processing, actuator, etc) |
@tomfi I read the issue and I am aware of that, thank you. |
This comment has been minimized.
This comment has been minimized.
Maybe I'm not interpreting this correctly, but it looks like How about adding a parameter, such as Example: @Bean
@ConfigurationProperties(prefix = "my.foo", bindingMode = ConfigurationProperties.BindingMode.CONSTRUCTOR)
public FooProperties fooProperties() {} |
@Davio looks nice, but what will you put in the actual method body? @Bean
@ConfigurationProperties(prefix = "my.foo", bindingMode = ConfigurationProperties.BindingMode.CONSTRUCTOR)
public FooProperties fooProperties() {
// compilation error, must provide parameters to the constructor
return new FooProperties();
} And if you use |
Oh of course the method body, it must return an actual instance of the thing. So if you want to do it without a method body. you basically need the annotation to be processed entirely by the annotation processor and you get the suggested And if you go with the existing route, you need to fill in the body, so that's why the factory bean option whas proposed. I guess a workaround would be to just use the Kotlin no-arg compiler plugin and annotate your data classes with some special custom annotation, like |
I tried a few different approaches and landed on a new The new annotation is conceptually a mix of The original feature request can now be implemented as follows: data class FooProperties(
val bar: String
) @Configuration
@ImportConfigurationPropertiesBean(type = [FooProperties::class], prefix = "foo")
class FooAutoConfiguration |
Oh, I almost forgot. The annotation processor has also been updated to generate meta-data if it finds |
@philwebb amazing!! Thank you very much :) |
@philwebb you wrote that default values are not supported. If the data class is as the following: data class FooProperties(
val a: String,
val b: String = "default" Will it honor the default value of the data class and succeed in creating the bean? |
@tomfi I'm not too sure what bytecode Kotlin with generate for default values. If it's a primary constructor that accepts |
Reopening to rename the annotation to |
I've renamed it to |
Yes it is a single constructor, it works perfectly fine with |
@philwebb What made you move away from |
I was super frustrated yesterday trying to come up with a name for the container annotation, so I wanted to try flipping the terms to see if it made any difference. I agree, it didn't really work :( We originally were thinking Perhaps we should add
Either that or I should just forget about finding a good name for the container and we go with:
|
My only remaining question is: if there are multiple constructors, how does it deduce which one to use? The one with the most (matched) arguments or something like that? |
Okay, for your use case it will work, but if you have a non-data Kotlin class with default parameters, it won't work. Maybe that's an acceptable tradeoff as there might not be a sensible way to determine the 'primary' constructor without it having a special annotation or something like that. |
FTR we've decided to revert this feature as it brings a number of inconsistencies. Please follow-up on #23607 |
I use kotlin, and I want to use data classes to describe my properties/options. The data classes themselves sit in core modules that do not depend on spring, and should have minimal 3rd party dependencies.
On top of the modules mentioned above, I built spring auto-configuration modules that create beans, load properties, and utilize spring's features to expose the core module as proper spring modules.
It would be great if I could create a data class in my core module, e.g.
And then in the spring auto-configuration module somehow load it with constructor binding, e.g.
Or maybe some way to do it programmatically, e.g.
I saw the following issues: #18935, #19011.
If i understand correctly i can create a bean that wraps my data class and the constructor binding will work for my inner class, but it will be nice to have a better way to define the properties without additional wrappers.
The text was updated successfully, but these errors were encountered: