SONARJAVA-6421 Extract @Profile expressions when gathering bean definitions - #6071
SONARJAVA-6421 Extract @Profile expressions when gathering bean definitions#6071NoemieBenard wants to merge 4 commits into
Conversation
| @Nullable | ||
| private static String composeProfiles(@Nullable String classProfiles, @Nullable String ownProfiles) { | ||
| if (classProfiles == null) { | ||
| return ownProfiles; | ||
| } | ||
| if (ownProfiles == null) { | ||
| return classProfiles; | ||
| } | ||
| return classProfiles + PROFILE_AND_SEPARATOR + ownProfiles; | ||
| } |
There was a problem hiding this comment.
💡 Quality: composeProfiles branch for method-only @Profile is untested
composeProfiles has three branches, but the parameterized profileArguments cases only exercise class-only (inheritedProfileBean → "prod"), both-present (ownProfileBean → "prod;test") and both-absent (simpleComponent → null); no test resource declares a @Profile on a @Bean method inside a class without a class-level @Profile (grep over src/test/files/springcontext shows @Profile only in ProfiledComponent, MultiProfileComponent and ProfiledConfigurationWithBeanMethods, the latter always class-annotated). The classProfiles == null && ownProfiles != null path — the common Spring pattern of an unprofiled @Configuration with profile-gated @Bean methods — is therefore uncovered, so a future regression that drops the method-level expression in that case would not be caught. Add a @Bean-level-only @Profile fixture and a corresponding argument row.
Add a fixture with a method-level-only @Profile and assert the composed value is the method's own expression.:
// src/test/files/springcontext/ConfigurationWithProfiledBeanMethod.java
@Configuration
class ConfigurationWithProfiledBeanMethod {
@Profile("test")
@Bean
ApplicationContext methodOnlyProfileBean() { return null; }
}
// BeanDefinitionGathererTest#profileArguments
// @Bean method's own @Profile is kept when the enclosing class has none
Arguments.of("src/test/files/springcontext/ConfigurationWithProfiledBeanMethod.java", "methodOnlyProfileBean", "test")
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
| .orElse(null); | ||
| } | ||
|
|
||
| @Nullable |
There was a problem hiding this comment.
The same as for PR #6068. After extracting this method please add comment.
asya-vorobeva
left a comment
There was a problem hiding this comment.
@Profile annotation luckily does not evaluate SpEL expressions. But it supports syntax like this:
@Profile("dev & !test")
More precisely, it supports !, &, | operators.
Would be great to add support for such evaluation. But I'd suggest to do it in separate PR.
3ab3792 to
d9a3dc1
Compare
Code Review 👍 Approved with suggestions 2 resolved / 5 findingsAdds extraction of Consider adding test coverage for the 💡 Quality: composeProfiles branch for method-only
|
| Auto-apply | Compact |
|
|
Was this helpful? React with 👍 / 👎 | Gitar
|
|
|
||
| /** Reads the {@code @Profile} annotation's "value" attribute, joining every profile name it lists. */ | ||
| @Nullable | ||
| private static String extractProfiles(SymbolMetadata metadata) { |
There was a problem hiding this comment.
The same as for PR #6068. Instead of making this class more and more unreadable, let's extract these methods and related machinery to SpringUtils. And also let's make documentation standard. Moreover, another benefit of extraction is that you can test methods independently in SpringUtilsTest class (which also will provide additional documentation).


Summary
BeanDefinitionGatherernow extracts@Profileexpressions (single or array-valued) from stereotype-annotated classes and@Beanmethods, storing them onBeanDefinitionHoldervia the existingprofiles(...)builder step.@Beanmethods, the method's own@Profiletakes precedence over the one declared on the enclosing@Configuration/@Componentclass; if the method has none, it inherits the class's.profilesinserted right afterisPrimary).