SONARJAVA-6421 Extract @Profile expressions when gathering bean definitions - #6071
SONARJAVA-6421 Extract @Profile expressions when gathering bean definitions#6071NoemieBenard wants to merge 3 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 👍 / 👎
Code Review 👍 Approved with suggestions 2 resolved / 3 findingsExtracts 💡 Quality: composeProfiles branch for method-only
|
| Auto-apply | Compact |
|
|
Was this helpful? React with 👍 / 👎 | Gitar
|
| Integer.parseInt(spanParts[2]), | ||
| Integer.parseInt(spanParts[3])); | ||
| boolean isPrimary = Boolean.parseBoolean(fields[4]); | ||
| String profiles = !fields[5].isEmpty() |
There was a problem hiding this comment.
This serialization-deserialization becomes more and more complex. I'd say we should think about using some format, JSON or maybe something binary like Protobuf. Let's create JIRA ticket as follow-up for this in epic https://sonarsource.atlassian.net/browse/SONARJAVA-6237.
| .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.


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).