As part of an effort to support both Spring Boot 1.5 and 2.0 for Togglz (https://github.com/togglz/togglz/pull/271) I have two equivalent AutoConfiguration classes that are Spring Boot version dependent, and so I'm using @ConditionalOnClass annotations with Spring boot version specific classes as parameter to only load the right AutoConfiguration class.
I would like to know if there is a best practice for this, or if my approach is acceptable.
I'm aware that supporting different Spring Boot versions is actually being contemplated (#12733), so it would be great if documentation also include guidelines on how to achieve that.
If the @ConditionalOnClass with Spring boot version specific classes as parameter is acceptable, probably it would be better to have a specific @Conditional annotation that would use the @ConditionalOnClass as a meta-annotation, similar to the the @ConditionalOnEnabledEndpoint.
For instance:
// Endpoint annotation only exists since Spring Boot 2
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
// ...
@ConditionalOnClass(Endpoint.class)
public @interface ConditionalOnSpringBoot2 { }
I think it would be useful to document some ideas for this, although I wonder if it might be better to use the wiki rather than add to the reference guide.
I'm personally a little nervous about suggesting auto-configurations attempt to support Spring Boot 2.0 and Spring Boot 1.5 in the same jar. It's certainly possible, but there are subtitles that can cause issues. For example, the common-autoconfigure module in https://github.com/togglz/togglz/pull/271 depends on Boot 1.5 so it could be making calls to classes or methods that have changed in Spring Boot 2.0. I guess it depends on the complexity of the auto-configuration.
For most projects, I think I'd recommend that only supporting Spring Boot 2.0 is the way to go. If Spring Boot 1.5 support is really needed I think I'd create a new dedicated module, even if it means copy-paste code.
@philwebb , thanks for your comments.
In togglz/togglz#271, common-autoconfigure could definitely disappear and those common bits could be duplicated into both modules.
The reason why I opened this issue is that I felt that other projects may have the same needs I had, trying to accommodate both Spring Boot major versions (the same way Spring Boot accommodated Hibernate 4 and 5), at least for a period of time. And, if no guidelines are provided, "creative" solutions will come up, and most of the times, not the right ones :)
Just to be clear, my "creative" solution was:
starter module that provides both a spring-boot-1-autoconfigure and a spring-boot-2-autoconfigure spring-boot-1-autoconfigure are only loaded if Spring Boot version is 1.x (we use @ConditionalOnClass with some Spring Boot class that only exists in 1.x), and the same for spring-boot-2-autoconfigureThe main advantage of that approach was that I don't need to change my starter dependency when I change Spring Boot version, but I'm aware that this is very confusing.
@ruifigueira I certainly agree that your approach is excellent for your users. As you say, we've do similar things in Spring Boot and Spring Framework when we need to support multiple versions. I'm just a little reluctant to recommend it as a general solution because it can be tricky to get right.
I am tempted to close this issue. We can add an extra note on this page to discourage users to support two generations of Spring Boot in the same module.
Would that be enough @ruifigueira?
I'm fine with that. And once again, thanks for your guidance, it was a huge help!
Thanks for the quick feedback. I've added a note on the wiki.
Most helpful comment
I'm fine with that. And once again, thanks for your guidance, it was a huge help!