Skip to content

Conversation

@ascheman
Copy link
Contributor

@ascheman ascheman commented Jan 7, 2026

Summary

  • Replace boolean flags (hasMain, hasTest, hasMainResources, etc.) with flexible set-based tracking using SourceHandlingContext
  • Rename ResourceHandlingContext to SourceHandlingContext to reflect unified handling of all source types
  • Add duplicate detection: first enabled source wins, duplicates trigger WARNING
  • Add hasSources(Language, ProjectScope) method for checking source existence
  • Replace Collectors.toList() with .toList() (Java 17+ idiom)

Closes #11612 (Phase 2: build-sources-validation)

Test plan

  • ProjectBuilderTest passes (19 tests)
  • New tests added:
    • testModularSourcesInjectResourceRoots - verifies module-aware resource injection
    • testModularSourcesWithExplicitResourcesIssuesWarning - verifies legacy resource warnings
    • testMixedSourcesModularMainClassicTest - mixed modular/classic configuration
    • testSourcesMixedModulesWithinSources - mixed modules within <sources>
    • testMultipleDirectoriesSameModule - multiple directories per module
    • testDuplicateEnabledSources - duplicate detection with WARNING

🤖 Generated with Claude Code

private final Set<String> modules;
private final boolean modularProject;
private final ModelBuilderResult result;
private final Set<SourceKey> declaredSources = new HashSet<>();
Copy link
Contributor

Choose a reason for hiding this comment

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

It is a very minor details, but moving this initialization inside the constructor would allow to specify an initial capacity as new HashSet<>(4 * modules.size()) (assuming that each module is likely to have a main, a test, main resources and test resources).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in commit 63d43d5. Moved initialization to constructor with initial capacity.

boolean shouldAddSource(SourceRoot sourceRoot) {
if (!sourceRoot.enabled()) {
// Disabled sources are always added - they're filtered out by getEnabledSourceRoots()
LOGGER.debug(
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this one be at the trace level?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in commit 63d43d5. Changed from DEBUG to TRACE level.

}

SourceKey key = new SourceKey(
sourceRoot.language(), sourceRoot.scope(), sourceRoot.module().orElse(null), sourceRoot.directory());
Copy link
Contributor

Choose a reason for hiding this comment

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

We may consider adding .toRealPath() after directory() for making the test more exhaustive.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Used .toAbsolutePath().normalize() instead in commit 63d43d5.

toRealPath() requires the file to exist on the filesystem and throws IOException if it doesn't, which would break duplicate detection for source directories that don't exist yet. The normalize() approach handles relative paths and .. components without requiring filesystem access.

<lang>java</lang>
<module>org.foo.moduleB</module>
</source>
<!-- No test sources defined - testSourceDirectory should be used -->
Copy link
Contributor

Choose a reason for hiding this comment

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

This is ambiguous: how could a single testSourceDirectory be used for two modules? I suggest to allow <sourceDirectory> and <testSourceDirectory> only for non-modular projects, and emit a warning or error for modular projects.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implemented in commit 63d43d5 as AC7: In modular projects, <sourceDirectory> and <testSourceDirectory> are now unconditionally ignored with a WARNING.

The test has been updated to verify this behavior - both legacy directories trigger warnings and are not used.

/**
* Tests mixed source configuration where:
* - Modular sources are defined for main Java (should override sourceDirectory)
* - Classic testSourceDirectory is used (should be preserved since no modular test sources)
Copy link
Contributor

Choose a reason for hiding this comment

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

See comment in mixed-sources: this is ambiguous if we have more than one module. I suggest to modify the test for verifying that <testSourceDirectory> has been ignored and a warning emitted.

Instead (maybe in a phase 3), for each module declared in a <source> with main scope but no test scope, generate automatically the <source> with test scope in a way similar to what is currently done for resources.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in commit 63d43d5. The test testMixedSourcesModularMainClassicTest() now verifies:

  • 2 warnings are emitted (one for <sourceDirectory>, one for <testSourceDirectory>)
  • Test sources are NOT added (0 test Java roots) because legacy <testSourceDirectory> is ignored

<lang>java</lang>
<module>org.foo.moduleA</module>
</source>
<!-- Non-modular source (no module attribute) -->
Copy link
Contributor

Choose a reason for hiding this comment

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

Should not be allowed. Either a project is fully modular or fully classic, but not a mix of both. The compiler plugin will not be able to handle that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implemented in commit 63d43d5 as AC6: Mixing modular (with module attribute) and classic (without module attribute) sources within <sources> now triggers an ERROR.

The test project comments and test method have been updated accordingly.

}

/**
* Tests mixed modular/non-modular sources within the same {@code <sources>} element.
Copy link
Contributor

Choose a reason for hiding this comment

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

See comment in sources-mixed-modules: a project can be fully modular or fully classic, but not a mix of both. An error should be emitted. In this case, I think that it should be an error rather than a warning, because the compiler plugin will not know what to do with such mixed project.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in commit 63d43d5. The validateNoMixedModularAndClassicSources() method now reports an ERROR (not a warning) for mixed configurations, as suggested.

The test testSourcesMixedModulesWithinSources() verifies that an ERROR is reported with the message "Mixed modular and classic sources detected".

ascheman and others added 4 commits January 13, 2026 20:43
Replace boolean flags (hasMain, hasTest, etc.) with flexible
set-based tracking for all language/scope combinations.
- Rename ResourceHandlingContext to SourceHandlingContext
- Add duplicate detection with WARNING for enabled sources
- Add hasSources() method for checking language/scope combinations
- Rename 'src' variable to 'sourceRoot' for clarity

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use Java 17+ Stream.toList() instead of Collectors.toList().

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Normalize path separators to forward slashes before comparing
directory paths in tests. On Windows, Path.toString() returns
backslashes, causing contains() checks with forward slashes to fail.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement validation rules for modular source handling (apache#11612):

- AC6: ERROR when mixing modular (with module) and classic (without
  module) sources within <sources>
- AC7: WARNING when legacy <sourceDirectory>/<testSourceDirectory>
  are used in modular projects (both explicit config and filesystem
  existence)

Changes:
- Add validateNoMixedModularAndClassicSources() to SourceHandlingContext
- Add warnIfExplicitLegacyDirectory() to DefaultProjectBuilder
- Update tests to verify AC6 and AC7 behavior
- Update test project comments to reflect correct behavior

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ascheman ascheman force-pushed the feature/11612-source-handling-context branch from 159d2ae to 63d43d5 Compare January 13, 2026 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unified source handling for all lang/scope combinations with modular sources (Phase 2)

2 participants