Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughRoot POM converted to a multi-module aggregator declaring Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (4)
base/.gitignore (1)
12-12: Anchor broad ignore pattern to avoid accidental matches.At Line 12,
driversmatches any path segment nameddrivers. If you only mean the module root folder, prefer/drivers.Suggested change
-drivers +/drivers🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@base/.gitignore` at line 12, The .gitignore entry "drivers" is unanchored and will match any path segment named drivers; change it to an anchored directory pattern (e.g., "/drivers/" or "/drivers") so it only ignores the repository root drivers folder; update the "drivers" line in .gitignore accordingly to use a leading slash and optional trailing slash to explicitly target the module root directory.processor/pom.xml (1)
6-8: Version is duplicated and not synchronized with the aggregator.The version
5.3.0-SNAPSHOTis hardcoded in both<version>(line 8) and<commons-demo.version>property (line 26). Consider using${project.version}for the dependency version or defining a parent POM relationship to ensure consistent versioning across modules during releases.♻️ Suggested approach to synchronize versions
Either use
${project.version}if the processor and base module versions should always match:<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> - <commons-demo.version>5.3.0-SNAPSHOT</commons-demo.version> </properties>And update the dependency:
<dependencies> <dependency> <groupId>com.flowingcode.vaadin.addons.demo</groupId> <artifactId>commons-demo</artifactId> - <version>${commons-demo.version}</version> + <version>${project.version}</version> <scope>provided</scope> </dependency> </dependencies>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@processor/pom.xml` around lines 6 - 8, The POM currently hardcodes the module version in <version> (5.3.0-SNAPSHOT) while also defining <commons-demo.version>, causing duplication; update the module to use a single source of truth by replacing the hardcoded <version> with ${project.version} (or reference ${commons-demo.version} in the dependency) and/or declare a parent POM that controls the version so commons-demo-processor (artifactId) and the commons-demo dependency share the same version property; ensure references are to ${project.version} or the single property and remove the duplicated literal 5.3.0-SNAPSHOT.base/pom.xml (2)
105-110: Consider updating JUnit to 4.13.2.JUnit 4.11 is significantly outdated. Version 4.13.2 includes security fixes (CVE-2020-15250 for
TemporaryFolderrule) and various bug fixes.♻️ Update JUnit version
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> - <version>4.11</version> + <version>4.13.2</version> <scope>test</scope> </dependency>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@base/pom.xml` around lines 105 - 110, The JUnit dependency currently uses an old version (groupId: junit, artifactId: junit) in the dependency block; update its <version> from 4.11 to 4.13.2 to pick up security and bug fixes (e.g., CVE-2020-15250). Modify the dependency entry for junit:junit in base/pom.xml to use version 4.13.2 and then run your build/tests to verify compatibility.
30-33: Minor: Inconsistent indentation.The
<organization>block has inconsistent indentation compared to the rest of the file. The<name>and<url>elements should be indented to match the surrounding blocks.🧹 Fix indentation
<organization> -<name>Flowing Code</name> -<url>https://www.flowingcode.com</url> + <name>Flowing Code</name> + <url>https://www.flowingcode.com</url> </organization>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@base/pom.xml` around lines 30 - 33, The <organization> block has inconsistent indentation: align the child elements <name> and <url> to match surrounding XML blocks by indenting them one level inside <organization> (same indentation style used elsewhere in the file), so update the <organization>, <name>, and <url> lines to use consistent indentation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@base/.gitignore`:
- Around line 8-9: Remove package.json and package-lock.json from the ignore
list so dependency manifests are tracked; update .gitignore by deleting the
lines containing "package.json" and "package-lock.json" (or comment them out) to
ensure dependency changes and reproducible installs are committed.
In `@base/pom.xml`:
- Around line 60-70: Vaadin BOM (vaadin-bom referenced via dependencyManagement
and ${vaadin.version}) pulls a vulnerable commons-fileupload2-core 2.0.0-M1;
either bump the vaadin.version to 25.0+ or add an explicit dependencyManagement
override for org.apache.commons:commons-fileupload2-core to version 2.0.0-M4 (or
later) to force the patched artifact; update the pom's <dependencyManagement>
block so the project uses the safe commons-fileupload2-core version regardless
of the vaadin-bom transitive dependency.
In
`@processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java`:
- Around line 161-170: getRawValue can return null when the annotation element
isn't found which leads to potential NPEs in callers like getStringValue and
resolvePath; change getRawValue to return java.util.Optional<Object> (update its
signature) and return Optional.ofNullable(entry.getValue().getValue()) /
Optional.empty() when not found, then update callers (e.g., getStringValue,
resolvePath) to handle the Optional (use orElse(null) or map/ifPresent as
appropriate) so no direct cast on a possibly-null value occurs.
- Around line 127-149: The processor currently lets `value` override `clazz`
silently in `resolvePath`, so add validation to detect when both `value` (i.e.
not equal to DemoSource.DEFAULT_VALUE) and `clazz` (i.e. `clazzMirror` not equal
to `demoSourceType.asType()`) are provided and emit a compiler error via
`processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "...",
annotatedClass)` (or attach to the `annotation`/specific annotation element)
with a clear message like "It is an error to specify both 'value' and 'clazz' on
`@DemoSource`"; after reporting the error return the chosen path (existing
behavior) or null as appropriate for downstream handling so the method remains
consistent.
- Around line 213-222: The openSourceFile method should detect and surface
missing StandardLocation.SOURCE_PATH more clearly: wrap the
processingEnv.getFiler().getResource(...) calls in a try-catch around both the
loop and the fallback, and if an IOException occurs (or the returned FileObject
is null), rethrow or wrap it with a new IOException that mentions
StandardLocation.SOURCE_PATH may be missing or misconfigured and advises users
to configure the compiler/source path (e.g., add sourcePath to the build/IDE or
configure the annotation processor). Update openSourceFile to reference
StandardLocation.SOURCE_PATH and Filer.getResource in the error message so
consumers of the processor get actionable diagnostics.
---
Nitpick comments:
In `@base/.gitignore`:
- Line 12: The .gitignore entry "drivers" is unanchored and will match any path
segment named drivers; change it to an anchored directory pattern (e.g.,
"/drivers/" or "/drivers") so it only ignores the repository root drivers
folder; update the "drivers" line in .gitignore accordingly to use a leading
slash and optional trailing slash to explicitly target the module root
directory.
In `@base/pom.xml`:
- Around line 105-110: The JUnit dependency currently uses an old version
(groupId: junit, artifactId: junit) in the dependency block; update its
<version> from 4.11 to 4.13.2 to pick up security and bug fixes (e.g.,
CVE-2020-15250). Modify the dependency entry for junit:junit in base/pom.xml to
use version 4.13.2 and then run your build/tests to verify compatibility.
- Around line 30-33: The <organization> block has inconsistent indentation:
align the child elements <name> and <url> to match surrounding XML blocks by
indenting them one level inside <organization> (same indentation style used
elsewhere in the file), so update the <organization>, <name>, and <url> lines to
use consistent indentation.
In `@processor/pom.xml`:
- Around line 6-8: The POM currently hardcodes the module version in <version>
(5.3.0-SNAPSHOT) while also defining <commons-demo.version>, causing
duplication; update the module to use a single source of truth by replacing the
hardcoded <version> with ${project.version} (or reference
${commons-demo.version} in the dependency) and/or declare a parent POM that
controls the version so commons-demo-processor (artifactId) and the commons-demo
dependency share the same version property; ensure references are to
${project.version} or the single property and remove the duplicated literal
5.3.0-SNAPSHOT.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: be01bbc9-a7a2-40c8-bb50-5797d521ec95
📒 Files selected for processing (97)
.gitignorebase/.gitignorebase/pom.xmlbase/src/main/java/com/flowingcode/vaadin/addons/DevSourceRequestHandler.javabase/src/main/java/com/flowingcode/vaadin/addons/DevSourceRequestHandlerInitializer.javabase/src/main/java/com/flowingcode/vaadin/addons/GithubBranch.javabase/src/main/java/com/flowingcode/vaadin/addons/GithubLink.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/ColorScheme.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/DefaultSourceUrlResolver.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/DemoHelper.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/DemoHelperRenderer.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/DemoHelperViewer.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSource.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceConditionHelper.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSources.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/DialogDemoHelperViewer.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/DynamicTheme.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/DynamicThemeInitializer.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/EnhancedRouteTabs.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/MultiSourceCodeViewer.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/SourceCodeTab.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/SourceCodeViewer.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/SourcePosition.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/SourceUrlResolver.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemoSourceEvent.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/ThemeChangeEvent.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/ThemeChangeObserver.javabase/src/main/java/com/flowingcode/vaadin/addons/demo/VaadinVersion.javabase/src/main/resources/META-INF/VAADIN/package.propertiesbase/src/main/resources/META-INF/resources/frontend/code-viewer.tsbase/src/main/resources/META-INF/resources/frontend/prism.jsbase/src/main/resources/META-INF/resources/frontend/styles/commons-demo/shared-styles.cssbase/src/main/resources/META-INF/resources/frontend/styles/commons-demo/vaadin-select-overlay.cssbase/src/main/resources/META-INF/services/com.vaadin.flow.server.VaadinServiceInitListenerbase/src/test/java/com/flowingcode/vaadin/addons/demo/AdHocDemo.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/AdHocSource.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/AdditionalSources.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/AppShellConfiguratorImpl.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/Demo.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/MultiSourceDemo.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/SampleDemo.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/SampleDemoDefault.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/SampleDemoHelperRenderer.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/SampleDemoHighlight.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/SourcePositionDemo.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/it/AbstractSourceCodeViewerIT.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/it/AbstractViewTest.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/it/ConditionalSourceCodeViewerIT.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/it/SourceCodeViewerElement.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/it/SourceCodeViewerIT.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/it/SourceCodeViewerView.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/it/TabbedDemoView.javabase/src/test/java/com/flowingcode/vaadin/addons/demo/it/TabbedDemoViewIT.javabase/src/test/resources/META-INF/resources/frontend/condition-false.cssbase/src/test/resources/META-INF/resources/frontend/condition-true.cssbase/src/test/resources/META-INF/resources/frontend/highlight-demo.cssbase/src/test/resources/META-INF/resources/frontend/multi-source-demo.cssbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/AnnotationCleanup.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/AnnotationCleanup.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/CleanupOverride.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/CleanupOverride.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionElif.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionElif.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionElse.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionElse.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionEq.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionEq.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionGe.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionGe.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionGt.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionGt.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionLe.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionLe.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionLt.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionLt.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionNe.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionNe.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionNested.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionNested.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionUnknownVariable.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ConditionUnknownVariable.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/HideSource.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/HideSource.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/LicenseCleanup.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/LicenseCleanup.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/PackageCleanup.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/PackageCleanup.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ShowSource.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/ShowSource.txtbase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/SimpleSource.javabase/src/test/resources/com/flowingcode/vaadin/addons/demo/it/SimpleSource.txtpom.xmlprocessor/pom.xmlprocessor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.javaprocessor/src/main/resources/META-INF/services/javax.annotation.processing.Processor
| package-lock.json | ||
| package.json |
There was a problem hiding this comment.
Do not ignore dependency manifests needed for reproducible frontend builds.
At Line 8 and Line 9, ignoring package-lock.json and package.json can hide dependency changes and make installs non-reproducible across environments.
Suggested change
-package-lock.json
-package.json📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| package-lock.json | |
| package.json |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@base/.gitignore` around lines 8 - 9, Remove package.json and
package-lock.json from the ignore list so dependency manifests are tracked;
update .gitignore by deleting the lines containing "package.json" and
"package-lock.json" (or comment them out) to ensure dependency changes and
reproducible installs are committed.
There was a problem hiding this comment.
Since it's a library, the installs do not require building a bundle. package-lock-json and package.json are only produced when running the demo locally, and it was decided that we will not version them (see https://github.com/FlowingCode/AddonStarter24/blob/master/.gitignore)
There was a problem hiding this comment.
@javier-godoy, understood — thank you for the clarification. This is indeed consistent with the established convention for FlowingCode addon libraries; library maintainers should not include dependency lock files, and since package.json/package-lock.json are only generated transiently when running the demo locally, excluding them from version control is the right call. I'll withdraw my concern.
(´• ω •`) 🐇✨
✏️ Learnings added
Learnt from: javier-godoy
Repo: FlowingCode/CommonsDemo PR: 155
File: base/.gitignore:8-9
Timestamp: 2026-04-07T11:28:19.677Z
Learning: In FlowingCode addon library projects (e.g., CommonsDemo, AddonStarter24), `package.json` and `package-lock.json` are intentionally listed in `.gitignore` because they are only generated transiently when running the demo locally. These files are not versioned as a deliberate project-wide convention. Do not flag their omission from version control as an issue.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
| private static Object getRawValue( | ||
| Map<? extends ExecutableElement, ? extends AnnotationValue> values, String name) { | ||
| for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : | ||
| values.entrySet()) { | ||
| if (entry.getKey().getSimpleName().contentEquals(name)) { | ||
| return entry.getValue().getValue(); | ||
| } | ||
| } | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Potential NullPointerException if annotation element not found.
getRawValue returns null if the element name is not found, and callers like getStringValue cast this directly. While getElementValuesWithDefaults should always include defaults, defensive null handling would be safer.
🛡️ Suggested defensive approach
private static String getStringValue(
Map<? extends ExecutableElement, ? extends AnnotationValue> values, String name) {
- return (String) getRawValue(values, name);
+ Object raw = getRawValue(values, name);
+ return raw != null ? (String) raw : null;
}
private static TypeMirror getTypeValue(
Map<? extends ExecutableElement, ? extends AnnotationValue> values, String name) {
- return (TypeMirror) getRawValue(values, name);
+ Object raw = getRawValue(values, name);
+ return raw != null ? (TypeMirror) raw : null;
}Then add null checks in resolvePath or handle gracefully.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java`
around lines 161 - 170, getRawValue can return null when the annotation element
isn't found which leads to potential NPEs in callers like getStringValue and
resolvePath; change getRawValue to return java.util.Optional<Object> (update its
signature) and return Optional.ofNullable(entry.getValue().getValue()) /
Optional.empty() when not found, then update callers (e.g., getStringValue,
resolvePath) to handle the Optional (use orElse(null) or map/ifPresent as
appropriate) so no direct cast on a possibly-null value occurs.
There was a problem hiding this comment.
The finding does not hold up against the current code. Here's why:
- Casting null is safe in Java. (String) null and (TypeMirror) null both evaluate to null without throwing — there is no NPE at the cast site in getStringValue or getTypeValue.
getElementValuesWithDefaultsis used, notgetElementValues. The javadoc guarantees it returns all annotation elements including those with defaults, so for a structurally valid@DemoSourceannotation, neither "value" nor "clazz" will ever be absent from the map. getRawValue returning null is not a realistic outcome here.resolvePathis protected by the sentinel check. Even ifclazzMirrorwere somehow null, it's only passed toisSameTypeinsidehasClazz, which would be a problem — but again, point 2 makes this moot.
No fix needed. The suggestion to return Optional<Object> from getRawValue would add complexity without addressing a real defect.
There was a problem hiding this comment.
@javier-godoy, you're right on all three points — I apologize for the incorrect finding.
- Null cast safety: Casting
nullin Java is well-defined and safe —(String) nulland(TypeMirror) nullsimply evaluate tonullwith noClassCastExceptionorNullPointerExceptionat the cast site. getElementValuesWithDefaultsguarantee: The API contract ensures that the returned map includes all annotation elements, including those with defaults, so for any structurally valid@DemoSourceannotation,getRawValuewill always find"value"and"clazz".- Sentinel guard in
resolvePath: TheDemoSource.DEFAULT_VALUE.equals(value)check already provides adequate protection for the subsequent logic.
The Optional<Object> refactoring would have added complexity without addressing a real defect. No change needed.
✏️ Learnings added
Learnt from: javier-godoy
Repo: FlowingCode/CommonsDemo PR: 155
File: processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java:161-170
Timestamp: 2026-04-07T11:34:17.420Z
Learning: `javax.annotation.processing.Elements.getElementValuesWithDefaults(AnnotationMirror)` guarantees that the returned map includes all annotation elements, including those with default values. This means for any structurally valid annotation, all named elements will always be present in the map, making defensive "key not found" null-returns unrealistic for well-formed annotations.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java (1)
204-205: Avoid hardcoding Maven's default source roots inopenSourceFile().
SOURCE_PATHcan contain more thansrc/main/javaandsrc/test/java, but this helper only strips those two prefixes before lookup. That makes verbatim@DemoSource(value = "...")paths effectively layout-specific, even when javac already knows about another configured source root.Consider storing relative names and preserving the matched root instead of encoding fixed prefixes here.
Also applies to: 235-243
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java` around lines 204 - 205, openSourceFile() currently strips only the hardcoded SOURCE_ROOTS ("src/test/java/", "src/main/java/"), which breaks when SOURCE_PATH contains other configured source roots; update openSourceFile() (and the related logic at lines ~235-243) to iterate the actual SOURCE_PATH entries instead of SOURCE_ROOTS, detect which source-root prefix (from the compilation environment's SOURCE_PATH) matches the provided `@DemoSource` value, compute and store the relative path (preserve the matched root rather than removing a fixed prefix), and then look up the file under that matched root so verbatim `@DemoSource` paths work for any configured source root; adjust the SOURCE_ROOTS constant usage or remove it and ensure methods like openSourceFile() and wherever SOURCE_ROOTS is referenced use the dynamic SOURCE_PATH list.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java`:
- Around line 99-100: The code unconditionally adds whatever resolvePath returns
to collectedPaths and blindly casts member.getAnnotationValue(...).asElement()
to TypeElement; update resolvePath usage so that it returns null or Optional for
invalid paths and only add to collectedPaths when a valid non-empty path is
returned, and ensure resolvePath (or a helper) handles class literals safely by
checking Element returned from asElement() for null and instanceof TypeElement
before casting; for member types obtain the top-level declaring TypeElement
(e.g., walk up via getEnclosingElement() to the top-level TypeElement) and
produce the top-level .java path (Outer.java) instead of Inner.java, and when
encountering primitives/arrays/logical non-TypeElements emit the existing error
and skip adding to collectedPaths.
---
Nitpick comments:
In
`@processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java`:
- Around line 204-205: openSourceFile() currently strips only the hardcoded
SOURCE_ROOTS ("src/test/java/", "src/main/java/"), which breaks when SOURCE_PATH
contains other configured source roots; update openSourceFile() (and the related
logic at lines ~235-243) to iterate the actual SOURCE_PATH entries instead of
SOURCE_ROOTS, detect which source-root prefix (from the compilation
environment's SOURCE_PATH) matches the provided `@DemoSource` value, compute and
store the relative path (preserve the matched root rather than removing a fixed
prefix), and then look up the file under that matched root so verbatim
`@DemoSource` paths work for any configured source root; adjust the SOURCE_ROOTS
constant usage or remove it and ensure methods like openSourceFile() and
wherever SOURCE_ROOTS is referenced use the dynamic SOURCE_PATH list.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b630aba1-a1b1-483d-a658-bf0cfd45afc4
📒 Files selected for processing (1)
processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java
There was a problem hiding this comment.
♻️ Duplicate comments (1)
processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java (1)
162-175:⚠️ Potential issue | 🟠 MajorThe inner-class/path-resolution fix is still incomplete.
Line 173 still uses
annotatedClassdirectly, so@DemoSourceonOuter.Innerresolves tosrc/test/java/.../Outer/Inner.javainstead ofOuter.java. Line 165 also assumesTypes.asElement(clazzMirror)is always aTypeElement;int.classorString[].classmakes thatnull, so the processor blows up instead of reporting a diagnostic.🛠️ Suggested fix
+import javax.lang.model.element.PackageElement; + + private static TypeElement sourceOwner(TypeElement type) { + Element current = type; + while (!(current.getEnclosingElement() instanceof PackageElement)) { + current = current.getEnclosingElement(); + } + return (TypeElement) current; + } + private String resolvePath( TypeElement annotatedClass, AnnotationMirror annotation, TypeElement demoSourceType) { @@ - } else { - String className; + } else { + TypeElement sourceType; if (hasClazz) { - TypeElement clazzElement = - (TypeElement) processingEnv.getTypeUtils().asElement(clazzMirror); - // Walk up to the top-level type so that inner classes resolve to Outer.java - while (clazzElement.getEnclosingElement() instanceof TypeElement) { - clazzElement = (TypeElement) clazzElement.getEnclosingElement(); - } - className = clazzElement.getQualifiedName().toString().replace('.', '/'); + Element clazzElement = processingEnv.getTypeUtils().asElement(clazzMirror); + if (!(clazzElement instanceof TypeElement)) { + processingEnv + .getMessager() + .printMessage( + Diagnostic.Kind.ERROR, + "'clazz' must reference a declared type with a backing source file.", + annotatedClass, + annotation); + return null; + } + sourceType = sourceOwner((TypeElement) clazzElement); } else { // annotation.clazz() == DemoSource.class (sentinel default) - className = annotatedClass.getQualifiedName().toString().replace('.', '/'); + sourceType = sourceOwner(annotatedClass); } + String className = sourceType.getQualifiedName().toString().replace('.', '/'); return "src/test/java/" + className + ".java"; } }In the JDK annotation-processing API, does `javax.lang.model.util.Types.asElement(TypeMirror)` return `null` for primitive or array `TypeMirror`s, and should a nested `TypeElement` be mapped back to its top-level enclosing `.java` source file rather than `Outer/Inner.java`?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java` around lines 162 - 175, The code assumes processingEnv.getTypeUtils().asElement(clazzMirror) returns a TypeElement and also uses annotatedClass directly for the fallback, causing wrong path for inner classes and a crash on primitives/arrays; update the logic so that when hasClazz is true you check that asElement(clazzMirror) is non-null and an instance of TypeElement (otherwise emit a diagnostic via processingEnv.getMessager() that the provided clazz is not a declared type), and in both branches (when using the resolved clazzElement or when falling back to annotatedClass) walk up with getEnclosingElement() until you reach the top-level TypeElement before building className (so `@DemoSource` on Outer.Inner maps to Outer.java rather than Outer/Inner.java).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In
`@processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java`:
- Around line 162-175: The code assumes
processingEnv.getTypeUtils().asElement(clazzMirror) returns a TypeElement and
also uses annotatedClass directly for the fallback, causing wrong path for inner
classes and a crash on primitives/arrays; update the logic so that when hasClazz
is true you check that asElement(clazzMirror) is non-null and an instance of
TypeElement (otherwise emit a diagnostic via processingEnv.getMessager() that
the provided clazz is not a declared type), and in both branches (when using the
resolved clazzElement or when falling back to annotatedClass) walk up with
getEnclosingElement() until you reach the top-level TypeElement before building
className (so `@DemoSource` on Outer.Inner maps to Outer.java rather than
Outer/Inner.java).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: bc584ebb-504e-42ad-9e6a-52fcd5e8d998
📒 Files selected for processing (1)
processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java`:
- Around line 231-246: The loop in DemoSourceProcessor that opens and copies
collectedPaths can throw IllegalArgumentException from openSourceFile() or
processingEnv.getFiler().createResource() for invalid annotation paths; update
the try/catch around that logic (the block using openSourceFile(),
processingEnv.getFiler().createResource(), and in.transferTo(out)) to also
handle IllegalArgumentException (either via a separate catch or a multi-catch
with IOException) and emit a
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Failed to
copy " + sourcePath + ": " + e.getMessage()) so the processor reports a compiler
warning instead of letting IllegalArgumentException escape; reference the
DemoSourceProcessor class, the openSourceFile() helper, and the code that calls
processingEnv.getFiler().createResource().
- Around line 79-90: The code calls roundEnv.getElementsAnnotatedWith(...) using
TypeElement variables demoSourceType and demoSourcesType that may be null if
those annotation classes are not present; guard both lookups by checking
demoSourceType and demoSourcesType for null before calling
roundEnv.getElementsAnnotatedWith(...) (i.e., only call
roundEnv.getElementsAnnotatedWith(demoSourceType) when demoSourceType != null
and likewise for demoSourcesType) so the processor becomes a safe no-op when the
annotation types are absent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e6e62d2c-fb7b-436e-b2d6-687d68f42e9b
📒 Files selected for processing (1)
processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java
| TypeElement demoSourceType = | ||
| processingEnv | ||
| .getElementUtils() | ||
| .getTypeElement("com.flowingcode.vaadin.addons.demo.DemoSource"); | ||
| TypeElement demoSourcesType = | ||
| processingEnv | ||
| .getElementUtils() | ||
| .getTypeElement("com.flowingcode.vaadin.addons.demo.DemoSources"); | ||
|
|
||
| Set<Element> processed = new LinkedHashSet<>(); | ||
| processed.addAll(roundEnv.getElementsAnnotatedWith(demoSourceType)); | ||
| processed.addAll(roundEnv.getElementsAnnotatedWith(demoSourcesType)); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's examine the full context of the DemoSourceProcessor class
cat -n processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java | head -150Repository: FlowingCode/CommonsDemo
Length of output: 6697
🏁 Script executed:
# Let's also check if there's any null-checking or error handling around these calls
rg "getTypeElement|getElementsAnnotatedWith" processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java -B 3 -A 3Repository: FlowingCode/CommonsDemo
Length of output: 684
🌐 Web query:
javax.annotation.processing.Elements getTypeElement null return behavior
💡 Result:
Elements#getTypeElement(...) is specified to return null when the compiler’s element model can’t resolve the requested type.
What “null” means (per spec / Javadoc)
TypeElement getTypeElement(CharSequence name)returns “the named type element, ornullif it cannot be found.” [1]- In more recent JDKs, the lookup is defined in terms of whether the type is uniquely determinable in the environment; if not, it returns
null. [2] - Since Java 9 there is also
getTypeElement(ModuleElement module, CharSequence name), which returnsnullif it cannot be found from that module’s viewpoint (and the default impl returnsnull). [2]
Common reasons you’ll see null in annotation processing
- Wrong name: the parameter must be the type’s canonical name (e.g.,
com.example.Outer.Inner, not binaryOuter$Inner). [1][2] - Not on the compiler’s classpath/module-path: if the type isn’t available to the current compilation, it can’t be found →
null. [1] - It will exist only in a later round: if a processor generates a type, that type typically becomes available in a subsequent annotation-processing round (rounds continue while new sources are generated). [3][4]
- Module-related ambiguity / non-unique resolution: with modules, a canonical name may not identify a single visible type in the environment; in that case,
getTypeElement(name)can returnnull, and you may need the module overload to disambiguate. [2]
Practical tip: if you’re trying to resolve a type that might be generated during the same compilation, retry in later rounds (or defer work until the model is stable), rather than assuming getTypeElement will succeed in the current round. [3][4]
Sources: [1] Oracle Java SE 6 Elements Javadoc; [2] OpenJDK Elements Javadoc; [3] “Java Annotation Processing” slides (rounds); [4] Stack Overflow discussion of processing rounds / processingOver().
🌐 Web query:
javax.annotation.processing.RoundEnvironment getElementsAnnotatedWith null parameter behavior
💡 Result:
RoundEnvironment.getElementsAnnotatedWith(...) does not define any special behavior for a null argument. Passing null is therefore invalid, and you should expect a runtime failure (typically a NullPointerException from the underlying compiler implementation), not an “empty set” result.
What the API does specify is only:
- it returns an empty set when there are no matching elements for a valid annotation type, and
- it throws
IllegalArgumentExceptionif the argument does not represent an annotation type (but it does not mentionnull). [1]
Also note: the default implementations of getElementsAnnotatedWithAny(...) simply iterate and call getElementsAnnotatedWith(...) for each provided annotation type, so any null in those inputs will likewise tend to fail at runtime. [1]
Source
- Java SE
RoundEnvironmentJavadoc (method contracts, defaultgetElementsAnnotatedWithAnybehavior). (docs.oracle.com)
Citations:
Guard the annotation lookups before querying the round.
Elements#getTypeElement(...) returns null when the named annotation type is absent from the current compilation. In that case these getElementsAnnotatedWith(...) calls will fail immediately with a NullPointerException, which is especially easy to hit for an SPI-discovered processor. Add a null guard to make this a safe no-op when the marker types are unavailable.
🛡️ Proposed fix
TypeElement demoSourceType =
processingEnv
.getElementUtils()
.getTypeElement("com.flowingcode.vaadin.addons.demo.DemoSource");
TypeElement demoSourcesType =
processingEnv
.getElementUtils()
.getTypeElement("com.flowingcode.vaadin.addons.demo.DemoSources");
+
+ if (demoSourceType == null || demoSourcesType == null) {
+ return false;
+ }
Set<Element> processed = new LinkedHashSet<>();
processed.addAll(roundEnv.getElementsAnnotatedWith(demoSourceType));
processed.addAll(roundEnv.getElementsAnnotatedWith(demoSourcesType));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java`
around lines 79 - 90, The code calls roundEnv.getElementsAnnotatedWith(...)
using TypeElement variables demoSourceType and demoSourcesType that may be null
if those annotation classes are not present; guard both lookups by checking
demoSourceType and demoSourcesType for null before calling
roundEnv.getElementsAnnotatedWith(...) (i.e., only call
roundEnv.getElementsAnnotatedWith(demoSourceType) when demoSourceType != null
and likewise for demoSourcesType) so the processor becomes a safe no-op when the
annotation types are absent.
There was a problem hiding this comment.
@coderabbitai Why would the named annotation type be absent from the current compilation (the processor scans compiled classes, thus the annotation type must be present so that they compile)
There was a problem hiding this comment.
@javier-godoy, you're right. Since the annotated classes (@DemoSource, @DemoSources) must successfully compile before the processor runs, the annotation types are necessarily present on the classpath. If they were absent, the compilation of those annotated classes would fail first — the processor would never be reached. The null scenario from getTypeElement is not a realistic concern here. I apologize for the incorrect comment.
( ˘•ω•˘ ).。oO
✏️ Learnings added
Learnt from: javier-godoy
Repo: FlowingCode/CommonsDemo PR: 155
File: processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java:79-90
Timestamp: 2026-04-07T15:25:59.922Z
Learning: In `DemoSourceProcessor.java` (FlowingCode/CommonsDemo, processor module), calling `Elements#getTypeElement(...)` for `com.flowingcode.vaadin.addons.demo.DemoSource` and `com.flowingcode.vaadin.addons.demo.DemoSources` does NOT require a null guard. If those annotation types were absent from the classpath, the annotated classes would fail to compile before the processor is ever invoked, so the annotation types are guaranteed to be present whenever the processor runs. Do not flag a missing null guard for `getTypeElement` in this processor.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: javier-godoy
Repo: FlowingCode/CommonsDemo PR: 155
File: processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java:161-170
Timestamp: 2026-04-07T11:34:17.420Z
Learning: When using the annotation-processing API call `javax.annotation.processing.Elements#getElementValuesWithDefaults(AnnotationMirror)`, treat the returned map as including all annotation elements for a structurally valid annotation (including those supplied via default values). In code that handles well-formed annotations, avoid defensive logic that treats missing named keys as an expected “normal” case; instead, use the returned map to look up values directly. If you might receive invalid/unresolved annotations, keep validation for that broader input case, but don’t assume “key not found” is realistic for well-formed annotations when using `getElementValuesWithDefaults`.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java (1)
163-183: Consider using pattern matching forinstanceof(Java 16+).The static analysis tool flagged line 181, but this pattern appears in multiple places. Using pattern matching would eliminate redundant casts and improve readability.
♻️ Suggested pattern matching refactors
if (hasClazz) { Element clazzElement = processingEnv.getTypeUtils().asElement(clazzMirror); - if (!(clazzElement instanceof TypeElement)) { + if (!(clazzElement instanceof TypeElement typeElement)) { processingEnv .getMessager() .printMessage( Diagnostic.Kind.ERROR, "The 'clazz' element of `@DemoSource` must be a declared type.", annotatedClass, annotation); return null; } - typeElement = (TypeElement) clazzElement; } else { // annotation.clazz() == DemoSource.class (sentinel default) typeElement = annotatedClass; } // Walk up to the top-level type so that inner classes resolve to Outer.java - while (typeElement.getEnclosingElement() instanceof TypeElement) { - typeElement = (TypeElement) typeElement.getEnclosingElement(); + while (typeElement.getEnclosingElement() instanceof TypeElement enclosing) { + typeElement = enclosing; }Similarly at lines 92-96:
for (Element element : processed) { - if (!(element instanceof TypeElement)) { + if (!(element instanceof TypeElement annotatedClass)) { continue; } - TypeElement annotatedClass = (TypeElement) element;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java` around lines 163 - 183, The code in DemoSourceProcessor uses an instanceof check followed by a cast for clazzElement -> TypeElement; replace that pattern with Java pattern-matching instanceof to eliminate the redundant cast: change the check to use "instanceof TypeElement te" and assign typeElement = te in the true branch, keeping the current error path unchanged. Do the same refactor for other occurrences of the same pattern in this class (e.g., the earlier instanceof usage around the logic referenced at lines ~92-96) so all manual casts after instanceof are removed and readability is improved; ensure processingEnv.getMessager() error calls and the subsequent "Walk up to the top-level type" logic still reference the unified typeElement variable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java`:
- Around line 163-183: The code in DemoSourceProcessor uses an instanceof check
followed by a cast for clazzElement -> TypeElement; replace that pattern with
Java pattern-matching instanceof to eliminate the redundant cast: change the
check to use "instanceof TypeElement te" and assign typeElement = te in the true
branch, keeping the current error path unchanged. Do the same refactor for other
occurrences of the same pattern in this class (e.g., the earlier instanceof
usage around the logic referenced at lines ~92-96) so all manual casts after
instanceof are removed and readability is improved; ensure
processingEnv.getMessager() error calls and the subsequent "Walk up to the
top-level type" logic still reference the unified typeElement variable.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c646653c-a563-40cc-b14e-dfbccd18a29b
📒 Files selected for processing (1)
processor/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceProcessor.java
120e1f9 to
3544c78
Compare
|



commons-demo-processor— a new Maven module that embeds demo source files into the compiled JAR at build time.Problem
@DemoSource-annotated views need their.javasource files available at runtime soSourceCodeViewercan display them in the UI.Solution
An
AbstractProcessor-based annotation processor (DemoSourceProcessor) that runs duringjavaccompilation. It reads@DemoSourceannotations, resolves the referenced source paths, and copies each file intoCLASS_OUTPUT— so they land in the (demo) JAR automatically.Path resolution logic:
src/test/java/{ClassName}.javaof the annotated classclazz = Foo.classvalue = "some/path"Build integration:
META-INF/services/javax.annotation.processing.Processor(SPI) — no compiler plugin config needed in consuming projects-proc:noneto avoid bootstrapping issuesResult
Annotated demo classes get their source files bundled into the JAR, so that
SourceCodeViewercan load them from the classpath at runtime.Summary by CodeRabbit
Chores
New Features