Skip to content

SONARJAVA-6489: Implement rule S8909 - Quarkus CacheKeyGenerator should be instantiable#5699

Open
romainbrenguier wants to merge 6 commits into
masterfrom
new-rule/SONARJAVA-6489-S8909
Open

SONARJAVA-6489: Implement rule S8909 - Quarkus CacheKeyGenerator should be instantiable#5699
romainbrenguier wants to merge 6 commits into
masterfrom
new-rule/SONARJAVA-6489-S8909

Conversation

@romainbrenguier

Copy link
Copy Markdown
Contributor

Summary

Implements rule S8909 to detect Quarkus CacheKeyGenerator implementations that cannot be instantiated by the CDI container.

Changes

  • Implemented CacheKeyGeneratorInstantiableCheck to detect classes implementing CacheKeyGenerator that:
    • Have no public no-args constructor AND
    • Are not CDI beans (missing scope annotations like @ApplicationScoped, @Dependent, etc.)
  • Added comprehensive test coverage with both compliant and non-compliant cases
  • Created mock-up CacheKeyGenerator interface for testing (avoiding external dependency)

Test Coverage

The rule detects:

  • ✅ Classes with constructor dependencies but no CDI scope annotation
  • ✅ Classes with multiple constructors (none no-args) and no CDI scope
  • ✅ Classes with private constructors

The rule correctly ignores:

  • ✅ Classes with CDI scope annotations (even with dependencies)
  • ✅ Classes with public no-args constructors
  • ✅ Abstract classes and interfaces
  • ✅ Non-CacheKeyGenerator classes

🤖 Generated with Claude Code

romainbrenguier and others added 2 commits June 23, 2026 10:53
This commit contains partial work that failed to complete.
Continuing with SA-CI and PR creation.
- Fixed CacheKeyGeneratorInstantiableCheck implementation to properly detect issues
- Added mock-up CacheKeyGenerator interface for testing instead of external dependency
- Moved test sample to compiling sources with proper mock-ups
- Test now passes successfully

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Comment thread java-checks-test-sources/default/pom.xml Outdated
romainbrenguier and others added 2 commits June 24, 2026 09:40
- Generated HTML and JSON rule metadata from RSPEC
- Added S8909 to Sonar way profile
- Rule detects non-instantiable CacheKeyGenerator implementations

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Comment: <details open>
<summary><b>Code Review</b> <kbd>⚠️ Changes requested</kbd> <kbd>1 resolved / 3 findings</kbd></summary>

Implements rule S8909 for Quarkus CacheKeyGenerator instantiability, but introduces a redundant dependency conflict and incorrectly evaluates implicit package-private constructors as public.

<details>
<summary>⚠️ <b>Quality:</b> Redundant quarkus-cache dependency conflicts with local mock interface</summary>

<kbd>📄 <a href="https://github.com/SonarSource/sonar-java/pull/5699/files#diff-65b481d7948308268695c9b6ced91981e76b2f17492fa537fa94e0e1acc6057dR189-R194">java-checks-test-sources/default/pom.xml:189-194</a></kbd> <kbd>📄 <a href="https://github.com/SonarSource/sonar-java/pull/5699/files#diff-8eba708ee0e692d479690a9177582d8d3295836ae8036bddc835e583fd5f26c9R8-R9">java-checks-test-sources/default/src/main/java/io/quarkus/cache/CacheKeyGenerator.java:8-9</a></kbd>

The PR adds the real `io.quarkus:quarkus-cache:3.2.0.Final` dependency in pom.xml AND also adds a hand-written mock `io/quarkus/cache/CacheKeyGenerator.java` with the same fully-qualified name. The PR description states the mock was created "avoiding external dependency", which directly contradicts also adding the dependency. Having both a local source file and a jar that define `io.quarkus.cache.CacheKeyGenerator` on the same compile path is at best redundant and can cause type-resolution ambiguity / duplicate-type issues in the test-sources module. Pick one approach: either rely on the real dependency and delete the mock, or keep the mock and drop the new dependency from pom.xml (consistent with the stated intent). Note the real Quarkus `CacheKeyGenerator` also declares a default `boolean generationGroup()` method, so the mock is not a faithful copy.

</details>

<details>
<summary>💡 <b>Edge Case:</b> Implicit constructor of package-private class treated as public</summary>

<kbd>📄 <a href="https://github.com/SonarSource/sonar-java/pull/5699/files#diff-163bcab034b13aa1549ddbee8f2fe2cde6ae0fa4bc77bce4da28044ef134cdf5R86-R98">java-checks/src/main/java/org/sonar/java/checks/quarkus/CacheKeyGeneratorInstantiableCheck.java:86-98</a></kbd> <kbd>📄 <a href="https://github.com/SonarSource/sonar-java/pull/5699/files#diff-163bcab034b13aa1549ddbee8f2fe2cde6ae0fa4bc77bce4da28044ef134cdf5R49-R51">java-checks/src/main/java/org/sonar/java/checks/quarkus/CacheKeyGeneratorInstantiableCheck.java:49-51</a></kbd>

`hasPublicNoArgsConstructor` returns true when the no-arg constructor's `declaration() == null` (implicit default constructor), regardless of visibility. An implicit default constructor inherits the class's access level, so for a package-private (or private nested) class implementing `CacheKeyGenerator` the implicit constructor is NOT public. The issue message explicitly tells users to add a "public no-args constructor", yet such a class is reported compliant — an inconsistency that can produce a false negative if Quarkus requires a public constructor for non-CDI instantiation. Consider also checking the effective visibility of the implicit constructor (e.g. require the class itself to be public), or align the message with the actual check. Also note records/enums implementing the interface are not covered since `nodesToVisit()` only registers `Tree.Kind.CLASS`.

</details>

<details>
<summary><kbd>✅ 1 resolved</kbd></summary>

<details>
<summary>✅ <b>Quality:</b> Missing S8909 rule metadata (HTML + JSON) breaks build</summary>

> <kbd>📄 java-checks/src/main/java/org/sonar/java/checks/quarkus/CacheKeyGeneratorInstantiableCheck.java:30</kbd>
> The new rule `CacheKeyGeneratorInstantiableCheck` is annotated with `@Rule(key = "S8909")` and is auto-registered via `CheckListGenerator`, but no metadata files exist for it. `GeneratedCheckListTest` asserts that both `org/sonar/l10n/java/rules/java/S8909.html` and `S8909.json` exist for every registered rule (see GeneratedCheckListTest.java:137-142), and a Glob confirms neither file is present. Without these the rule has no description, no severity/type/profile assignment, and the test suite (hence the build) will fail. Add `S8909.html` (rule description) and `S8909.json` (metadata: title, type, status, tags, remediation, default severity, and SonarWay profile membership) under `java-checks/src/main/resources/org/sonar/l10n/java/rules/java/`.

</details>

</details>

<details>
<summary>🤖 <b>Prompt for agents</b></summary>

````
Code Review: Implements rule S8909 for Quarkus CacheKeyGenerator instantiability, but introduces a redundant dependency conflict and incorrectly evaluates implicit package-private constructors as public.

1. ⚠️ Quality: Redundant quarkus-cache dependency conflicts with local mock interface
   Files: java-checks-test-sources/default/pom.xml:189-194, java-checks-test-sources/default/src/main/java/io/quarkus/cache/CacheKeyGenerator.java:8-9

   The PR adds the real `io.quarkus:quarkus-cache:3.2.0.Final` dependency in pom.xml AND also adds a hand-written mock `io/quarkus/cache/CacheKeyGenerator.java` with the same fully-qualified name. The PR description states the mock was created "avoiding external dependency", which directly contradicts also adding the dependency. Having both a local source file and a jar that define `io.quarkus.cache.CacheKeyGenerator` on the same compile path is at best redundant and can cause type-resolution ambiguity / duplicate-type issues in the test-sources module. Pick one approach: either rely on the real dependency and delete the mock, or keep the mock and drop the new dependency from pom.xml (consistent with the stated intent). Note the real Quarkus `CacheKeyGenerator` also declares a default `boolean generationGroup()` method, so the mock is not a faithful copy.

2. 💡 Edge Case: Implicit constructor of package-private class treated as public
   Files: java-checks/src/main/java/org/sonar/java/checks/quarkus/CacheKeyGeneratorInstantiableCheck.java:86-98, java-checks/src/main/java/org/sonar/java/checks/quarkus/CacheKeyGeneratorInstantiableCheck.java:49-51

   `hasPublicNoArgsConstructor` returns true when the no-arg constructor's `declaration() == null` (implicit default constructor), regardless of visibility. An implicit default constructor inherits the class's access level, so for a package-private (or private nested) class implementing `CacheKeyGenerator` the implicit constructor is NOT public. The issue message explicitly tells users to add a "public no-args constructor", yet such a class is reported compliant — an inconsistency that can produce a false negative if Quarkus requires a public constructor for non-CDI instantiation. Consider also checking the effective visibility of the implicit constructor (e.g. require the class itself to be public), or align the message with the actual check. Also note records/enums implementing the interface are not covered since `nodesToVisit()` only registers `Tree.Kind.CLASS`.

````

</details>

</details>

<details>
<summary><b>Options</b> </summary>

<kbd>Auto-apply is off</kbd> → Gitar will not commit updates to this branch.<br><kbd>Display: compact</kbd> → Showing less information.<br><kbd>Unblock</kbd> → Override a blocking verdict and allow merging.

Comment with these commands to change:

<table>
<tr>
<td><kbd>Auto-apply</kbd></td>
<td><kbd>Compact</kbd></td>
<td><kbd>Unblock</kbd></td>
</tr>
<tr>
<td>

```
gitar auto-apply:on
```
</td>
<td>

```
gitar display:verbose
```
</td>
<td>

```
gitar unblock
```
</td>
</tr>
</table>

</details>

<sub>Was this helpful? React with 👍 / 👎 | [Gitar](https://gitar.ai)</sub>
@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

SONARJAVA-6489

romainbrenguier and others added 2 commits June 24, 2026 15:45
- Fix Noncompliant marker length in CacheKeyGeneratorInstantiableCheckSample (50 carets -> 45 carets to match class name)
Add expected autoscan diff for new rule S8909 (3 false positives in autoscan mode)
and update S6813 false negatives count (65 -> 68). Update test to expect 11 rules
causing FPs instead of 10.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@gitar-bot

gitar-bot Bot commented Jun 24, 2026

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

Implements rule S8909 to detect non-instantiable Quarkus CacheKeyGenerator classes. The build metadata, dependency conflicts, and package-private constructor false positives have all been resolved.

✅ 3 resolved
Quality: Missing S8909 rule metadata (HTML + JSON) breaks build

📄 java-checks/src/main/java/org/sonar/java/checks/quarkus/CacheKeyGeneratorInstantiableCheck.java:30
The new rule CacheKeyGeneratorInstantiableCheck is annotated with @Rule(key = "S8909") and is auto-registered via CheckListGenerator, but no metadata files exist for it. GeneratedCheckListTest asserts that both org/sonar/l10n/java/rules/java/S8909.html and S8909.json exist for every registered rule (see GeneratedCheckListTest.java:137-142), and a Glob confirms neither file is present. Without these the rule has no description, no severity/type/profile assignment, and the test suite (hence the build) will fail. Add S8909.html (rule description) and S8909.json (metadata: title, type, status, tags, remediation, default severity, and SonarWay profile membership) under java-checks/src/main/resources/org/sonar/l10n/java/rules/java/.

Quality: Redundant quarkus-cache dependency conflicts with local mock interface

📄 java-checks-test-sources/default/pom.xml:189-194 📄 java-checks-test-sources/default/src/main/java/io/quarkus/cache/CacheKeyGenerator.java:8-9
The PR adds the real io.quarkus:quarkus-cache:3.2.0.Final dependency in pom.xml AND also adds a hand-written mock io/quarkus/cache/CacheKeyGenerator.java with the same fully-qualified name. The PR description states the mock was created "avoiding external dependency", which directly contradicts also adding the dependency. Having both a local source file and a jar that define io.quarkus.cache.CacheKeyGenerator on the same compile path is at best redundant and can cause type-resolution ambiguity / duplicate-type issues in the test-sources module. Pick one approach: either rely on the real dependency and delete the mock, or keep the mock and drop the new dependency from pom.xml (consistent with the stated intent). Note the real Quarkus CacheKeyGenerator also declares a default boolean generationGroup() method, so the mock is not a faithful copy.

Edge Case: Implicit constructor of package-private class treated as public

📄 java-checks/src/main/java/org/sonar/java/checks/quarkus/CacheKeyGeneratorInstantiableCheck.java:86-98 📄 java-checks/src/main/java/org/sonar/java/checks/quarkus/CacheKeyGeneratorInstantiableCheck.java:49-51
hasPublicNoArgsConstructor returns true when the no-arg constructor's declaration() == null (implicit default constructor), regardless of visibility. An implicit default constructor inherits the class's access level, so for a package-private (or private nested) class implementing CacheKeyGenerator the implicit constructor is NOT public. The issue message explicitly tells users to add a "public no-args constructor", yet such a class is reported compliant — an inconsistency that can produce a false negative if Quarkus requires a public constructor for non-CDI instantiation. Consider also checking the effective visibility of the implicit constructor (e.g. require the class itself to be public), or align the message with the actual check. Also note records/enums implementing the interface are not covered since nodesToVisit() only registers Tree.Kind.CLASS.

Options

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

Comment with these commands to change:

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

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqube-next

Copy link
Copy Markdown

@romainbrenguier romainbrenguier marked this pull request as ready for review June 24, 2026 14:40
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.

1 participant