[IDEA-391550] maven: Support Maven 3.10.x

(cherry picked from commit 1b361710f57c5f33773cb5a8b0f6ba3b159e37ca)

IJ-CR-214363

GitOrigin-RevId: c64d8fcaa2f40d5ec2df2c7065d0f0baa2dceee6
This commit is contained in:
Alexander Bubenchikov
2026-07-21 16:39:32 +00:00
committed by intellij-monorepo-bot
parent dee6413c9d
commit 60df7672eb
5 changed files with 172 additions and 18 deletions
@@ -4,7 +4,9 @@ package org.jetbrains.idea.maven.server.embedder;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.DefaultArtifactFactory;
import org.apache.maven.artifact.versioning.VersionRange;
import org.eclipse.sisu.Priority;
@Priority(Integer.MAX_VALUE)
public class CustomMaven3ArtifactFactory extends DefaultArtifactFactory {
private static final VersionRange UNKNOWN_VERSION_RANGE = VersionRange.createFromVersion("unknown");
@@ -1,6 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.maven.server;
import com.google.inject.AbstractModule;
import com.intellij.maven.server.telemetry.MavenServerOpenTelemetry;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtilRt;
@@ -60,6 +61,9 @@ import org.apache.maven.settings.building.SettingsBuilder;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.logging.BaseLoggerManager;
import org.codehaus.plexus.logging.Logger;
@@ -101,6 +105,8 @@ import org.jetbrains.idea.maven.server.utils.Maven3SettingsBuilder;
import org.jetbrains.idea.maven.server.utils.Maven3XProjectResolver;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -112,6 +118,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -135,6 +142,7 @@ import java.util.Set;
* org.jetbrains.idea.maven.server.embedder.CustomMaven3ModelInterpolator2 <-> org.apache.maven.model.interpolation.StringSearchModelInterpolator
* org.jetbrains.idea.maven.server.embedder.CustomModelValidator <-> org.apache.maven.model.validation.ModelValidator
*/
@SuppressWarnings("ClassOverriddenAtRuntime")
public abstract class Maven3XServerEmbedder extends Maven3ServerEmbedder {
private final @NotNull DefaultPlexusContainer myContainer;
@@ -153,6 +161,10 @@ public abstract class Maven3XServerEmbedder extends Maven3ServerEmbedder {
protected final @NotNull MavenEmbedderSettings myEmbedderSettings;
private static final String MAVEN_JSR330_VERSION = "3.10.0-rc-1";
private boolean myComponentsRegistered;
public Maven3XServerEmbedder(MavenEmbedderSettings settings) {
super(settings.getSettings());
@@ -425,13 +437,7 @@ public abstract class Maven3XServerEmbedder extends Maven3ServerEmbedder {
protected void customizeComponents(@Nullable MavenWorkspaceMap workspaceMap) {
try {
// replace some plexus components
if (VersionComparatorUtil.compare("3.7.0-SNAPSHOT", getMavenVersion()) < 0) {
myContainer.addComponent(getComponent(ArtifactFactory.class, "ide"), ArtifactFactory.ROLE);
}
myContainer.addComponent(getComponent(ArtifactResolver.class, "ide"), ArtifactResolver.ROLE);
myContainer.addComponent(getComponent(RepositoryMetadataManager.class, "ide"), RepositoryMetadataManager.class.getName());
myContainer.addComponent(getComponent(PluginDescriptorCache.class, "ide"), PluginDescriptorCache.class.getName());
registerCustomComponents();
ModelInterpolator modelInterpolator = createAndPutInterpolator(myContainer);
ModelValidator modelValidator;
@@ -476,6 +482,108 @@ public abstract class Maven3XServerEmbedder extends Maven3ServerEmbedder {
}
}
private void registerCustomComponents() {
if (myComponentsRegistered) return;
myComponentsRegistered = true;
Map<Class<?>, Object> overridesByRole = new LinkedHashMap<>();
// replace some plexus components
if (VersionComparatorUtil.compare("3.7.0-SNAPSHOT", getMavenVersion()) < 0) {
overridesByRole.put(ArtifactFactory.class, getComponent(ArtifactFactory.class, "ide"));
}
overridesByRole.put(ArtifactResolver.class, getComponent(ArtifactResolver.class, "ide"));
overridesByRole.put(RepositoryMetadataManager.class, getComponent(RepositoryMetadataManager.class, "ide"));
overridesByRole.put(PluginDescriptorCache.class, getComponent(PluginDescriptorCache.class, "ide"));
registerComponents(overridesByRole);
}
private void registerComponents(@NotNull Map<Class<?>, Object> overridesByRole) {
if (overridesByRole.isEmpty()) return;
if (isJsr330Container()) {
registerRealmModule(overridesByRole);
}
else {
for (Map.Entry<Class<?>, Object> entry : overridesByRole.entrySet()) {
myContainer.addComponent(entry.getValue(), entry.getKey().getName());
}
}
}
private void registerRealmModule(@NotNull Map<Class<?>, Object> overridesByRole) {
Map<Class<?>, Object> sharedInjectorOverrides = new LinkedHashMap<>();
for (Map.Entry<Class<?>, Object> entry : overridesByRole.entrySet()) {
if (hasInjectedMembers(entry.getValue().getClass())) {
sharedInjectorOverrides.put(entry.getKey(), entry.getValue());
}
else {
myContainer.addComponent(entry.getValue(), entry.getKey().getName());
}
}
registerSharedInjectorOverrides("intellij-maven-ide-components", sharedInjectorOverrides);
}
protected void registerSharedInjectorOverrides(@NotNull String realmId, @NotNull Map<Class<?>, Object> overrides) {
if (overrides.isEmpty()) return;
ClassRealm realm = createComponentsRealm(realmId);
myContainer.discoverComponents(realm, new AbstractModule() {
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
protected void configure() {
for (Map.Entry<Class<?>, Object> entry : overrides.entrySet()) {
bind((Class)entry.getKey()).toInstance(entry.getValue());
}
}
});
}
private static boolean hasInjectedMembers(@NotNull Class<?> type) {
for (Class<?> c = type; c != null && c != Object.class; c = c.getSuperclass()) {
for (Field field : c.getDeclaredFields()) {
if (isInjectAnnotated(field)) return true;
}
for (Method method : c.getDeclaredMethods()) {
if (isInjectAnnotated(method)) return true;
}
}
return false;
}
private static boolean isInjectAnnotated(@NotNull AnnotatedElement element) {
for (Annotation annotation : element.getDeclaredAnnotations()) {
String name = annotation.annotationType().getName();
if (name.equals("javax.inject.Inject") ||
name.equals("jakarta.inject.Inject") ||
name.equals("com.google.inject.Inject")) {
return true;
}
}
return false;
}
protected boolean isJsr330Container() {
return VersionComparatorUtil.compare(getMavenVersion(), MAVEN_JSR330_VERSION) >= 0;
}
@SuppressWarnings("ClassOverriddenAtRuntime")
private @NotNull ClassRealm createComponentsRealm(@NotNull String realmId) {
try {
return myContainer.getContainerRealm().createChildRealm(realmId);
}
catch (DuplicateRealmException e) {
try {
return myContainer.getClassWorld().getRealm(realmId);
}
catch (NoSuchRealmException ex) {
throw new RuntimeException(ex);
}
}
}
private ModelInterpolator createAndPutInterpolator(DefaultPlexusContainer container) {
if (VersionComparatorUtil.compare(getMavenVersion(), "3.6.2") >= 0) {
org.apache.maven.model.path.DefaultPathTranslator pathTranslator = new org.apache.maven.model.path.DefaultPathTranslator();
@@ -179,17 +179,13 @@ public class Maven3XProjectResolver {
ArrayList<MavenServerExecutionResult> executionResults = new ArrayList<>();
try {
MavenSession mavenSession = myEmbedder.getComponent(LegacySupport.class).getSession();
RepositorySystemSession repositorySession = myEmbedder.getComponent(LegacySupport.class).getRepositorySession();
if (repositorySession instanceof DefaultRepositorySystemSession) {
DefaultRepositorySystemSession session = (DefaultRepositorySystemSession)repositorySession;
MavenServerConsoleIndicatorImpl indicator = myLongRunningTask.getIndicator();
myImporterSpy.setIndicator(indicator);
session.setTransferListener(new Maven3TransferListenerAdapter(indicator));
setupWorkspaceReader(session);
session.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true);
session.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true);
RepositorySystemSession rawSession = myEmbedder.getComponent(LegacySupport.class).getRepositorySession();
RepositorySystemSession repositorySession;
if (rawSession instanceof DefaultRepositorySystemSession) {
repositorySession = createRepositorySessionForMavenResolverV1((DefaultRepositorySystemSession)rawSession);
}
else {
repositorySession = createRepositorySessionForMavenResolverV2_x(request, rawSession);
}
List<ProjectBuildingResult> buildingResults = myTelemetry.callWithSpan("getProjectBuildingResults " + files.size(), () ->
@@ -266,6 +262,23 @@ public class Maven3XProjectResolver {
return executionResults;
}
private @NotNull RepositorySystemSession createRepositorySessionForMavenResolverV2_x(MavenExecutionRequest request, RepositorySystemSession rawSession) {
RepositorySystemSession repositorySession;
DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(rawSession);
customizeRepositorySession(session);
request.getProjectBuildingRequest().setRepositorySession(session);
repositorySession = session;
return repositorySession;
}
private @NotNull RepositorySystemSession createRepositorySessionForMavenResolverV1(DefaultRepositorySystemSession rawSession) {
RepositorySystemSession repositorySession;
DefaultRepositorySystemSession session = rawSession;
customizeRepositorySession(session);
repositorySession = session;
return repositorySession;
}
private boolean transitiveDependenciesChanged(@NotNull File pomFile,
String newDependencyHash,
Map<File, String> fileToNewDependencyHash) {
@@ -300,6 +313,17 @@ public class Maven3XProjectResolver {
return fileToNewDependencyHash;
}
private void customizeRepositorySession(@NotNull DefaultRepositorySystemSession session) {
MavenServerConsoleIndicatorImpl indicator = myLongRunningTask.getIndicator();
myImporterSpy.setIndicator(indicator);
session.setTransferListener(new Maven3TransferListenerAdapter(indicator));
setupWorkspaceReader(session);
session.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true);
session.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true);
}
protected void setupWorkspaceReader(DefaultRepositorySystemSession session) {
String mavenVersion = System.getProperty(MAVEN_EMBEDDER_VERSION);
if (VersionComparatorUtil.compare(mavenVersion, "3.3.1") < 0) return;
@@ -23,6 +23,8 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;
public class Maven36ServerEmbedderImpl extends Maven3XServerEmbedder {
@@ -32,6 +34,12 @@ public class Maven36ServerEmbedderImpl extends Maven3XServerEmbedder {
@Override
protected void customizeComponents(@Nullable MavenWorkspaceMap workspaceMap) {
if (isJsr330Container()) {
registerCustomArtifactResolverOverrideAsHigherPrioritySisuBeans();
super.customizeComponents(workspaceMap);
return;
}
super.customizeComponents(workspaceMap);
ArtifactResolver customResolver = createCustomArtifactResolver(workspaceMap);
@@ -102,6 +110,16 @@ public class Maven36ServerEmbedderImpl extends Maven3XServerEmbedder {
}
}
private void registerCustomArtifactResolverOverrideAsHigherPrioritySisuBeans() {
ArtifactResolver customResolver = createCustomArtifactResolver(null);
if (customResolver != null) {
Map<Class<?>, Object> override = new HashMap<>();
override.put(ArtifactResolver.class, customResolver);
registerSharedInjectorOverrides("intellij-maven-aether-resolver", override);
}
}
protected @Nullable ArtifactResolver createCustomArtifactResolver(@Nullable MavenWorkspaceMap workspaceMap) {
if (!myEmbedderSettings.useCustomDependenciesResolver()) {
return null;
@@ -6,6 +6,7 @@ import org.eclipse.aether.impl.ArtifactResolver;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.sisu.Priority;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.server.ParallelRunnerForServer;
@@ -15,6 +16,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Priority(Integer.MAX_VALUE)
public class CustomMaven36ArtifactResolver implements ArtifactResolver, Resetable {
private final ArtifactResolver myWrapee;
private final Map<ArtifactRequestData, ArtifactResultData> artifactCache = new ConcurrentHashMap<>();