Skip to content

SONARJAVA-6798 Collect dependencies from implicit single-constructor injection - #5950

Merged
NoemieBenard merged 5 commits into
epic-SONARJAVA-6237from
nb/sonarjava-6798-implicit-constructor-injection
Aug 25, 2026
Merged

SONARJAVA-6798 Collect dependencies from implicit single-constructor injection#5950
NoemieBenard merged 5 commits into
epic-SONARJAVA-6237from
nb/sonarjava-6798-implicit-constructor-injection

Conversation

@NoemieBenard

@NoemieBenard NoemieBenard commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary by Gitar

  • Spring context model:
    • Collect dependencies from implicit single-constructor injection in BeanDefinitionGatherer
    • Add test cases for single-constructor and multiple-constructor scenarios

This will update automatically on new commits.

@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

SONARJAVA-6798

@NoemieBenard
NoemieBenard force-pushed the nb/sonarjava-6798-implicit-constructor-injection branch from e764d04 to cd56907 Compare August 21, 2026 09:39
@NoemieBenard
NoemieBenard marked this pull request as ready for review August 21, 2026 11:53
@NoemieBenard
NoemieBenard force-pushed the nb/sonarjava-6798-implicit-constructor-injection branch from 2331cc8 to 590df8d Compare August 24, 2026 13:03
Base automatically changed from nb/sonarjava-6791-qualifier-handling to epic-SONARJAVA-6237 August 24, 2026 13:19
@NoemieBenard
NoemieBenard force-pushed the nb/sonarjava-6798-implicit-constructor-injection branch from 590df8d to aee21d4 Compare August 24, 2026 13:19

@asya-vorobeva asya-vorobeva left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theoretically speaking, we can mix single-constructor injection and @Autowired on field injection within the same Spring component, and Spring will successfully inject dependencies for both. E.g. the following configuration will successfully autowire 2 beans:

@Component
public class UserService {

    // Injected via Constructor
    private final UserRepository userRepository;

    // Injected via Field Injection after instantiation
    @Autowired
    private NotificationService notificationService;

    // Single constructor: Spring automatically autowires 'userRepository'
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

@gitar-bot

gitar-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 2 resolved / 2 findings

Collects dependencies from implicit single-constructor injection and properly skips them when an @Autowired constructor is present, addressing the dead code and over-collection findings.

✅ 2 resolved
Quality: New BeanDependency record is dead/unused code

📄 java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDependency.java:27 📄 java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionGatherer.java:304-318
This commit adds the new BeanDependency record but the same commit replaces its only consumers: dependency collection now returns Map<String, Set<String>> and the tests no longer reference BeanDependency::typeFqn/qualifier. A codebase-wide search confirms no remaining references, so the file is dead code. Either delete BeanDependency.java or wire it into the model; leaving an unused type adds confusion for future readers.

Bug: Implicit constructor injection over-collects when an @Autowired constructor exists

📄 java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionGatherer.java:317-329
Removing the deps.isEmpty() guard means that when a class has one @Autowired constructor plus one other (unannotated) constructor, unannotatedConstructors.size() == 1 is true, so the unannotated constructor's parameters are collected as dependencies in addition to the autowired constructor's. Spring only performs implicit constructor injection when there is exactly one constructor and no @Autowired constructor, so this yields phantom dependencies from a constructor Spring never uses. Track whether any @Autowired constructor was seen and only run the implicit-constructor branch when none was.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqube-next

Copy link
Copy Markdown
Contributor

@asya-vorobeva asya-vorobeva left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

@NoemieBenard
NoemieBenard merged commit a75a6c3 into epic-SONARJAVA-6237 Aug 25, 2026
17 checks passed
@NoemieBenard
NoemieBenard deleted the nb/sonarjava-6798-implicit-constructor-injection branch August 25, 2026 11:41
NoemieBenard added a commit that referenced this pull request Sep 8, 2026
…injection (#5950)

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants