SONARJAVA-6791 Handle @Qualifier annotations on autowired dependencies in BeanDefinitionGatherer - #5936
Conversation
cf0c655 to
ef6cdf8
Compare
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
| /** Names of other beans this bean depends on. */ | ||
| private List<String> dependingBeans; | ||
| /** Dependencies this bean requires, each capturing the required type and an optional {@code @Qualifier} name. */ | ||
| private List<BeanDependency> dependingBeans; |
There was a problem hiding this comment.
This list can be rather large, and we need to have fast look-up to be able to define needed dependency. I'd suggest to think about using Map / Set, the key should be the bean's name. In Spring framework this should be qualifier or type.
| private static Map<String, String> collectAutowiredDependencies(ClassTree classTree) { | ||
| Map<String, String> deps = new LinkedHashMap<>(); | ||
| for (Tree member : classTree.members()) { | ||
| if (member.is(Tree.Kind.VARIABLE)) { | ||
| VariableTree field = (VariableTree) member; | ||
| if (member instanceof VariableTree field) { | ||
| if (field.symbol().metadata().isAnnotatedWith(SpringUtils.AUTOWIRED_ANNOTATION)) { | ||
| deps.add(field.symbol().type().fullyQualifiedName()); | ||
| String typeFqn = field.symbol().type().fullyQualifiedName(); | ||
| deps.put(dependencyKey(field.simpleName().name(), extractQualifier(field.symbol().metadata())), typeFqn); | ||
| } | ||
| } else if (member.is(Tree.Kind.CONSTRUCTOR, Tree.Kind.METHOD)) { | ||
| MethodTree method = (MethodTree) member; | ||
| if (method.symbol().metadata().isAnnotatedWith(SpringUtils.AUTOWIRED_ANNOTATION)) { | ||
| method.parameters().stream() | ||
| .map(p -> p.symbol().type().fullyQualifiedName()) | ||
| .forEach(deps::add); | ||
| deps.putAll(parameterDependencies(method)); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
⚠️ Edge Case: Map keyed by field/param name silently drops colliding dependencies
Switching dependingBeans from a List to a Map keyed by qualifier-or-field/param-name means two distinct dependencies that share a key collapse into one, silently losing a dependency the old list preserved. Collisions are reachable: e.g. an @Autowired field named service plus an @Autowired setter/constructor param also named service, or a @Qualifier("x") dependency alongside another dependency whose field name is x (putAll/put overwrite). Consider keying by a guaranteed-unique value or keeping a collection of dependencies per key if multiple injection points must be retained.
Allow multiple dependency types per key to avoid silently dropping colliding entries.:
// If multiple deps can legitimately share a name, keep them all, e.g.:
Map<String, List<String>> deps = new LinkedHashMap<>();
...
deps.computeIfAbsent(dependencyKey(name, qualifier), k -> new ArrayList<>()).add(typeFqn);
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
|
CI failed: Maven build failures in the integration test module (it-java-ruling) due to the SonarQube Maven plugin requiring Java 21+ while executing on Java 17.Overview1 unique failure pattern found across 3 analyzed logs. The integration tests fail during the SonarQube analysis goal because the scanner plugin requires Java 21 or newer, but the build environment is running on Java 17. FailuresSonarQube Plugin Java Version Mismatch (confidence: high)
Summary
Code Review
|
| Auto-apply | Compact | Unblock |
|
|
|
Was this helpful? React with 👍 / 👎 | Gitar



Summary by Gitar
BeanDependencyrecord to capture dependency type and optional@Qualifiervalue.BeanDefinitionGathererto extract@Qualifierannotations on fields, constructors, and@Beanmethods.This will update automatically on new commits.