From 60df7672eb1fe5129e5cf520f9d1510e1e89d87e Mon Sep 17 00:00:00 2001 From: Alexander Bubenchikov Date: Thu, 16 Jul 2026 12:30:58 +0200 Subject: [PATCH] [IDEA-391550] maven: Support Maven 3.10.x (cherry picked from commit 1b361710f57c5f33773cb5a8b0f6ba3b159e37ca) IJ-CR-214363 GitOrigin-RevId: c64d8fcaa2f40d5ec2df2c7065d0f0baa2dceee6 --- .../embedder/CustomMaven3ArtifactFactory.java | 2 + .../maven/server/Maven3XServerEmbedder.java | 122 +++++++++++++++++- .../server/utils/Maven3XProjectResolver.java | 46 +++++-- .../server/Maven36ServerEmbedderImpl.java | 18 +++ .../CustomMaven36ArtifactResolver.java | 2 + 5 files changed, 172 insertions(+), 18 deletions(-) diff --git a/plugins/maven/maven3-server-common/src/org/jetbrains/idea/maven/server/embedder/CustomMaven3ArtifactFactory.java b/plugins/maven/maven3-server-common/src/org/jetbrains/idea/maven/server/embedder/CustomMaven3ArtifactFactory.java index fd18e9e7a2dc..bc605358e532 100644 --- a/plugins/maven/maven3-server-common/src/org/jetbrains/idea/maven/server/embedder/CustomMaven3ArtifactFactory.java +++ b/plugins/maven/maven3-server-common/src/org/jetbrains/idea/maven/server/embedder/CustomMaven3ArtifactFactory.java @@ -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"); diff --git a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3XServerEmbedder.java b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3XServerEmbedder.java index 5e482d614304..fc8992ee8283 100644 --- a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3XServerEmbedder.java +++ b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3XServerEmbedder.java @@ -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, 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, Object> overridesByRole) { + if (overridesByRole.isEmpty()) return; + + if (isJsr330Container()) { + registerRealmModule(overridesByRole); + } + else { + for (Map.Entry, Object> entry : overridesByRole.entrySet()) { + myContainer.addComponent(entry.getValue(), entry.getKey().getName()); + } + } + } + + private void registerRealmModule(@NotNull Map, Object> overridesByRole) { + Map, Object> sharedInjectorOverrides = new LinkedHashMap<>(); + for (Map.Entry, 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, 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, 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(); diff --git a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/utils/Maven3XProjectResolver.java b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/utils/Maven3XProjectResolver.java index 6fe16a21562c..660f8367dfb5 100644 --- a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/utils/Maven3XProjectResolver.java +++ b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/utils/Maven3XProjectResolver.java @@ -179,17 +179,13 @@ public class Maven3XProjectResolver { ArrayList 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 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 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; diff --git a/plugins/maven/maven36-server-impl/src/org/jetbrains/idea/maven/server/Maven36ServerEmbedderImpl.java b/plugins/maven/maven36-server-impl/src/org/jetbrains/idea/maven/server/Maven36ServerEmbedderImpl.java index b300a3e5b266..5f6fece3b5ce 100644 --- a/plugins/maven/maven36-server-impl/src/org/jetbrains/idea/maven/server/Maven36ServerEmbedderImpl.java +++ b/plugins/maven/maven36-server-impl/src/org/jetbrains/idea/maven/server/Maven36ServerEmbedderImpl.java @@ -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, 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; diff --git a/plugins/maven/maven36-server-impl/src/org/jetbrains/idea/maven/server/embedder/CustomMaven36ArtifactResolver.java b/plugins/maven/maven36-server-impl/src/org/jetbrains/idea/maven/server/embedder/CustomMaven36ArtifactResolver.java index 0b14c9dc6f7c..6496e1a02002 100644 --- a/plugins/maven/maven36-server-impl/src/org/jetbrains/idea/maven/server/embedder/CustomMaven36ArtifactResolver.java +++ b/plugins/maven/maven36-server-impl/src/org/jetbrains/idea/maven/server/embedder/CustomMaven36ArtifactResolver.java @@ -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 artifactCache = new ConcurrentHashMap<>();