Skip to content

Expand star imports in ChangePackage and related recipes when they would create ambiguity#7202

Open
steve-aom-elliott wants to merge 16 commits intomainfrom
fix/changepackage-ambiguous-star-imports
Open

Expand star imports in ChangePackage and related recipes when they would create ambiguity#7202
steve-aom-elliott wants to merge 16 commits intomainfrom
fix/changepackage-ambiguous-star-imports

Conversation

@steve-aom-elliott
Copy link
Copy Markdown
Contributor

@steve-aom-elliott steve-aom-elliott commented Mar 30, 2026

Summary

  • When ChangePackage renames a star import (e.g., import javax.validation.constraints.*import jakarta.validation.constraints.*), it now detects if the new package contains types whose simple names clash with types from other star imports (e.g., org.hibernate.validator.constraints.* also has NotBlank)
  • If ambiguity is detected, only the changed star import is expanded into explicit imports for the types actually referenced in the source, leaving other star imports untouched
  • Uses JavaSourceSet classpath to enumerate types in each package, then walks AST identifiers to determine which types are actually referenced
  • ChangeType now also detects when its target type is covered by a star import that would become ambiguous with another star import, and inserts an explicit import to disambiguate
  • ChangeDependencyGroupIdAndArtifactId (Maven) and AddDependency (Maven and Gradle) now update the JavaSourceSet marker when changing or adding dependencies, so downstream recipes like ChangePackage and ChangeType have accurate classpath data for ambiguity detection
  • JavaSourceSetUpdater.addDependency now tries the project's actual Maven repositories instead of hardcoding Maven Central, fixing failures in air-gapped environments or projects using private repositories
  • Shared withSourceTypesOnClasspath test helper extracted to Assertions.java for reuse across test classes

Test plan

  • changePackageExpandsStarImportWhenItWouldCreateAmbiguity — uses real javax.validation, jakarta.validation, and org.hibernate.validator types; verifies star import is expanded to explicit imports when another star import contains a type with the same simple name
  • changePackagePreservesStarImportWhenNoAmbiguity — verifies star import is preserved when no ambiguity exists
  • changeTypeAddsExplicitImportWhenStarImportsWouldBeAmbiguous — verifies ChangeType inserts an explicit import when two star imports would both provide the target type's simple name
  • composedWithChangePackageUpdatesImports — end-to-end test composing ChangeDependencyGroupIdAndArtifactId + ChangePackage to verify import renaming works when the JavaSourceSet is updated by the dependency change
  • Existing ChangePackageTest, ChangeTypeTest, and ChangeDependencyGroupIdAndArtifactIdTest suites pass

@github-project-automation github-project-automation bot moved this to In Progress in OpenRewrite Mar 30, 2026
@steve-aom-elliott steve-aom-elliott force-pushed the fix/changepackage-ambiguous-star-imports branch from a6ee247 to c7942f8 Compare March 30, 2026 18:22
@steve-aom-elliott steve-aom-elliott force-pushed the fix/changepackage-ambiguous-star-imports branch 4 times, most recently from e50f48f to 48f89f5 Compare April 7, 2026 19:57
@steve-aom-elliott steve-aom-elliott changed the title Expand star imports in ChangePackage when they would create ambiguity Expand star imports in ChangePackage and related recipes when they would create ambiguity Apr 7, 2026
@steve-aom-elliott steve-aom-elliott marked this pull request as ready for review April 7, 2026 20:55
@steve-aom-elliott steve-aom-elliott added bug Something isn't working enhancement New feature or request test provided Already replicated with a unit test, using JUnit pioneer's ExpectedToFail java maven gradle labels Apr 7, 2026
@steve-aom-elliott steve-aom-elliott moved this from In Progress to Ready to Review in OpenRewrite Apr 7, 2026
When ChangePackage renames a star import (e.g. import origpkg.* to
import newpkg.*), the new package may contain types whose simple names
clash with types from other star imports in the same file. This creates
ambiguous imports that fail to compile.

This change converts ChangePackage to a ScanningRecipe so it can first
collect which types exist in which packages across all source files,
then use that information to detect ambiguity. When a changed star
import would create ambiguity, it is expanded into explicit imports for
only the types actually used from that package.

Fixes moderneinc/customer-requests#1733
Move annotation interface definitions out of source specs and into
parser dependsOn, so the tests focus on the consumer file's import
behavior rather than asserting changes to the definition files.
Replace synthetic test packages with real javax/jakarta/hibernate validation
types from recipeDependencies. Use JavaSourceSet.build with classpath to
populate the source set marker. Switch from typesInUse to AST identifier
walking for collecting referenced types, since typesInUse does not include
annotation types resolved through star imports.
- Use javax.validation:validation-api:1.1 (no NotBlank), jakarta.validation-api:2.0.2,
  and org.hibernate:hibernate-validator:5.4.3 (has NotBlank) so @notblank unambiguously
  resolves from org.hibernate.validator.constraints
- Fix hasAmbiguity to also check the original (pre-rename) package on the classpath,
  since the classpath may not yet have types under the new package name
- Regenerate type table for updated parserClasspath versions
Use classpathFromResources + srcMainJava + addTypesToSourceSet instead of
manual JavaSourceSet.build and classpath. Move validation and hibernate
deps to testParserClasspath since they're only needed by ChangePackageTest.
When dependency recipes (ChangeDependency, AddDependency, RemoveDependency,
UpgradeDependencyVersion) modify a module's dependencies, the JavaSourceSet
marker on Java source files now reflects those changes. This allows downstream
recipes like ChangePackage to correctly detect ambiguous star imports that arise
from classpath changes.

Adds JavaSourceSetUpdater utility that downloads new dependency JARs and scans
them for types, then updates the JavaSourceSet's classpath and gavToTypes map.
All operations are idempotent to maintain single-cycle recipe stability.
…endency

AddDependency (both Maven and Gradle) was constructing a synthetic
ResolvedDependency with MavenRepository.MAVEN_CENTRAL hardcoded as the
repository. This would fail to download JARs in air-gapped environments
or when the dependency lives in a private repository.

Changed JavaSourceSetUpdater.addDependency to accept a list of
repositories and try each one until the JAR is found. The scanners now
capture the project's actual repositories during version resolution.
When ChangeType moves a type into a package covered by a star import,
and another star import provides a type with the same simple name,
add an explicit import to disambiguate. This mirrors the ambiguity
handling already present in ChangePackage.
…ntegration test

Move the withSourceTypesOnClasspath test helper from private methods in
ChangePackageTest and ChangeTypeTest to a public static method in
Assertions.java so it can be reused across test classes.

Add an end-to-end integration test in ChangeDependencyGroupIdAndArtifactIdTest
that composes ChangeDependencyGroupIdAndArtifactId with ChangePackage to verify
that import renaming works correctly when the JavaSourceSet is updated by the
dependency change recipe.
…rce set updates

- Attach Markup.warn to build files when version resolution for JavaSourceSet
  updates fails, so users know the classpath won't be updated
- Remove counter-productive G.CompilationUnit/K.CompilationUnit exclusion in
  Gradle AddDependency and ChangeDependency — Groovy/Kotlin source files can
  have JavaSourceSet markers; Gradle build files won't have one and are already
  filtered by the maybeSourceSet.isPresent() check
- Cache computed JavaSourceSet per source set in ChangeDependency (Gradle) and
  ChangeDependencyGroupIdAndArtifactId (Maven) to avoid redundant per-file
  recomputation when all files in a source set share identical markers
… ChangeDependency

Capture Maven repositories from GradleProject in the scanner and use
them when downloading JARs for JavaSourceSet updates, falling back to
Maven Central only if no remote repository is available. This matches
the approach already used in Maven ChangeDependencyGroupIdAndArtifactId
and both AddDependency recipes.
@steve-aom-elliott steve-aom-elliott force-pushed the fix/changepackage-ambiguous-star-imports branch from 7566269 to 7bc9f18 Compare April 9, 2026 13:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request gradle java maven test provided Already replicated with a unit test, using JUnit pioneer's ExpectedToFail

Projects

Status: Ready to Review

Development

Successfully merging this pull request may close these issues.

2 participants