diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java index b0386f040ba..689aa620031 100644 --- a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java +++ b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java @@ -48,6 +48,13 @@ public interface ClassRealmManager { */ ClassRealm getMavenApiRealm(); + /** + * Gets the class realm exposing the Maven 4 API. This is basically a restricted view on the Maven core realm. + * + * @return The class realm exposing the Maven API, never {@code null}. + */ + ClassRealm getMaven4ApiRealm(); + /** * Creates a new class realm for the specified project and its build extensions. * diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java index 512e7cae8f5..5d31bc025bd 100644 --- a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java +++ b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java @@ -24,14 +24,8 @@ import java.io.File; import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Random; -import java.util.Set; -import java.util.TreeMap; +import java.util.*; +import java.util.stream.Collectors; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.classrealm.ClassRealmRequest.RealmType; @@ -58,6 +52,8 @@ public class DefaultClassRealmManager implements ClassRealmManager { public static final String API_REALMID = "maven.api"; + public static final String API_V4_REALMID = "maven.api.v4"; + /** * During normal command line build, ClassWorld is loaded by jvm system classloader, which only includes * plexus-classworlds jar and possibly javaagent classes, see https://issues.apache.org/jira/browse/MNG-4747. @@ -79,12 +75,16 @@ public class DefaultClassRealmManager implements ClassRealmManager { private final ClassRealm mavenApiRealm; + private final ClassRealm maven4ApiRealm; + /** * Patterns of artifacts provided by maven core and exported via maven api realm. These artifacts are filtered from * plugin and build extensions realms to avoid presence of duplicate and possibly conflicting classes on classpath. */ private final Set providedArtifacts; + private final Set providedArtifactsV4; + @Inject public DefaultClassRealmManager( PlexusContainer container, List delegates, CoreExports exports) { @@ -102,7 +102,18 @@ public DefaultClassRealmManager( foreignImports, null /* artifacts */); + Map apiV4Imports = new HashMap<>(); + apiV4Imports.put("org.apache.maven.api", containerRealm); + apiV4Imports.put("org.slf4j", containerRealm); + apiV4Imports.put("jakarta.inject.*", containerRealm); + this.maven4ApiRealm = createRealm(API_V4_REALMID, RealmType.Core, null, null, apiV4Imports, null); + this.providedArtifacts = exports.getExportedArtifacts(); + + this.providedArtifactsV4 = providedArtifacts.stream() + .filter(ga -> + ga.startsWith("org.apache.maven:maven-api-") || ga.equals("jakarta.inject:jakarta.inject-api")) + .collect(Collectors.toSet()); } private ClassRealm newRealm(String id) { @@ -129,6 +140,11 @@ public ClassRealm getMavenApiRealm() { return mavenApiRealm; } + @Override + public ClassRealm getMaven4ApiRealm() { + return maven4ApiRealm; + } + /** * Creates a new class realm with the specified parent and imports. * @@ -151,8 +167,9 @@ private ClassRealm createRealm( List constituents = new ArrayList<>(artifacts == null ? 0 : artifacts.size()); if (artifacts != null && !artifacts.isEmpty()) { + boolean v4api = foreignImports != null && foreignImports.containsValue(maven4ApiRealm); for (Artifact artifact : artifacts) { - if (!isProvidedArtifact(artifact) && artifact.getFile() != null) { + if (!isProvidedArtifact(artifact, v4api) && artifact.getFile() != null) { constituents.add(new ArtifactClassRealmConstituent(artifact)); } else if (logger.isDebugEnabled()) { logger.debug(" Excluded: {}", getId(artifact)); @@ -212,8 +229,9 @@ public ClassRealm createExtensionRealm(Plugin plugin, List artifacts) getKey(plugin, true), RealmType.Extension, PARENT_CLASSLOADER, null, foreignImports, artifacts); } - private boolean isProvidedArtifact(Artifact artifact) { - return providedArtifacts.contains(artifact.getGroupId() + ":" + artifact.getArtifactId()); + private boolean isProvidedArtifact(Artifact artifact, boolean v4api) { + Set provided = v4api ? providedArtifactsV4 : providedArtifacts; + return provided.contains(artifact.getGroupId() + ":" + artifact.getArtifactId()); } public ClassRealm createPluginRealm( diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java index 6fa005b58a6..7ed0b211b57 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java @@ -348,7 +348,8 @@ public void setupPluginRealm( pluginDescriptor.setClassRealm(pluginRealm); pluginDescriptor.setArtifacts(pluginArtifacts); } else { - Map foreignImports = calcImports(project, parent, imports); + boolean v4api = pluginDescriptor.getMojos().stream().anyMatch(MojoDescriptor::isV4Api); + Map foreignImports = calcImports(project, parent, imports, v4api); PluginRealmCache.Key cacheKey = pluginRealmCache.createKey( plugin, @@ -480,14 +481,16 @@ private List toMavenArtifacts(DependencyNode root, PreorderNodeListGen return Collections.unmodifiableList(artifacts); } - private Map calcImports(MavenProject project, ClassLoader parent, List imports) { + private Map calcImports( + MavenProject project, ClassLoader parent, List imports, boolean v4api) { Map foreignImports = new HashMap<>(); ClassLoader projectRealm = project.getClassRealm(); if (projectRealm != null) { foreignImports.put("", projectRealm); } else { - foreignImports.put("", classRealmManager.getMavenApiRealm()); + foreignImports.put( + "", v4api ? classRealmManager.getMaven4ApiRealm() : classRealmManager.getMavenApiRealm()); } if (parent != null && imports != null) { diff --git a/maven-core/src/main/resources/META-INF/maven/extension.xml b/maven-core/src/main/resources/META-INF/maven/extension.xml index 1823336d837..2cb0bd188fd 100644 --- a/maven-core/src/main/resources/META-INF/maven/extension.xml +++ b/maven-core/src/main/resources/META-INF/maven/extension.xml @@ -143,7 +143,9 @@ under the License. org.apache.maven:maven-api-core org.apache.maven:maven-api-meta org.apache.maven:maven-api-model + org.apache.maven:maven-api-plugin org.apache.maven:maven-api-settings + org.apache.maven:maven-api-spi org.apache.maven:maven-api-toolchain org.apache.maven:maven-api-xml @@ -187,6 +189,7 @@ under the License. org.apache.maven.resolver:maven-resolver-util org.apache.maven.resolver:maven-resolver-connector-basic + jakarta.inject:jakarta.inject-api javax.inject:javax.inject javax.annotation:javax.annotation-api org.slf4j:slf4j-api