I would like to be able to generate configuration metadata using lombok @Value annotations and Constructor Binding.
Background
In our projects we have adopted ConstructorBinding but perhaps differently from what was envisaged at Spring :-).
To avoid collisions we place all of our properties under a single tag: "application" (we use yaml). Under here we have application specific configuration properties.
In Java we have one parent class "ApplicationProperties" using ConstructorBinding that contains the sub properties.
@ConfigurationProperties("application")
@ConstructorBinding
@Value
public class ApplicationProperties {
String name;
Service1Properties service1;
Service2Properties service2;
}
And then each sub system configuration only needs the @Value annotation, for example:
@Value
public class Service1Properties {
String prop1;
Duration prop2;
}
Java field names need to match the property name but this gives us a number of benefits:
- No need to specify property keys in multiple files with ConfigurationProperties.
- reduces errors
- easier refactoring
- All classes are Immutable
- Java properties classes reflect properties files structure
- Easier to test and validate at startup
- Common values from the top level (like name/environment) can be available when creating subsystem beans.
- Clean properties classes: only one annotation: @Value
We only inject the Application Properties in one place (where we create beans). If we need subsystem properties we either inject that or expose it as a bean.
But there is one major downside, generation of metadata from spring-boot-configuration-processor
.
Existing Code
I have looked at how the annotation processor works and I see there is support for @Data and @Getter/Setter. I experimented with that a bit, but see that I always need a real "AllArgsConstructor" - the lombok one does not work.
This is normal I guess since they are both annotation processors and so run order cannot be guaranteed
I tried adding @Value
to the existing code and by creating similar tests everything was fine but in our case it still won't generate the metadata because the class is not annotated with @ConfigurationProperties
.
What I've done so far is to put them in by hand, generate them, and then put them in additional-spring-configuration-metadata.json
But it soon gets out of sync. It'd be great to support this, but I can see how it would be a lot of work with the existing code base.
Maybe if it was undergoing major changes in future it could be considered?
Example project based on start.spring.io
attached. See DemoApplicationTests.java
Comment From: snicoll
In our projects we have adopted ConstructorBinding but perhaps differently from what was envisaged at Spring :-).
The configuration processor doesn't handle @Value
at all indeed. Even if we would, the sample that you've shared (thank you for that!) is invalid as it misses @NestedConfigurationProperty
on service1
and service2
. I would argue that what you've chosen there is problematic as the annotation processor won't support generating metadata for such POJOs if they're not compiled in the same module as the main ApplicationProperties
. And choosing this infrastructure makes it very tempting to map something from another module.
We can consider adding support for @Value
if that's not too costly maintenance wise.
Comment From: mjeffrey
Thanks @snicoll for the feedback. I didn't know about @NestedConfigurationProperty
and tried a few experiments with and without it.
The only way I could get the metadata generated was to add the @ConfigurationProperties("application.service1")
and (of course) change @Value
to @Data
.
@Data
@ConfigurationProperties("application.service1")
public class Service1Properties {
String prop1;
Duration prop2;
}
The additional configuration is not ideal, but I already use it as a workaround.
Adding @NestedConfigurationProperty
didn't make a difference to the metadata generation for my case.
@NestedConfigurationProperty
Service1Properties service1;
Anyway having @Value
recognised would definitely help. I could make a PR for it, but it is a relatively straight forward change I think. Let me know if you think a PR would be helpful.
Comment From: snicoll
@NestedConfigurationProperty
with a valid POJO should work and is mandatory if the nested namespace is not an inner-class of the @ConfigurationProperties
annotated type. Sure, a PR with test coverage is more than welcome.
Comment From: philwebb
Closing in favor of PR #26337