Skip to content

Avoid duplicate dependencies in ChangeDependency#8129

Draft
timtebeek wants to merge 1 commit into
openrewrite:mainfrom
timtebeek:change-dependency-avoid-duplicates
Draft

Avoid duplicate dependencies in ChangeDependency#8129
timtebeek wants to merge 1 commit into
openrewrite:mainfrom
timtebeek:change-dependency-avoid-duplicates

Conversation

@timtebeek

@timtebeek timtebeek commented Jun 26, 2026

Copy link
Copy Markdown
Member

What's changed

ChangeDependencyGroupIdAndArtifactId (the Maven engine behind org.openrewrite.java.dependencies.ChangeDependency) could produce a duplicate dependency: when the new coordinates were already declared directly at a lower version than the requested one, the recipe renamed the old declaration in place, leaving two declarations of the same dependency.

The recipe already removed the old declaration when the existing copy was at a version >= the requested one, but the version guard meant the lower-version case fell through to a rename and produced a duplicate.

This change:

  • Removes the old declaration whenever an existing direct dependency already declares the new coordinates, matched on full identity (groupId + artifactId + classifier + type + scope) — independent of version.
  • Upgrades the surviving declaration in place to the requested version pattern, reusing the recipe's existing version-resolution and managed-dependency handling.
  • Leaves declarations that differ on classifier, type, or scope untouched, since those are distinct dependencies.

Why

Concretely, migrating a POM that declares both jakarta.jws:jakarta.jws-api:3.0.0 and jakarta.xml.ws:jakarta.xml.ws-api:3.0.1 with ChangeDependency (jws-api → xml.ws-api, version 4.0.x) previously yielded two jakarta.xml.ws-api entries. It now drops jakarta.jws-api and upgrades the existing jakarta.xml.ws-api to 4.0.x — a single, correct entry.

Tests

  • Reworked shouldAddNewIfDependencyAlreadyExistsInOlderVersion (which asserted the duplicate) into shouldUpgradeExistingInPlaceIfDependencyAlreadyExistsInOlderVersion, asserting a single upgraded entry.
  • Added shouldNotLeaveDuplicateWhenExistingNewDependencyIsAtLowerVersion covering the jws/ws scenario.
  • Added shouldNotDeduplicateWhenClassifierDiffers confirming distinct coordinates are preserved.
  • Verified no regressions in ChangeManagedDependencyGroupIdAndArtifactIdTest and UpgradeDependencyVersionTest.

The Gradle ChangeDependency path is out of scope here, matching the Maven-only scope of the downstream compensation.

When the new coordinates were already declared directly and the existing
declaration was at a lower version than the requested one, the recipe renamed
the old dependency in place, producing two declarations of the same dependency.

Now the old declaration is removed whenever an existing direct dependency
already matches the new coordinates on groupId, artifactId, classifier, type,
and scope, and the surviving declaration is upgraded in place to the requested
version. Declarations that differ on classifier, type, or scope are left
untouched as distinct dependencies.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant