diff --git a/maven-api-impl/pom.xml b/maven-api-impl/pom.xml
index 8cc4830f86..69b7355e57 100644
--- a/maven-api-impl/pom.xml
+++ b/maven-api-impl/pom.xml
@@ -71,6 +71,10 @@ under the License.
org.apache.maven
maven-api-settings
+
+ org.apache.maven
+ maven-di
+
org.apache.maven.resolver
maven-resolver-api
@@ -132,11 +136,6 @@ under the License.
org.assertj
assertj-core
-
- org.apache.maven
- maven-di
- test
-
org.apache.maven.resolver
maven-resolver-named-locks
diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/di/MojoExecutionScope.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/di/MojoExecutionScope.java
new file mode 100644
index 0000000000..2128db3ac0
--- /dev/null
+++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/di/MojoExecutionScope.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.di;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.di.Key;
+import org.apache.maven.di.Scope;
+import org.apache.maven.di.impl.DIException;
+
+/**
+ * MojoExecutionScope
+ */
+public class MojoExecutionScope implements Scope {
+
+ protected static final class ScopeState {
+ private final Map, Supplier>> seeded = new HashMap<>();
+
+ private final Map, Object> provided = new HashMap<>();
+
+ public void seed(Class clazz, Supplier value) {
+ seeded.put(Key.of(clazz), value);
+ }
+
+ public Collection provided() {
+ return provided.values();
+ }
+ }
+
+ private final ThreadLocal> values = new ThreadLocal<>();
+
+ public MojoExecutionScope() {}
+
+ public static Supplier seededKeySupplier(Class extends T> clazz) {
+ return () -> {
+ throw new IllegalStateException(
+ "No instance of " + clazz.getName() + " is bound to the mojo execution scope.");
+ };
+ }
+
+ public void enter() {
+ LinkedList stack = values.get();
+ if (stack == null) {
+ stack = new LinkedList<>();
+ values.set(stack);
+ }
+ stack.addFirst(new ScopeState());
+ }
+
+ protected ScopeState getScopeState() {
+ LinkedList stack = values.get();
+ if (stack == null || stack.isEmpty()) {
+ throw new IllegalStateException();
+ }
+ return stack.getFirst();
+ }
+
+ public void exit() {
+ final LinkedList stack = values.get();
+ if (stack == null || stack.isEmpty()) {
+ throw new IllegalStateException();
+ }
+ stack.removeFirst();
+ if (stack.isEmpty()) {
+ values.remove();
+ }
+ }
+
+ public void seed(Class clazz, Supplier value) {
+ getScopeState().seed(clazz, value);
+ }
+
+ public void seed(Class clazz, final T value) {
+ seed(clazz, (Supplier) () -> value);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nonnull
+ public Supplier scope(@Nonnull Key key, @Nonnull Supplier unscoped) {
+ return () -> {
+ LinkedList stack = values.get();
+ if (stack == null || stack.isEmpty()) {
+ throw new DIException("Cannot access " + key + " outside of a scoping block");
+ }
+
+ ScopeState state = stack.getFirst();
+
+ Supplier> seeded = state.seeded.get(key);
+
+ if (seeded != null) {
+ return (T) seeded.get();
+ }
+
+ T provided = (T) state.provided.get(key);
+ if (provided == null && unscoped != null) {
+ provided = unscoped.get();
+ state.provided.put(key, provided);
+ }
+
+ return provided;
+ };
+ }
+}
diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/di/OutOfScopeException.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/di/OutOfScopeException.java
new file mode 100644
index 0000000000..c437425415
--- /dev/null
+++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/di/OutOfScopeException.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.di;
+
+import org.apache.maven.di.impl.DIException;
+
+public class OutOfScopeException extends DIException {
+ public OutOfScopeException(String message) {
+ super(message);
+ }
+
+ public OutOfScopeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/di/SessionScope.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/di/SessionScope.java
new file mode 100644
index 0000000000..f1ebcc22fc
--- /dev/null
+++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/di/SessionScope.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.di;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import org.apache.maven.di.Key;
+import org.apache.maven.di.Scope;
+import org.apache.maven.di.impl.Types;
+
+public class SessionScope implements Scope {
+
+ /**
+ * ScopeState
+ */
+ protected static final class ScopeState {
+ private final Map, CachingProvider>> provided = new ConcurrentHashMap<>();
+
+ public void seed(Class clazz, Supplier value) {
+ provided.put(Key.of(clazz), new CachingProvider<>(value));
+ }
+
+ @SuppressWarnings("unchecked")
+ public Supplier scope(Key key, Supplier unscoped) {
+ Supplier> provider = provided.computeIfAbsent(key, k -> new CachingProvider<>(unscoped));
+ return (Supplier) provider;
+ }
+
+ public Collection> providers() {
+ return provided.values();
+ }
+ }
+
+ protected final List values = new CopyOnWriteArrayList<>();
+
+ public void enter() {
+ values.add(0, new ScopeState());
+ }
+
+ protected ScopeState getScopeState() {
+ if (values.isEmpty()) {
+ throw new OutOfScopeException("Cannot access session scope outside of a scoping block");
+ }
+ return values.get(0);
+ }
+
+ public void exit() {
+ if (values.isEmpty()) {
+ throw new IllegalStateException();
+ }
+ values.remove(0);
+ }
+
+ public void seed(Class clazz, Supplier value) {
+ getScopeState().seed(clazz, value);
+ }
+
+ public void seed(Class clazz, T value) {
+ seed(clazz, (Supplier) () -> value);
+ }
+
+ @Override
+ public Supplier scope(Key key, Supplier unscoped) {
+ // Lazy evaluating provider
+ return () -> {
+ if (values.isEmpty()) {
+ return createProxy(key, unscoped);
+ } else {
+ return getScopeState().scope(key, unscoped).get();
+ }
+ };
+ }
+
+ @SuppressWarnings("unchecked")
+ protected T createProxy(Key key, Supplier unscoped) {
+ InvocationHandler dispatcher = (proxy, method, args) -> dispatch(key, unscoped, method, args);
+ Class superType = (Class) Types.getRawType(key.getType());
+ Class>[] interfaces = getInterfaces(superType);
+ return (T) java.lang.reflect.Proxy.newProxyInstance(superType.getClassLoader(), interfaces, dispatcher);
+ }
+
+ protected Object dispatch(Key key, Supplier unscoped, Method method, Object[] args) throws Throwable {
+ method.setAccessible(true);
+ try {
+ return method.invoke(getScopeState().scope(key, unscoped).get(), args);
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ }
+
+ protected Class>[] getInterfaces(Class> superType) {
+ if (superType.isInterface()) {
+ return new Class>[] {superType};
+ } else {
+ for (Annotation a : superType.getAnnotations()) {
+ Class extends Annotation> annotationType = a.annotationType();
+ if (isTypeAnnotation(annotationType)) {
+ try {
+ Class>[] value =
+ (Class>[]) annotationType.getMethod("value").invoke(a);
+ if (value.length == 0) {
+ value = superType.getInterfaces();
+ }
+ List> nonInterfaces =
+ Stream.of(value).filter(c -> !c.isInterface()).toList();
+ if (!nonInterfaces.isEmpty()) {
+ throw new IllegalArgumentException(
+ "The Typed annotation must contain only interfaces but the following types are not: "
+ + nonInterfaces);
+ }
+ return value;
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+ throw new IllegalArgumentException("The use of session scoped proxies require "
+ + "a org.eclipse.sisu.Typed or javax.enterprise.inject.Typed annotation");
+ }
+ }
+
+ protected boolean isTypeAnnotation(Class extends Annotation> annotationType) {
+ return "org.apache.maven.api.di.Typed".equals(annotationType.getName());
+ }
+
+ /**
+ * A provider wrapping an existing provider with a cache
+ * @param the provided type
+ */
+ protected static class CachingProvider implements Supplier {
+ private final Supplier provider;
+ private volatile T value;
+
+ CachingProvider(Supplier provider) {
+ this.provider = provider;
+ }
+
+ public T value() {
+ return value;
+ }
+
+ @Override
+ public T get() {
+ if (value == null) {
+ synchronized (this) {
+ if (value == null) {
+ value = provider.get();
+ }
+ }
+ }
+ return value;
+ }
+ }
+
+ public static Supplier seededKeySupplier(Class extends T> clazz) {
+ return () -> {
+ throw new IllegalStateException("No instance of " + clazz.getName() + " is bound to the session scope.");
+ };
+ }
+}
diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java
index 1f141fbbbe..15a605ea20 100644
--- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java
+++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java
@@ -41,6 +41,7 @@ import org.apache.maven.api.Session;
import org.apache.maven.api.Type;
import org.apache.maven.api.Version;
import org.apache.maven.api.di.Provides;
+import org.apache.maven.api.di.SessionScoped;
import org.apache.maven.api.model.PluginContainer;
import org.apache.maven.api.model.Profile;
import org.apache.maven.api.services.ArtifactManager;
@@ -58,6 +59,7 @@ import org.apache.maven.di.Key;
import org.apache.maven.di.impl.DIException;
import org.apache.maven.internal.impl.AbstractSession;
import org.apache.maven.internal.impl.InternalSession;
+import org.apache.maven.internal.impl.di.SessionScope;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
@@ -75,7 +77,12 @@ public class ApiRunner {
injector.bindInstance(Injector.class, injector);
injector.bindImplicit(ApiRunner.class);
injector.discover(ApiRunner.class.getClassLoader());
- return injector.getInstance(Session.class);
+ Session session = injector.getInstance(Session.class);
+ SessionScope scope = new SessionScope();
+ scope.enter();
+ scope.seed(Session.class, session);
+ injector.bindScope(SessionScoped.class, scope);
+ return session;
}
static class DefaultSession extends AbstractSession {
diff --git a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java
index a9d9feb65f..1233557b37 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java
@@ -18,20 +18,13 @@
*/
package org.apache.maven.execution.scope.internal;
-import java.lang.annotation.Annotation;
import java.util.Collection;
-import java.util.HashMap;
import java.util.IdentityHashMap;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.function.Supplier;
import com.google.inject.Key;
-import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
import com.google.inject.Scope;
-import com.google.inject.name.Names;
-import com.google.inject.util.Providers;
+import com.google.inject.name.Named;
import org.apache.maven.execution.MojoExecutionEvent;
import org.apache.maven.execution.MojoExecutionListener;
import org.apache.maven.execution.scope.WeakMojoExecutionListener;
@@ -40,96 +33,22 @@ import org.apache.maven.plugin.MojoExecutionException;
/**
* MojoExecutionScope
*/
-public class MojoExecutionScope implements Scope, org.apache.maven.di.Scope, MojoExecutionListener {
- private static final Provider SEEDED_KEY_PROVIDER = () -> {
- throw new IllegalStateException();
- };
-
- private static final class ScopeState {
- private final Map, Provider>> seeded = new HashMap<>();
-
- private final Map, Object> provided = new HashMap<>();
- }
-
- private final ThreadLocal> values = new ThreadLocal<>();
-
- public MojoExecutionScope() {}
-
- public void enter() {
- LinkedList stack = values.get();
- if (stack == null) {
- stack = new LinkedList<>();
- values.set(stack);
- }
- stack.addFirst(new ScopeState());
- }
-
- private ScopeState getScopeState() {
- LinkedList stack = values.get();
- if (stack == null || stack.isEmpty()) {
- throw new IllegalStateException();
- }
- return stack.getFirst();
- }
-
- public void exit() throws MojoExecutionException {
- final LinkedList stack = values.get();
- if (stack == null || stack.isEmpty()) {
- throw new IllegalStateException();
- }
- stack.removeFirst();
- if (stack.isEmpty()) {
- values.remove();
- }
- }
+public class MojoExecutionScope extends org.apache.maven.internal.impl.di.MojoExecutionScope
+ implements Scope, MojoExecutionListener {
public void seed(Class clazz, Provider value) {
- getScopeState().seeded.put(Key.get(clazz), value);
+ getScopeState().seed(clazz, value::get);
}
- public void seed(Class clazz, final T value) {
- getScopeState().seeded.put(Key.get(clazz), Providers.of(value));
+ public Provider scope(final Key key, Provider unscoped) {
+ Object qualifier = key.getAnnotation() instanceof Named n ? n.value() : key.getAnnotation();
+ org.apache.maven.di.Key k =
+ org.apache.maven.di.Key.ofType(key.getTypeLiteral().getType(), qualifier);
+ return scope(k, unscoped::get)::get;
}
- public Provider scope(final Key key, final Provider unscoped) {
- return () -> {
- LinkedList stack = values.get();
- if (stack == null || stack.isEmpty()) {
- throw new OutOfScopeException("Cannot access " + key + " outside of a scoping block");
- }
-
- ScopeState state = stack.getFirst();
-
- Provider> seeded = state.seeded.get(key);
-
- if (seeded != null) {
- return (T) seeded.get();
- }
-
- T provided = (T) state.provided.get(key);
- if (provided == null && unscoped != null) {
- provided = unscoped.get();
- state.provided.put(key, provided);
- }
-
- return provided;
- };
- }
-
- @Override
- public Supplier scope(org.apache.maven.di.Key key, Annotation scope, Supplier unscoped) {
- Object qualifier = key.getQualifier();
- Key k = qualifier != null
- ? Key.get(key.getType(), qualifier instanceof String s ? Names.named(s) : (Annotation) qualifier)
- : Key.get(key.getType());
- Provider up = unscoped::get;
- Provider p = scope(k, up);
- return p::get;
- }
-
- @SuppressWarnings({"unchecked"})
- public static Provider seededKeyProvider() {
- return (Provider) SEEDED_KEY_PROVIDER;
+ public static Provider seededKeyProvider(Class extends T> clazz) {
+ return MojoExecutionScope.seededKeySupplier(clazz)::get;
}
public void beforeMojoExecution(MojoExecutionEvent event) throws MojoExecutionException {
@@ -154,7 +73,7 @@ public class MojoExecutionScope implements Scope, org.apache.maven.di.Scope, Moj
// the same instance can be provided multiple times under different Key's
// deduplicate instances to avoid redundant beforeXXX/afterXXX callbacks
IdentityHashMap listeners = new IdentityHashMap<>();
- for (Object provided : getScopeState().provided.values()) {
+ for (Object provided : getScopeState().provided()) {
if (provided instanceof WeakMojoExecutionListener) {
listeners.put((WeakMojoExecutionListener) provided, null);
}
diff --git a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeModule.java b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeModule.java
index 149b94f97c..a477ec868c 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeModule.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeModule.java
@@ -40,17 +40,19 @@ public class MojoExecutionScopeModule extends AbstractModule {
// bindScope(org.apache.maven.api.di.MojoExecutionScoped.class, scope);
bind(MojoExecutionScope.class).toInstance(scope);
bind(MavenProject.class)
- .toProvider(MojoExecutionScope.seededKeyProvider())
+ .toProvider(MojoExecutionScope.seededKeyProvider(MavenProject.class))
.in(scope);
bind(MojoExecution.class)
- .toProvider(MojoExecutionScope.seededKeyProvider())
+ .toProvider(MojoExecutionScope.seededKeyProvider(MojoExecution.class))
+ .in(scope);
+ bind(Log.class)
+ .toProvider(MojoExecutionScope.seededKeyProvider(Log.class))
.in(scope);
- bind(Log.class).toProvider(MojoExecutionScope.seededKeyProvider()).in(scope);
bind(org.apache.maven.api.Project.class)
- .toProvider(MojoExecutionScope.seededKeyProvider())
+ .toProvider(MojoExecutionScope.seededKeyProvider(org.apache.maven.api.Project.class))
.in(scope);
bind(org.apache.maven.api.MojoExecution.class)
- .toProvider(MojoExecutionScope.seededKeyProvider())
+ .toProvider(MojoExecutionScope.seededKeyProvider(org.apache.maven.api.MojoExecution.class))
.in(scope);
}
}
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 eb6789c12b..6cc9b49733 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
@@ -21,31 +21,27 @@ package org.apache.maven.internal.impl;
import javax.inject.Named;
import javax.inject.Provider;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
import java.lang.annotation.Annotation;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Iterator;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import com.google.inject.AbstractModule;
-import com.google.inject.binder.AnnotatedBindingBuilder;
+import com.google.inject.Binder;
import com.google.inject.name.Names;
+import com.google.inject.spi.ProviderInstanceBinding;
import org.apache.maven.api.di.MojoExecutionScoped;
import org.apache.maven.api.di.SessionScoped;
-import org.apache.maven.api.services.MavenException;
import org.apache.maven.di.Injector;
import org.apache.maven.di.Key;
+import org.apache.maven.di.Scope;
import org.apache.maven.di.impl.Binding;
import org.apache.maven.di.impl.DIException;
import org.apache.maven.di.impl.Dependency;
@@ -54,76 +50,147 @@ import org.apache.maven.execution.scope.internal.MojoExecutionScope;
import org.apache.maven.session.scope.internal.SessionScope;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.eclipse.sisu.BeanEntry;
+import org.eclipse.sisu.inject.BeanLocator;
@Named
public class SisuDiBridgeModule extends AbstractModule {
- InjectorImpl injector;
- final Set loaded = new HashSet<>();
+ protected final boolean discover;
+ protected InjectorImpl injector;
+
+ public SisuDiBridgeModule() {
+ this(true);
+ }
+
+ public SisuDiBridgeModule(boolean discover) {
+ this.discover = discover;
+ }
@Override
protected void configure() {
Provider containerProvider = getProvider(PlexusContainer.class);
+ Provider beanLocatorProvider = getProvider(BeanLocator.class);
+ injector = new BridgeInjectorImpl(beanLocatorProvider, binder());
+ bindScope(injector, containerProvider, SessionScoped.class, SessionScope.class);
+ bindScope(injector, containerProvider, MojoExecutionScoped.class, MojoExecutionScope.class);
+ 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();
+ }
+ if (discover) {
+ injector.discover(classLoader);
+ }
+ }
+
+ private void bindScope(
+ InjectorImpl injector,
+ Provider containerProvider,
+ Class extends Annotation> sa,
+ Class extends Scope> ss) {
+ injector.bindScope(sa, () -> {
+ try {
+ return containerProvider.get().lookup(ss);
+ } catch (ComponentLookupException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+
+ static class BridgeInjectorImpl extends InjectorImpl {
+ final Provider locator;
+ final Binder binder;
+
+ BridgeInjectorImpl(Provider locator, Binder binder) {
+ this.locator = locator;
+ this.binder = binder;
+ }
+
+ @Override
+ protected Injector bind(Key key, Binding binding) {
+ super.bind(key, binding);
+ if (key.getQualifier() != null) {
+ com.google.inject.Key k = toGuiceKey(key);
+ this.binder.bind(k).toProvider(new BridgeProvider<>(binding));
+ }
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static com.google.inject.Key toGuiceKey(Key key) {
+ if (key.getQualifier() instanceof String s) {
+ return (com.google.inject.Key) com.google.inject.Key.get(key.getType(), Names.named(s));
+ } else if (key.getQualifier() instanceof Annotation a) {
+ return (com.google.inject.Key) com.google.inject.Key.get(key.getType(), a);
+ } else {
+ return (com.google.inject.Key) com.google.inject.Key.get(key.getType());
+ }
+ }
+
+ static class BindingToBeanEntry extends Binding {
+ private BeanEntry beanEntry;
+
+ BindingToBeanEntry(Key elementType) {
+ super(elementType, Set.of());
+ }
+
+ public BindingToBeanEntry toBeanEntry(BeanEntry beanEntry) {
+ this.beanEntry = beanEntry;
+ return this;
+ }
- injector = new InjectorImpl() {
@Override
- public Supplier getCompiledBinding(Dependency dep) {
- Key key = dep.key();
- Set> res = getBindings(key);
- if (res != null && !res.isEmpty()) {
- List> bindingList = new ArrayList<>(res);
- Comparator> comparing = Comparator.comparing(Binding::getPriority);
- bindingList.sort(comparing.reversed());
- Binding binding = bindingList.get(0);
- return compile(binding);
- }
- if (key.getRawType() == List.class) {
- Set> res2 = getBindings(key.getTypeParameter(0));
- Set> res3 = res2 != null ? new HashSet<>(res2) : new HashSet<>();
- try {
- List l = containerProvider
- .get()
- .lookupList(key.getTypeParameter(0).getRawType());
- l.forEach(o -> res3.add(new Binding.BindingToInstance<>(o)));
- } catch (Throwable e) {
- // ignore
- e.printStackTrace();
- }
- List> list =
- res3.stream().map(this::compile).collect(Collectors.toList());
- //noinspection unchecked
- return () -> (Q) list(list);
- }
- if (key.getRawType() == Map.class) {
- Key> k = key.getTypeParameter(0);
- Key v = key.getTypeParameter(1);
- if (k.getRawType() == String.class) {
- Set> res2 = getBindings(v);
- Set> res3 = res2 != null ? new HashSet<>(res2) : new HashSet<>();
- Map> map = res3.stream()
- .filter(b -> b.getOriginalKey() == null
- || b.getOriginalKey().getQualifier() == null
- || b.getOriginalKey().getQualifier() instanceof String)
- .collect(Collectors.toMap(
- b -> (String)
- (b.getOriginalKey() != null
- ? b.getOriginalKey().getQualifier()
- : null),
- this::compile));
- //noinspection unchecked
- return () -> (Q) map(map);
- }
- }
- try {
- Q t = containerProvider.get().lookup(key.getRawType());
- return compile(new Binding.BindingToInstance<>(t));
- } catch (Throwable e) {
- // ignore
- e.printStackTrace();
- }
- if (dep.optional()) {
- return () -> null;
+ public Supplier compile(Function, Supplier>> compiler) {
+ return beanEntry.getProvider()::get;
+ }
+ }
+
+ class BridgeProvider implements Provider {
+ final Binding binding;
+
+ BridgeProvider(Binding binding) {
+ this.binding = binding;
+ }
+
+ @Override
+ public T get() {
+ return compile(binding).get();
+ }
+ }
+
+ @Override
+ public Supplier getCompiledBinding(Dependency dep) {
+ Key key = dep.key();
+ Class rawType = key.getRawType();
+ if (rawType == List.class) {
+ return getListSupplier(key);
+ } else if (rawType == Map.class) {
+ return getMapSupplier(key);
+ } else {
+ return getBeanSupplier(dep, key);
+ }
+ }
+
+ private Supplier getBeanSupplier(Dependency dep, Key key) {
+ List> list = new ArrayList<>();
+ // Add DI bindings
+ list.addAll(getBindings().getOrDefault(key, Set.of()));
+ // Add Plexus bindings
+ for (var bean : locator.get().locate(toGuiceKey(key))) {
+ if (isPlexusBean(bean)) {
+ list.add(new BindingToBeanEntry<>(key).toBeanEntry(bean));
}
+ }
+ if (!list.isEmpty()) {
+ list.sort(getBindingComparator());
+ //noinspection unchecked
+ return () -> (Q) getInstance(list.iterator().next());
+ } else if (dep.optional()) {
+ return () -> null;
+ } else {
throw new DIException("No binding to construct an instance for key "
+ key.getDisplayString() + ". Existing bindings:\n"
+ getBoundKeys().stream()
@@ -133,80 +200,78 @@ public class SisuDiBridgeModule extends AbstractModule {
.distinct()
.collect(Collectors.joining("\n - ", " - ", "")));
}
- };
- injector.bindScope(SessionScoped.class, () -> {
- try {
- return containerProvider.get().lookup(SessionScope.class);
- } catch (ComponentLookupException e) {
- throw new RuntimeException(e);
- }
- });
- injector.bindScope(MojoExecutionScoped.class, () -> {
- try {
- return containerProvider.get().lookup(MojoExecutionScope.class);
- } catch (ComponentLookupException e) {
- throw new RuntimeException(e);
- }
- });
- 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();
}
- loadFromClassLoader(classLoader);
- injector.getBindings().keySet().stream()
- .filter(k -> k.getQualifier() != null)
- .sorted(Comparator.comparing(k -> k.getRawType().getName()))
- .distinct()
- .forEach(key -> {
- Class> clazz = key.getRawType();
- Class itf = (clazz.isInterface()
- ? null
- : (Class) (clazz.getInterfaces().length > 0 ? clazz.getInterfaces()[0] : clazz));
- if (itf != null) {
- AnnotatedBindingBuilder binder = bind(itf);
- if (key.getQualifier() instanceof String s && !s.isEmpty()) {
- binder.annotatedWith(Names.named(s));
- } else if (key.getQualifier() instanceof Annotation a) {
- binder.annotatedWith(a);
- }
- binder.toProvider(() -> injector.getInstance(clazz));
- }
- });
- }
- 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();
- }
+ private Supplier getListSupplier(Key key) {
+ Key elementType = key.getTypeParameter(0);
+ return () -> {
+ List> list = new ArrayList<>();
+ // Add DI bindings
+ list.addAll(getBindings().getOrDefault(elementType, Set.of()));
+ // Add Plexus bindings
+ for (var bean : locator.get().locate(toGuiceKey(elementType))) {
+ if (isPlexusBean(bean)) {
+ list.add(new BindingToBeanEntry<>(elementType).toBeanEntry(bean));
}
}
+ //noinspection unchecked
+ return (Q) list(list.stream().sorted(getBindingComparator()).toList(), this::getInstance);
+ };
+ }
+
+ private Supplier getMapSupplier(Key key) {
+ Key> keyType = key.getTypeParameter(0);
+ Key valueType = key.getTypeParameter(1);
+ if (keyType.getRawType() != String.class) {
+ throw new DIException("Only String keys are supported for maps: " + key);
}
- } catch (IOException e) {
- throw new MavenException(e);
+ return () -> {
+ var comparator = getBindingComparator();
+ Map> map = new HashMap<>();
+ for (Binding> b : getBindings().getOrDefault(valueType, Set.of())) {
+ String name =
+ b.getOriginalKey() != null && b.getOriginalKey().getQualifier() instanceof String s
+ ? s
+ : "";
+ map.compute(name, (n, ob) -> ob == null || comparator.compare(ob, b) < 0 ? b : ob);
+ }
+ for (var bean : locator.get().locate(toGuiceKey(valueType))) {
+ if (isPlexusBean(bean)) {
+ Binding> b = new BindingToBeanEntry<>(valueType)
+ .toBeanEntry(bean)
+ .prioritize(bean.getRank());
+ String name = bean.getKey() instanceof com.google.inject.name.Named n ? n.value() : "";
+ map.compute(name, (n, ob) -> ob == null || ob.getPriority() < b.getPriority() ? b : ob);
+ }
+ }
+ //noinspection unchecked
+ return (Q) map(map, this::getInstance);
+ };
+ }
+
+ private Q getInstance(Binding binding) {
+ return compile(binding).get();
+ }
+
+ private static Comparator> getBindingComparator() {
+ Comparator> comparing = Comparator.comparing(Binding::getPriority);
+ return comparing.reversed();
+ }
+
+ private boolean isPlexusBean(BeanEntry entry) {
+ try {
+ if ("org.eclipse.sisu.inject.LazyBeanEntry"
+ .equals(entry.getClass().getName())) {
+ Field f = entry.getClass().getDeclaredField("binding");
+ f.setAccessible(true);
+ Object b = f.get(entry);
+ return !(b instanceof ProviderInstanceBinding> pib)
+ || !(pib.getUserSuppliedProvider() instanceof BridgeProvider>);
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ return true;
}
}
}
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 284fafd6ae..9938a9c46c 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
@@ -19,190 +19,36 @@
package org.apache.maven.session.scope.internal;
import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
import com.google.inject.Key;
-import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
import com.google.inject.Scope;
-import com.google.inject.name.Names;
+import com.google.inject.name.Named;
/**
* SessionScope
*/
-public class SessionScope implements Scope, org.apache.maven.di.Scope {
-
- private static final Provider SEEDED_KEY_PROVIDER = () -> {
- throw new IllegalStateException();
- };
-
- /**
- * ScopeState
- */
- protected static final class ScopeState {
- private final Map, CachingProvider>> provided = new ConcurrentHashMap<>();
-
- public void seed(Class clazz, Provider value) {
- provided.put(Key.get(clazz), new CachingProvider<>(value));
- }
-
- @SuppressWarnings("unchecked")
- public Provider scope(Key key, Provider unscoped) {
- Provider> provider = provided.computeIfAbsent(key, k -> new CachingProvider<>(unscoped));
- return (Provider) provider;
- }
-
- public Collection> providers() {
- return provided.values();
- }
- }
-
- private final List values = new CopyOnWriteArrayList<>();
-
- public void enter() {
- values.add(0, new ScopeState());
- }
-
- protected ScopeState getScopeState() {
- if (values.isEmpty()) {
- throw new OutOfScopeException("Cannot access session scope outside of a scoping block");
- }
- return values.get(0);
- }
-
- public void exit() {
- if (values.isEmpty()) {
- throw new IllegalStateException();
- }
- values.remove(0);
- }
+public class SessionScope extends org.apache.maven.internal.impl.di.SessionScope implements Scope {
public void seed(Class clazz, Provider value) {
- getScopeState().seed(clazz, value);
- }
-
- public void seed(Class clazz, final T value) {
- seed(clazz, (Provider) () -> value);
+ getScopeState().seed(clazz, value::get);
}
public Provider scope(final Key key, final Provider unscoped) {
- // Lazy evaluating provider
- return () -> {
- if (values.isEmpty()) {
- return createProxy(key, unscoped);
- } else {
- return getScopeState().scope(key, unscoped).get();
- }
- };
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Supplier scope(org.apache.maven.di.Key key, Annotation scope, Supplier unscoped) {
- Object qualifier = key.getQualifier();
- Key> k = qualifier != null
- ? Key.get(key.getType(), qualifier instanceof String s ? Names.named(s) : (Annotation) qualifier)
- : Key.get(key.getType());
- Provider up = unscoped::get;
- Provider p = scope((Key) k, up);
- return p::get;
- }
-
- @SuppressWarnings("unchecked")
- private T createProxy(Key key, Provider unscoped) {
- InvocationHandler dispatcher = (proxy, method, args) -> {
- method.setAccessible(true);
- try {
- return method.invoke(getScopeState().scope(key, unscoped).get(), args);
- } catch (InvocationTargetException e) {
- throw e.getCause();
- }
- };
- Class superType = (Class) key.getTypeLiteral().getRawType();
- Class>[] interfaces = getInterfaces(superType);
- return (T) java.lang.reflect.Proxy.newProxyInstance(superType.getClassLoader(), interfaces, dispatcher);
- }
-
- private Class>[] getInterfaces(Class> superType) {
- if (superType.isInterface()) {
- return new Class>[] {superType};
- } else {
- for (Annotation a : superType.getAnnotations()) {
- Class extends Annotation> annotationType = a.annotationType();
- 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 {
- Class>[] value =
- (Class>[]) annotationType.getMethod("value").invoke(a);
- if (value.length == 0) {
- value = superType.getInterfaces();
- }
- List> nonInterfaces =
- Stream.of(value).filter(c -> !c.isInterface()).collect(Collectors.toList());
- if (!nonInterfaces.isEmpty()) {
- throw new IllegalArgumentException(
- "The Typed annotation must contain only interfaces but the following types are not: "
- + nonInterfaces);
- }
- return value;
- } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
- throw new IllegalStateException(e);
- }
- }
- }
- throw new IllegalArgumentException("The use of session scoped proxies require "
- + "a org.eclipse.sisu.Typed or javax.enterprise.inject.Typed annotation");
- }
- }
-
- /**
- * A provider wrapping an existing provider with a cache
- * @param the provided type
- */
- protected static class CachingProvider implements Provider {
- private final Provider provider;
- private volatile T value;
-
- CachingProvider(Provider provider) {
- this.provider = provider;
- }
-
- public T value() {
- return value;
- }
-
- @Override
- public T get() {
- if (value == null) {
- synchronized (this) {
- if (value == null) {
- value = provider.get();
- }
- }
- }
- return value;
- }
- }
-
- @SuppressWarnings({"unchecked"})
- public static Provider seededKeyProvider() {
- return (Provider) SEEDED_KEY_PROVIDER;
+ Object qualifier = key.getAnnotation() instanceof Named n ? n.value() : key.getAnnotation();
+ org.apache.maven.di.Key k =
+ org.apache.maven.di.Key.ofType(key.getTypeLiteral().getType(), qualifier);
+ return scope(k, unscoped::get)::get;
}
public static Provider seededKeyProvider(Class extends T> clazz) {
- return () -> {
- throw new IllegalStateException("No instance of " + clazz.getName() + " is bound to the session scope.");
- };
+ return SessionScope.seededKeySupplier(clazz)::get;
+ }
+
+ protected boolean isTypeAnnotation(Class extends Annotation> annotationType) {
+ return "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());
}
}
diff --git a/maven-core/src/test/java/org/apache/maven/di/DiTest.java b/maven-core/src/test/java/org/apache/maven/di/DiTest.java
new file mode 100644
index 0000000000..62b84bca3b
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/di/DiTest.java
@@ -0,0 +1,271 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.di;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Binding;
+import com.google.inject.Injector;
+import com.google.inject.TypeLiteral;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.services.Source;
+import org.apache.maven.api.spi.ModelParser;
+import org.apache.maven.api.spi.ModelParserException;
+import org.apache.maven.internal.impl.SisuDiBridgeModule;
+import org.codehaus.plexus.DefaultContainerConfiguration;
+import org.codehaus.plexus.DefaultPlexusContainer;
+import org.codehaus.plexus.PlexusContainer;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIf;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class DiTest {
+
+ // return true to run the test
+ static boolean testShouldNotHaveDuplicates() {
+ return true;
+ }
+
+ @Nested
+ class DiTest1 {
+
+ PlexusContainer container;
+
+ @BeforeEach
+ void setup() throws Exception {
+ container = new DefaultPlexusContainer(
+ new DefaultContainerConfiguration(),
+ new AbstractModule() {
+ @Override
+ protected void configure() {
+ bind(ModelParser.class).to(TestModelParser.class);
+ }
+ },
+ new SisuDiBridgeModule(false));
+ }
+
+ @Test
+ void testPlexus() throws Exception {
+ List parsers = container.lookupList(ModelParser.class);
+ assertNotNull(parsers);
+ assertEquals(1, parsers.size());
+ Map parsersMap = container.lookupMap(ModelParser.class);
+ assertNotNull(parsersMap);
+ assertEquals(1, parsersMap.size());
+ }
+
+ @Test
+ void testGuice() throws Exception {
+ List> parsers =
+ container.lookup(Injector.class).findBindingsByType(TypeLiteral.get(ModelParser.class));
+ assertNotNull(parsers);
+ assertEquals(1, parsers.size());
+ }
+
+ @Test
+ void testDI() throws Exception {
+ DiInjected diInjected = new DiInjected();
+ container.lookup(org.apache.maven.di.Injector.class).injectInstance(diInjected);
+ assertNotNull(diInjected.parser);
+ assertNotNull(diInjected.parsers);
+ assertEquals(1, diInjected.parsers.size());
+ assertNotNull(diInjected.parsersMap);
+ assertEquals(1, diInjected.parsersMap.size());
+ }
+
+ static class DiInjected {
+ @org.apache.maven.api.di.Inject
+ ModelParser parser;
+
+ @org.apache.maven.api.di.Inject
+ List parsers;
+
+ @org.apache.maven.api.di.Inject
+ Map parsersMap;
+ }
+
+ @Named
+ @Singleton
+ static class TestModelParser implements ModelParser {
+ @Override
+ public Optional locate(Path dir) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Model parse(Source source, Map options) throws ModelParserException {
+ return null;
+ }
+ }
+ }
+
+ @Nested
+ class DiTest2 {
+
+ PlexusContainer container;
+
+ @BeforeEach
+ void setup() throws Exception {
+ container = new DefaultPlexusContainer(new DefaultContainerConfiguration(), new SisuDiBridgeModule(false) {
+ @Override
+ protected void configure() {
+ super.configure();
+ injector.bindImplicit(TestModelParser.class);
+ }
+ });
+ }
+
+ @Test
+ void testPlexus() throws Exception {
+ List parsers = container.lookupList(ModelParser.class);
+ assertNotNull(parsers);
+ assertEquals(1, parsers.size());
+ Map parsersMap = container.lookupMap(ModelParser.class);
+ assertNotNull(parsersMap);
+ assertEquals(1, parsersMap.size());
+ }
+
+ @Test
+ void testGuice() throws Exception {
+ List> parsers2 =
+ container.lookup(Injector.class).findBindingsByType(TypeLiteral.get(ModelParser.class));
+ assertNotNull(parsers2);
+ assertEquals(1, parsers2.size());
+ }
+
+ @Test
+ @EnabledIf("org.apache.maven.di.DiTest#testShouldNotHaveDuplicates")
+ void testDI() throws Exception {
+ DiInjected diInjected = new DiInjected();
+ container.lookup(org.apache.maven.di.Injector.class).injectInstance(diInjected);
+ assertNotNull(diInjected.parser);
+ assertNotNull(diInjected.parsers);
+ assertEquals(1, diInjected.parsers.size());
+ assertNotNull(diInjected.parsersMap);
+ assertEquals(1, diInjected.parsersMap.size());
+ }
+
+ static class DiInjected {
+ @org.apache.maven.api.di.Inject
+ ModelParser parser;
+
+ @org.apache.maven.api.di.Inject
+ List parsers;
+
+ @org.apache.maven.api.di.Inject
+ Map parsersMap;
+ }
+
+ @org.apache.maven.api.di.Named
+ @org.apache.maven.api.di.Singleton
+ static class TestModelParser implements ModelParser {
+ @Override
+ public Optional locate(Path dir) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Model parse(Source source, Map options) throws ModelParserException {
+ return null;
+ }
+ }
+ }
+
+ @Nested
+ class DiTest3 {
+
+ PlexusContainer container;
+
+ @BeforeEach
+ void setup() throws Exception {
+ container = new DefaultPlexusContainer(new DefaultContainerConfiguration(), new SisuDiBridgeModule(false) {
+ @Override
+ protected void configure() {
+ super.configure();
+ injector.bindImplicit(TestModelParser.class);
+ }
+ });
+ }
+
+ @Test
+ void testPlexus() throws Exception {
+ List parsers = container.lookupList(ModelParser.class);
+ assertNotNull(parsers);
+ assertEquals(1, parsers.size());
+ Map parsersMap = container.lookupMap(ModelParser.class);
+ assertNotNull(parsersMap);
+ assertEquals(1, parsersMap.size());
+ }
+
+ @Test
+ void testGuice() throws Exception {
+ List> parsers =
+ container.lookup(Injector.class).findBindingsByType(TypeLiteral.get(ModelParser.class));
+ assertNotNull(parsers);
+ assertEquals(1, parsers.size());
+ }
+
+ @Test
+ @EnabledIf("org.apache.maven.di.DiTest#testShouldNotHaveDuplicates")
+ void testDI() throws Exception {
+ DiInjected diInjected = new DiInjected();
+ container.lookup(org.apache.maven.di.Injector.class).injectInstance(diInjected);
+ assertNotNull(diInjected.parser);
+ assertNotNull(diInjected.parsers);
+ assertEquals(1, diInjected.parsers.size());
+ assertNotNull(diInjected.parsersMap);
+ assertEquals(1, diInjected.parsersMap.size());
+ }
+
+ static class DiInjected {
+ @org.apache.maven.api.di.Inject
+ ModelParser parser;
+
+ @org.apache.maven.api.di.Inject
+ List parsers;
+
+ @org.apache.maven.api.di.Inject
+ Map parsersMap;
+ }
+
+ @org.apache.maven.api.di.Named
+ static class TestModelParser implements ModelParser {
+ @Override
+ public Optional locate(Path dir) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Model parse(Source source, Map options) throws ModelParserException {
+ return null;
+ }
+ }
+ }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeTest.java b/maven-core/src/test/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeTest.java
index 5e53789a47..09af78fb6e 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeTest.java
@@ -39,15 +39,15 @@ class MojoExecutionScopeTest {
Object o1 = new Object();
scope.seed(Object.class, o1);
- assertSame(o1, scope.scope(Key.get(Object.class), null).get());
+ assertSame(o1, scope.scope(Key.get(Object.class), () -> null).get());
scope.enter();
Object o2 = new Object();
scope.seed(Object.class, o2);
- assertSame(o2, scope.scope(Key.get(Object.class), null).get());
+ assertSame(o2, scope.scope(Key.get(Object.class), () -> null).get());
scope.exit();
- assertSame(o1, scope.scope(Key.get(Object.class), null).get());
+ assertSame(o1, scope.scope(Key.get(Object.class), () -> null).get());
scope.exit();
diff --git a/maven-core/src/test/java/org/apache/maven/session/scope/SessionScopeProxyTest.java b/maven-core/src/test/java/org/apache/maven/session/scope/SessionScopeProxyTest.java
index 00bc450b14..8db44f55d9 100644
--- a/maven-core/src/test/java/org/apache/maven/session/scope/SessionScopeProxyTest.java
+++ b/maven-core/src/test/java/org/apache/maven/session/scope/SessionScopeProxyTest.java
@@ -22,9 +22,9 @@ import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
-import com.google.inject.OutOfScopeException;
import org.apache.maven.SessionScoped;
import org.apache.maven.api.Session;
+import org.apache.maven.internal.impl.di.OutOfScopeException;
import org.apache.maven.session.scope.internal.SessionScope;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
diff --git a/maven-di/src/main/java/org/apache/maven/di/Injector.java b/maven-di/src/main/java/org/apache/maven/di/Injector.java
index d4eea98625..56b2212650 100644
--- a/maven-di/src/main/java/org/apache/maven/di/Injector.java
+++ b/maven-di/src/main/java/org/apache/maven/di/Injector.java
@@ -36,27 +36,29 @@ public interface Injector {
}
@Nonnull
- Injector discover(ClassLoader classLoader);
+ Injector discover(@Nonnull ClassLoader classLoader);
@Nonnull
- Injector bindScope(Class extends Annotation> scopeAnnotation, Scope scope);
+ Injector bindScope(@Nonnull Class extends Annotation> scopeAnnotation, @Nonnull Scope scope);
@Nonnull
- Injector bindScope(Class extends Annotation> scopeAnnotation, Supplier scope);
+ Injector bindScope(@Nonnull Class extends Annotation> scopeAnnotation, @Nonnull Supplier scope);
@Nonnull
- Injector bindImplicit(Class> cls);
+ Injector bindImplicit(@Nonnull Class> cls);
@Nonnull
- Injector bindInstance(Class cls, T instance);
+ Injector bindInstance(@Nonnull Class cls, @Nonnull T instance);
//
// Bean access
//
- void injectInstance(T instance);
+ void injectInstance(@Nonnull T instance);
- T getInstance(Class key);
+ @Nonnull
+ T getInstance(@Nonnull Class key);
- T getInstance(Key key);
+ @Nonnull
+ T getInstance(@Nonnull Key