Details
-
Bug
-
Status: Open
-
Major
-
Resolution: Unresolved
-
None
-
None
-
None
Description
We have a Maven core extension (https://search.maven.org/artifact/com.gradle/gradle-enterprise-maven-extension/1.5/jar) that declares two packages as exported in its META-INF/maven/extension.xml:
<?xml version="1.0" encoding="UTF-8"?> <extension> <exportedPackages> <exportedPackage>com.gradle.maven.extension.api.scan</exportedPackage> <exportedPackage>com.gradle.maven.mojo</exportedPackage> </exportedPackages> <exportedArtifacts> <exportedArtifact>com.gradle:gradle-enterprise-maven-extension</exportedArtifact> </exportedArtifacts> </extension>
The first package (com.gradle.maven.extension.api.scan) contains a BuildScanApi interface for which the extension registers a component in an EventSpy at runtime.
We would now like to consume that component in another core extension (let's call it consuming-extension) that has a provided dependency to com.gradle:gradle-enterprise-maven-extension like this:
BuildScanApi buildScan = (BuildScanApi) session.lookup("com.gradle.maven.extension.api.scan.BuildScanApi");
However, whether that works depends on how the core extensions are registered. Relevant for us are the following registration locations: <maven-home>/lib/ext, -Dmaven.ext.class.path, and .mvn/extensions.xml.
consuming-extension | gradle-enterprise-maven-extension | Result |
---|---|---|
<maven-home>/lib/ext | <maven-home>/lib/ext | |
.mvn/extensions.xml | <maven-home>/lib/ext | |
-Dmaven.ext.class.path | <maven-home>/lib/ext | |
<maven-home>/lib/ext | .mvn/extensions.xml | NoClassDefFoundError |
.mvn/extensions.xml | .mvn/extensions.xml | NoClassDefFoundError |
-Dmaven.ext.class.path | .mvn/extensions.xml | |
<maven-home>/lib/ext | -Dmaven.ext.class.path | NoClassDefFoundError |
.mvn/extensions.xml | -Dmaven.ext.class.path | NoClassDefFoundError |
-Dmaven.ext.class.path | -Dmaven.ext.class.path |
With this workaround, I was able to get it working in all cases:
ClassRealm extensionRealm = (ClassRealm) this.getClass().getClassLoader(); if (!"maven.ext".equals(extensionRealm.getId())) { extensionRealm.getWorld().getRealms().stream() .filter(realm -> realm.getId().startsWith("coreExtension>com.gradle:gradle-enterprise-maven-extension:") || realm.getId().equals("maven.ext")) .max(comparing((ClassRealm realm) -> realm.getId().length())) .ifPresent(realm -> { try { extensionRealm.importFrom(realm.getId(), "com.gradle.maven.extension.api.scan"); } catch (Exception e) { throw new RuntimeException("Could not import package from realm", e); } }); }
Please let me know if I have misunderstood the intention of declaring exported packages in extension.xml. I was unable to find documentation on it, unfortunately.