Skip to content

Conversation

@timtebeek
Copy link
Member

Remove direct dependencies that are also brought in transitively by other direct dependencies.

Intended to be used when introducing spring boot starters to remove the direct dependencies they bring in.

timtebeek and others added 3 commits December 23, 2025 22:52
Adds a new recipe that removes direct dependencies which are already
provided transitively by another dependency matching a specified glob
pattern. Only removes when the transitive version exactly matches.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Instead of relying on the project's resolved dependency tree (which
merges direct dependencies), this downloads the parent dependency's
POM and resolves it independently. This allows detecting redundancies
even when both dependencies are explicitly declared.

Also fixes GAV comparison to ignore datedSnapshotVersion field.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
timtebeek and others added 3 commits December 24, 2025 13:50
Use specific Gradle configuration buckets instead of a single "all"
bucket, with getBroaderGradleScopes to find transitives from broader
configurations like api -> implementation.

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

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@steve-aom-elliott
Copy link
Contributor

steve-aom-elliott commented Dec 24, 2025

@timtebeek I'm thinking through how using this recipe in conjunction with other recipes that change dependencies may lead to undesirable situations.

Let's say we have a direct dependency W that has a transitive dependency on X, an we also have a direct dependency on X. If we run this recipe, it would presumably remove the direct dependency on X. If we follow that with something that perhaps upgrades W or changes it to Y and that new dependency no longer has a transitive dependency on X. We're potentially going to be in a situation where the code no longer compiles. I don't think we have a particularly generic way for determining that.

I understand we have plenty of ways to get to a similar situation already, though we would probably want to use this recipe rather sparingly as we can't always easily account for all the overlap.

If we only applied clearing out direct redundant dependencies based on those transitively available through our parent, that's a bit more of a focused scenario, at least, which sounds like could be a desired situation.

Still reading through all the code for this

EDIT: Ah, so I'm seeing that it's definitely for an intentioned removal of a specific dependency's transitives, so that alleviates some of the concern.

@steve-aom-elliott
Copy link
Contributor

Would it be worth adding a test example of something like:

...
<dependencies>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.0</version>
    <exclusions>
      <exclusion>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.17.0</version>
  </dependency>
</dependencies>
...

This may already be implicit due to it using the resolved POM, but could be a nice illustration of that fact.

…pe (transitive `compile`) and a currently failing test for an exclusion scenario.
…d POM's `requestedDependencies` based on the exclusions present on the dependency in our project POM
@github-project-automation github-project-automation bot moved this from In Progress to Ready to Review in OpenRewrite Dec 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Ready to Review

Development

Successfully merging this pull request may close these issues.

3 participants