Skip to content

Link dependents of shaded reactor modules to the shaded JAR instead of target/classes - #145

Merged
tgodzik merged 2 commits into
scalacenter:mainfrom
jozanek:fix/shade-relocation-classpath
Jun 23, 2026
Merged

Link dependents of shaded reactor modules to the shaded JAR instead of target/classes#145
tgodzik merged 2 commits into
scalacenter:mainfrom
jozanek:fix/shade-relocation-classpath

Conversation

@jozanek

@jozanek jozanek commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Link dependents of shaded reactor modules to the shaded JAR instead of target/classes

Problem

A reactor module built by maven-shade-plugin (uber-jar / class relocation) keeps relocated classes only inside the shaded JAR, never in target/classes. But the plugin linked that module's dependents to target/classes, so they got an empty directory on their classpath and failed with cannot find symbol, cascading down the subtree (e.g. neo4j: lucene9-shadedlucene-index → the cypher Scala stack, ~16 modules).

Fixes scalameta/metals#3024.

Root cause

The stale target/classes reached dependents through two paths: the explicit reactor-dependency list (build.getOutputDirectory()) and Maven's resolved classpath elements. A third, subtler leak: a shaded module left as a Bloop project dependency contributes its classesDir to the effective classpath through the dependency graph.

Fix (plugin-only; Bloop core / Metals just consume the emitted JSON)

  • Detect shaded reactor deps via an execution that binds the shade goal (not mere plugin presence), and locate the JAR honoring outputFile / finalName / shadedArtifactAttached. The module's GAV is never resolved from a repository (could wire a stale binary).
  • Substitute the shaded JAR for target/classes at both classpath entry points.
  • Drop the shaded module's main project dependency so its classesDir can't leak back via the dependency graph; a consumed test-jar name is preserved (shade replaces the main artifact, not the test-jar).

Behavior when the shaded JAR doesn't exist yet

bloopInstall runs at generate-resources, while shade binds to package. On a clean tree the shaded JAR legitimately may not exist yet. In that case the plugin warns loudly (naming the module, telling the user to mvn package) and falls back to the previous target/classes behavior, rather than failing the export or wiring an unrelated binary.

This keeps the plugin consistent with its existing architecture (cf. "Download only external dependencies in multi module Maven projects" — the plugin deliberately avoids invoking Maven tasks and resolving reactor artifacts to stay fast at an early lifecycle phase). Making the default export fully self-sufficient for shaded modules (triggering the shade goal during export) is a larger change best handled on the Metals/import side, and is intentionally out of scope here.

Known gaps (not blocking)

  • The outputFile / shadedArtifactAttached / shade-finalName branches and the shaded-module-with-consumed-test-jar path are correct by construction but not yet covered by dedicated fixtures (each needs its own packaged module).

@tgodzik tgodzik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM Don't know too much about the plugin, but it seems if the plugin is not present, nothing changes, so we should be to merge

@tgodzik
tgodzik force-pushed the fix/shade-relocation-classpath branch from 2b7fa57 to 7682937 Compare June 23, 2026 18:08
@tgodzik
tgodzik merged commit f4c382d into scalacenter:main Jun 23, 2026
4 checks passed
@jozanek
jozanek deleted the fix/shade-relocation-classpath branch June 23, 2026 21:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The extension for vscode doesn't work for a project which doesn't have build.sbt file

2 participants