Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions maven-core/src/main/resources/META-INF/maven/extension.xml
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,12 @@ under the License.
<exportedPackage>org.slf4j.helpers.*</exportedPackage>
<exportedPackage>org.slf4j.event.*</exportedPackage>

<!-- JAnsi -->
<exportedPackage>org.fusesource.jansi.*</exportedPackage>
<!-- JAnsi: maven-jline ships Ansi.java, forwarding ANSI calls to the already-initialized JLine terminal, for
backward compatibility with code (e.g. maven-shared-utils) still calling the JAnsi API. Named exactly,
not as org.fusesource.jansi.*, since Ansi is the only class maven-jline provides; any other class in
that package a plugin needs falls back to its own classpath (see ClassRealm#loadClassFromImport), so
this stays even though the jansi artifact itself is no longer exported below. -->
<exportedPackage>org.fusesource.jansi.Ansi</exportedPackage>
</exportedPackages>

<exportedArtifacts>
Expand Down Expand Up @@ -175,7 +179,6 @@ under the License.
<exportedArtifact>javax.inject:javax.inject</exportedArtifact>
<exportedArtifact>javax.annotation:javax.annotation-api</exportedArtifact>
<exportedArtifact>org.slf4j:slf4j-api</exportedArtifact>
<exportedArtifact>org.fusesource.jansi:jansi</exportedArtifact>

<!--
| We must also filter out the old Aether or NoClassDefFoundErrors will surface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,37 @@ public void testCompleteDescriptor() throws Exception {
assertEquals(Arrays.asList("a", "b", "c"), ed.getExportedPackages());
assertEquals(Arrays.asList("x", "y", "z"), ed.getExportedArtifacts());
}

/**
* maven-core's own {@code META-INF/maven/extension.xml} must not export an artifact that maven-core no longer
* actually bundles: a stale {@code exportedArtifact} entry causes
* {@link org.apache.maven.ArtifactFilterManager} to strip that dependency out of a plugin's own resolved
* classpath even though Maven core does not provide it, breaking any plugin that declares it directly (see
* #13726, jansi left exported as an artifact after the JAnsi-to-JLine migration removed the real dependency).
* <p>
* {@code exportedPackage} entries are a different, safer mechanism (a {@code ClassRealm} import with fallback
* to the plugin's own classpath for anything the import doesn't resolve, see
* {@code ClassRealm#loadClassFromImport}), so {@code org.fusesource.jansi.Ansi} staying there, named exactly
* rather than as the {@code org.fusesource.jansi.*} package, is intentional: maven-jline ships only that one
* compatibility class, forwarding to the already-initialized JLine terminal, and plugins that need other real
* jansi classes still get them from their own classpath.
*/
@Test
public void testCoreExtensionDescriptorHasNoStaleArtifactExports() throws Exception {
try (InputStream in =
getClass().getClassLoader().getResourceAsStream(builder.getExtensionDescriptorLocation())) {
assertNotNull(in, "maven-core's own extension descriptor must be on the test classpath");

ExtensionDescriptor ed = builder.build(in);

assertTrue(
ed.getExportedArtifacts().stream().noneMatch(a -> a.contains("jansi")),
"jansi is no longer a maven-core dependency and must not be exported as an artifact: "
+ ed.getExportedArtifacts());
assertTrue(
ed.getExportedPackages().contains("org.fusesource.jansi.Ansi"),
"the JAnsi compatibility shim export must stay, named exactly (not as the org.fusesource.jansi.*"
+ " package, which maven-jline does not fully provide): " + ed.getExportedPackages());
}
}
}
Loading