From 40fe1dc16726e77ae877345bde42816efcfb32e8 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 29 Aug 2024 17:32:53 +0200 Subject: [PATCH] [MNG-8220] Fix loading DI-powered beans from extensions (#1683) --- .../internal/impl/SisuDiBridgeModule.java | 72 +++++++++++-------- .../session/scope/internal/SessionScope.java | 3 +- .../main/java/org/apache/maven/di/Key.java | 13 +++- .../apache/maven/di/impl/InjectorImpl.java | 17 +++-- .../java/org/apache/maven/cli/MavenCli.java | 2 + 5 files changed, 65 insertions(+), 42 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/SisuDiBridgeModule.java b/maven-core/src/main/java/org/apache/maven/internal/impl/SisuDiBridgeModule.java index 30423b2c1025..ab12ee5b62d8 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/SisuDiBridgeModule.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/SisuDiBridgeModule.java @@ -55,13 +55,16 @@ import org.codehaus.plexus.component.repository.exception.ComponentLookupException; @Named -class SisuDiBridgeModule extends AbstractModule { +public class SisuDiBridgeModule extends AbstractModule { + + InjectorImpl injector; + final Set loaded = new HashSet<>(); @Override protected void configure() { Provider containerProvider = getProvider(PlexusContainer.class); - InjectorImpl injector = new InjectorImpl() { + injector = new InjectorImpl() { @Override public Supplier getCompiledBinding(Key key) { Set> res = getBindings(key); @@ -142,38 +145,12 @@ public Supplier getCompiledBinding(Key key) { }); injector.bindInstance(Injector.class, injector); bind(Injector.class).toInstance(injector); + bind(SisuDiBridgeModule.class).toInstance(this); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) { classLoader = getClass().getClassLoader(); } - try { - for (Iterator it = classLoader - .getResources("META-INF/maven/org.apache.maven.api.di.Inject") - .asIterator(); - it.hasNext(); ) { - URL url = it.next(); - List lines; - try (InputStream is = url.openStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { - lines = reader.lines() - .map(String::trim) - .filter(s -> !s.isEmpty() && !s.startsWith("#")) - .toList(); - } - for (String className : lines) { - try { - Class clazz = classLoader.loadClass(className); - injector.bindImplicit(clazz); - } catch (ClassNotFoundException e) { - // ignore - e.printStackTrace(); - } - } - } - - } catch (IOException e) { - throw new MavenException(e); - } + loadFromClassLoader(classLoader); injector.getBindings().keySet().stream() .filter(k -> k.getQualifier() != null) .sorted(Comparator.comparing(k -> k.getRawType().getName())) @@ -185,7 +162,7 @@ public Supplier getCompiledBinding(Key key) { : (Class) (clazz.getInterfaces().length > 0 ? clazz.getInterfaces()[0] : clazz)); if (itf != null) { AnnotatedBindingBuilder binder = bind(itf); - if (key.getQualifier() instanceof String s) { + if (key.getQualifier() instanceof String s && !s.isEmpty()) { binder.annotatedWith(Names.named(s)); } else if (key.getQualifier() instanceof Annotation a) { binder.annotatedWith(a); @@ -194,4 +171,37 @@ public Supplier getCompiledBinding(Key key) { } }); } + + public void loadFromClassLoader(ClassLoader classLoader) { + try { + for (Iterator it = classLoader + .getResources("META-INF/maven/org.apache.maven.api.di.Inject") + .asIterator(); + it.hasNext(); ) { + URL url = it.next(); + if (loaded.add(url.toExternalForm())) { + List lines; + try (InputStream is = url.openStream(); + BufferedReader reader = + new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { + lines = reader.lines() + .map(String::trim) + .filter(s -> !s.isEmpty() && !s.startsWith("#")) + .toList(); + } + for (String className : lines) { + try { + Class clazz = classLoader.loadClass(className); + injector.bindImplicit(clazz); + } catch (ClassNotFoundException e) { + // ignore + e.printStackTrace(); + } + } + } + } + } catch (IOException e) { + throw new MavenException(e); + } + } } diff --git a/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java b/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java index 71c2add405c3..284fafd6aea0 100644 --- a/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java +++ b/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java @@ -138,7 +138,8 @@ private Class[] getInterfaces(Class superType) { } else { for (Annotation a : superType.getAnnotations()) { Class annotationType = a.annotationType(); - if ("org.eclipse.sisu.Typed".equals(annotationType.getName()) + if ("org.apache.maven.api.di.Typed".equals(annotationType.getName()) + || "org.eclipse.sisu.Typed".equals(annotationType.getName()) || "javax.enterprise.inject.Typed".equals(annotationType.getName()) || "jakarta.enterprise.inject.Typed".equals(annotationType.getName())) { try { diff --git a/maven-di/src/main/java/org/apache/maven/di/Key.java b/maven-di/src/main/java/org/apache/maven/di/Key.java index d27882ae76cb..3e922bf0a4f5 100644 --- a/maven-di/src/main/java/org/apache/maven/di/Key.java +++ b/maven-di/src/main/java/org/apache/maven/di/Key.java @@ -128,8 +128,15 @@ public Key getTypeParameter(int index) { * and prepended qualifier display string if this key has a qualifier. */ public String getDisplayString() { - return (qualifier != null ? Utils.getDisplayString(qualifier) + " " : "") - + ReflectionUtils.getDisplayName(type); + return (qualifier != null ? getQualifierDisplayString() + " " : "") + ReflectionUtils.getDisplayName(type); + } + + private String getQualifierDisplayString() { + if (qualifier instanceof String s) { + return s.isEmpty() ? "@Named" : "@Named(\"" + s + "\")"; + } + String s = Utils.getDisplayString(qualifier); + return s; } @Override @@ -155,6 +162,6 @@ public int hashCode() { @Override public String toString() { - return (qualifier != null ? qualifier + " " : "") + type.getTypeName(); + return getDisplayString(); } } diff --git a/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java b/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java index 2edd74f9caef..c2c3de98dbe9 100644 --- a/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java +++ b/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java @@ -137,15 +137,18 @@ private Injector doBind(Key key, Binding binding) { current.add(key); throw new DIException("Circular references: " + current); } - doBindImplicit(key, binding); - Class cls = key.getRawType().getSuperclass(); - while (cls != Object.class && cls != null) { - key = Key.of(cls, key.getQualifier()); + try { doBindImplicit(key, binding); - cls = cls.getSuperclass(); + Class cls = key.getRawType().getSuperclass(); + while (cls != Object.class && cls != null) { + key = Key.of(cls, key.getQualifier()); + doBindImplicit(key, binding); + cls = cls.getSuperclass(); + } + return this; + } finally { + current.remove(key); } - current.remove(key); - return this; } protected Injector bind(Key key, Binding b) { diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java index b7db768555eb..bd958320b7e2 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java @@ -95,6 +95,7 @@ import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule; import org.apache.maven.extension.internal.CoreExports; import org.apache.maven.extension.internal.CoreExtensionEntry; +import org.apache.maven.internal.impl.SisuDiBridgeModule; import org.apache.maven.jline.JLineMessageBuilderFactory; import org.apache.maven.jline.MessageUtils; import org.apache.maven.lifecycle.LifecycleExecutionException; @@ -715,6 +716,7 @@ public Object getValue(String expression) { new SessionScopeModule(container.lookup(SessionScope.class)), new MojoExecutionScopeModule(container.lookup(MojoExecutionScope.class)), new ExtensionConfigurationModule(extension, extensionSource)); + container.lookup(SisuDiBridgeModule.class).loadFromClassLoader(extension.getClassRealm()); } customizeContainer(container);