mirror of https://github.com/apache/maven.git
[MNG-8259] Improve Sisu / DI bridge (#1722)
This commit is contained in:
parent
30f52651a7
commit
deb15be3b6
|
@ -71,6 +71,10 @@ under the License.
|
|||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-api-settings</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-di</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-api</artifactId>
|
||||
|
@ -132,11 +136,6 @@ under the License.
|
|||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-di</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-named-locks</artifactId>
|
||||
|
|
|
@ -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<Key<?>, Supplier<?>> seeded = new HashMap<>();
|
||||
|
||||
private final Map<Key<?>, Object> provided = new HashMap<>();
|
||||
|
||||
public <T> void seed(Class<T> clazz, Supplier<T> value) {
|
||||
seeded.put(Key.of(clazz), value);
|
||||
}
|
||||
|
||||
public Collection<Object> provided() {
|
||||
return provided.values();
|
||||
}
|
||||
}
|
||||
|
||||
private final ThreadLocal<LinkedList<ScopeState>> values = new ThreadLocal<>();
|
||||
|
||||
public MojoExecutionScope() {}
|
||||
|
||||
public static <T> Supplier<T> 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<ScopeState> stack = values.get();
|
||||
if (stack == null) {
|
||||
stack = new LinkedList<>();
|
||||
values.set(stack);
|
||||
}
|
||||
stack.addFirst(new ScopeState());
|
||||
}
|
||||
|
||||
protected ScopeState getScopeState() {
|
||||
LinkedList<ScopeState> stack = values.get();
|
||||
if (stack == null || stack.isEmpty()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return stack.getFirst();
|
||||
}
|
||||
|
||||
public void exit() {
|
||||
final LinkedList<ScopeState> stack = values.get();
|
||||
if (stack == null || stack.isEmpty()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
stack.removeFirst();
|
||||
if (stack.isEmpty()) {
|
||||
values.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void seed(Class<T> clazz, Supplier<T> value) {
|
||||
getScopeState().seed(clazz, value);
|
||||
}
|
||||
|
||||
public <T> void seed(Class<T> clazz, final T value) {
|
||||
seed(clazz, (Supplier<T>) () -> value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nonnull
|
||||
public <T> Supplier<T> scope(@Nonnull Key<T> key, @Nonnull Supplier<T> unscoped) {
|
||||
return () -> {
|
||||
LinkedList<ScopeState> 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;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<Key<?>, CachingProvider<?>> provided = new ConcurrentHashMap<>();
|
||||
|
||||
public <T> void seed(Class<T> clazz, Supplier<T> value) {
|
||||
provided.put(Key.of(clazz), new CachingProvider<>(value));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Supplier<T> scope(Key<T> key, Supplier<T> unscoped) {
|
||||
Supplier<?> provider = provided.computeIfAbsent(key, k -> new CachingProvider<>(unscoped));
|
||||
return (Supplier<T>) provider;
|
||||
}
|
||||
|
||||
public Collection<CachingProvider<?>> providers() {
|
||||
return provided.values();
|
||||
}
|
||||
}
|
||||
|
||||
protected final List<ScopeState> 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 <T> void seed(Class<T> clazz, Supplier<T> value) {
|
||||
getScopeState().seed(clazz, value);
|
||||
}
|
||||
|
||||
public <T> void seed(Class<T> clazz, T value) {
|
||||
seed(clazz, (Supplier<T>) () -> value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Supplier<T> scope(Key<T> key, Supplier<T> unscoped) {
|
||||
// Lazy evaluating provider
|
||||
return () -> {
|
||||
if (values.isEmpty()) {
|
||||
return createProxy(key, unscoped);
|
||||
} else {
|
||||
return getScopeState().scope(key, unscoped).get();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T createProxy(Key<T> key, Supplier<T> unscoped) {
|
||||
InvocationHandler dispatcher = (proxy, method, args) -> dispatch(key, unscoped, method, args);
|
||||
Class<T> superType = (Class<T>) Types.getRawType(key.getType());
|
||||
Class<?>[] interfaces = getInterfaces(superType);
|
||||
return (T) java.lang.reflect.Proxy.newProxyInstance(superType.getClassLoader(), interfaces, dispatcher);
|
||||
}
|
||||
|
||||
protected <T> Object dispatch(Key<T> key, Supplier<T> 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<Class<?>> 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 <T> the provided type
|
||||
*/
|
||||
protected static class CachingProvider<T> implements Supplier<T> {
|
||||
private final Supplier<T> provider;
|
||||
private volatile T value;
|
||||
|
||||
CachingProvider(Supplier<T> 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 <T> Supplier<T> seededKeySupplier(Class<? extends T> clazz) {
|
||||
return () -> {
|
||||
throw new IllegalStateException("No instance of " + clazz.getName() + " is bound to the session scope.");
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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<Object> SEEDED_KEY_PROVIDER = () -> {
|
||||
throw new IllegalStateException();
|
||||
};
|
||||
|
||||
private static final class ScopeState {
|
||||
private final Map<Key<?>, Provider<?>> seeded = new HashMap<>();
|
||||
|
||||
private final Map<Key<?>, Object> provided = new HashMap<>();
|
||||
}
|
||||
|
||||
private final ThreadLocal<LinkedList<ScopeState>> values = new ThreadLocal<>();
|
||||
|
||||
public MojoExecutionScope() {}
|
||||
|
||||
public void enter() {
|
||||
LinkedList<ScopeState> stack = values.get();
|
||||
if (stack == null) {
|
||||
stack = new LinkedList<>();
|
||||
values.set(stack);
|
||||
}
|
||||
stack.addFirst(new ScopeState());
|
||||
}
|
||||
|
||||
private ScopeState getScopeState() {
|
||||
LinkedList<ScopeState> stack = values.get();
|
||||
if (stack == null || stack.isEmpty()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return stack.getFirst();
|
||||
}
|
||||
|
||||
public void exit() throws MojoExecutionException {
|
||||
final LinkedList<ScopeState> 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 <T> void seed(Class<T> clazz, Provider<T> value) {
|
||||
getScopeState().seeded.put(Key.get(clazz), value);
|
||||
getScopeState().seed(clazz, value::get);
|
||||
}
|
||||
|
||||
public <T> void seed(Class<T> clazz, final T value) {
|
||||
getScopeState().seeded.put(Key.get(clazz), Providers.of(value));
|
||||
public <T> Provider<T> scope(final Key<T> key, Provider<T> unscoped) {
|
||||
Object qualifier = key.getAnnotation() instanceof Named n ? n.value() : key.getAnnotation();
|
||||
org.apache.maven.di.Key<T> k =
|
||||
org.apache.maven.di.Key.ofType(key.getTypeLiteral().getType(), qualifier);
|
||||
return scope(k, unscoped::get)::get;
|
||||
}
|
||||
|
||||
public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
|
||||
return () -> {
|
||||
LinkedList<ScopeState> 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 <T> Supplier<T> scope(org.apache.maven.di.Key<T> key, Annotation scope, Supplier<T> 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<T> up = unscoped::get;
|
||||
Provider<T> p = scope(k, up);
|
||||
return p::get;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public static <T> Provider<T> seededKeyProvider() {
|
||||
return (Provider<T>) SEEDED_KEY_PROVIDER;
|
||||
public static <T> Provider<T> seededKeyProvider(Class<? extends T> clazz) {
|
||||
return MojoExecutionScope.<T>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<WeakMojoExecutionListener, Object> listeners = new IdentityHashMap<>();
|
||||
for (Object provided : getScopeState().provided.values()) {
|
||||
for (Object provided : getScopeState().provided()) {
|
||||
if (provided instanceof WeakMojoExecutionListener) {
|
||||
listeners.put((WeakMojoExecutionListener) provided, null);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String> 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<PlexusContainer> containerProvider = getProvider(PlexusContainer.class);
|
||||
Provider<BeanLocator> 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<PlexusContainer> 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<BeanLocator> locator;
|
||||
final Binder binder;
|
||||
|
||||
BridgeInjectorImpl(Provider<BeanLocator> locator, Binder binder) {
|
||||
this.locator = locator;
|
||||
this.binder = binder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <U> Injector bind(Key<U> key, Binding<U> binding) {
|
||||
super.bind(key, binding);
|
||||
if (key.getQualifier() != null) {
|
||||
com.google.inject.Key<U> k = toGuiceKey(key);
|
||||
this.binder.bind(k).toProvider(new BridgeProvider<>(binding));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <U> com.google.inject.Key<U> toGuiceKey(Key<U> key) {
|
||||
if (key.getQualifier() instanceof String s) {
|
||||
return (com.google.inject.Key<U>) com.google.inject.Key.get(key.getType(), Names.named(s));
|
||||
} else if (key.getQualifier() instanceof Annotation a) {
|
||||
return (com.google.inject.Key<U>) com.google.inject.Key.get(key.getType(), a);
|
||||
} else {
|
||||
return (com.google.inject.Key<U>) com.google.inject.Key.get(key.getType());
|
||||
}
|
||||
}
|
||||
|
||||
static class BindingToBeanEntry<T> extends Binding<T> {
|
||||
private BeanEntry<Annotation, T> beanEntry;
|
||||
|
||||
BindingToBeanEntry(Key<T> elementType) {
|
||||
super(elementType, Set.of());
|
||||
}
|
||||
|
||||
public BindingToBeanEntry<T> toBeanEntry(BeanEntry<Annotation, T> beanEntry) {
|
||||
this.beanEntry = beanEntry;
|
||||
return this;
|
||||
}
|
||||
|
||||
injector = new InjectorImpl() {
|
||||
@Override
|
||||
public <Q> Supplier<Q> getCompiledBinding(Dependency<Q> dep) {
|
||||
Key<Q> key = dep.key();
|
||||
Set<Binding<Q>> res = getBindings(key);
|
||||
if (res != null && !res.isEmpty()) {
|
||||
List<Binding<Q>> bindingList = new ArrayList<>(res);
|
||||
Comparator<Binding<Q>> comparing = Comparator.comparing(Binding::getPriority);
|
||||
bindingList.sort(comparing.reversed());
|
||||
Binding<Q> binding = bindingList.get(0);
|
||||
return compile(binding);
|
||||
}
|
||||
if (key.getRawType() == List.class) {
|
||||
Set<Binding<Object>> res2 = getBindings(key.getTypeParameter(0));
|
||||
Set<Binding<Object>> res3 = res2 != null ? new HashSet<>(res2) : new HashSet<>();
|
||||
try {
|
||||
List<Object> l = containerProvider
|
||||
.get()
|
||||
.lookupList(key.getTypeParameter(0).getRawType());
|
||||
l.forEach(o -> res3.add(new Binding.BindingToInstance<>(o)));
|
||||
} catch (Throwable e) {
|
||||
// ignore
|
||||
e.printStackTrace();
|
||||
}
|
||||
List<Supplier<Object>> 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<Object> v = key.getTypeParameter(1);
|
||||
if (k.getRawType() == String.class) {
|
||||
Set<Binding<Object>> res2 = getBindings(v);
|
||||
Set<Binding<Object>> res3 = res2 != null ? new HashSet<>(res2) : new HashSet<>();
|
||||
Map<String, Supplier<Object>> 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<T> compile(Function<Dependency<?>, Supplier<?>> compiler) {
|
||||
return beanEntry.getProvider()::get;
|
||||
}
|
||||
}
|
||||
|
||||
class BridgeProvider<T> implements Provider<T> {
|
||||
final Binding<T> binding;
|
||||
|
||||
BridgeProvider(Binding<T> binding) {
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return compile(binding).get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q> Supplier<Q> getCompiledBinding(Dependency<Q> dep) {
|
||||
Key<Q> key = dep.key();
|
||||
Class<Q> rawType = key.getRawType();
|
||||
if (rawType == List.class) {
|
||||
return getListSupplier(key);
|
||||
} else if (rawType == Map.class) {
|
||||
return getMapSupplier(key);
|
||||
} else {
|
||||
return getBeanSupplier(dep, key);
|
||||
}
|
||||
}
|
||||
|
||||
private <Q> Supplier<Q> getBeanSupplier(Dependency<Q> dep, Key<Q> key) {
|
||||
List<Binding<?>> 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<Object> itf = (clazz.isInterface()
|
||||
? null
|
||||
: (Class<Object>) (clazz.getInterfaces().length > 0 ? clazz.getInterfaces()[0] : clazz));
|
||||
if (itf != null) {
|
||||
AnnotatedBindingBuilder<Object> 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<URL> 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<String> 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 <Q> Supplier<Q> getListSupplier(Key<Q> key) {
|
||||
Key<Object> elementType = key.getTypeParameter(0);
|
||||
return () -> {
|
||||
List<Binding<?>> 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 <Q> Supplier<Q> getMapSupplier(Key<Q> key) {
|
||||
Key<?> keyType = key.getTypeParameter(0);
|
||||
Key<Object> 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<String, Binding<?>> 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> Q getInstance(Binding<Q> binding) {
|
||||
return compile(binding).get();
|
||||
}
|
||||
|
||||
private static Comparator<Binding<?>> getBindingComparator() {
|
||||
Comparator<Binding<?>> comparing = Comparator.comparing(Binding::getPriority);
|
||||
return comparing.reversed();
|
||||
}
|
||||
|
||||
private <T> boolean isPlexusBean(BeanEntry<Annotation, T> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Object> SEEDED_KEY_PROVIDER = () -> {
|
||||
throw new IllegalStateException();
|
||||
};
|
||||
|
||||
/**
|
||||
* ScopeState
|
||||
*/
|
||||
protected static final class ScopeState {
|
||||
private final Map<Key<?>, CachingProvider<?>> provided = new ConcurrentHashMap<>();
|
||||
|
||||
public <T> void seed(Class<T> clazz, Provider<T> value) {
|
||||
provided.put(Key.get(clazz), new CachingProvider<>(value));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
|
||||
Provider<?> provider = provided.computeIfAbsent(key, k -> new CachingProvider<>(unscoped));
|
||||
return (Provider<T>) provider;
|
||||
}
|
||||
|
||||
public Collection<CachingProvider<?>> providers() {
|
||||
return provided.values();
|
||||
}
|
||||
}
|
||||
|
||||
private final List<ScopeState> 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 <T> void seed(Class<T> clazz, Provider<T> value) {
|
||||
getScopeState().seed(clazz, value);
|
||||
}
|
||||
|
||||
public <T> void seed(Class<T> clazz, final T value) {
|
||||
seed(clazz, (Provider<T>) () -> value);
|
||||
getScopeState().seed(clazz, value::get);
|
||||
}
|
||||
|
||||
public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
|
||||
// Lazy evaluating provider
|
||||
return () -> {
|
||||
if (values.isEmpty()) {
|
||||
return createProxy(key, unscoped);
|
||||
} else {
|
||||
return getScopeState().scope(key, unscoped).get();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> Supplier<T> scope(org.apache.maven.di.Key<T> key, Annotation scope, Supplier<T> 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<T> up = unscoped::get;
|
||||
Provider<T> p = scope((Key<T>) k, up);
|
||||
return p::get;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T createProxy(Key<T> key, Provider<T> 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<T> superType = (Class<T>) 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<Class<?>> 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 <T> the provided type
|
||||
*/
|
||||
protected static class CachingProvider<T> implements Provider<T> {
|
||||
private final Provider<T> provider;
|
||||
private volatile T value;
|
||||
|
||||
CachingProvider(Provider<T> 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 <T> Provider<T> seededKeyProvider() {
|
||||
return (Provider<T>) SEEDED_KEY_PROVIDER;
|
||||
Object qualifier = key.getAnnotation() instanceof Named n ? n.value() : key.getAnnotation();
|
||||
org.apache.maven.di.Key<T> k =
|
||||
org.apache.maven.di.Key.ofType(key.getTypeLiteral().getType(), qualifier);
|
||||
return scope(k, unscoped::get)::get;
|
||||
}
|
||||
|
||||
public static <T> Provider<T> seededKeyProvider(Class<? extends T> clazz) {
|
||||
return () -> {
|
||||
throw new IllegalStateException("No instance of " + clazz.getName() + " is bound to the session scope.");
|
||||
};
|
||||
return SessionScope.<T>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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ModelParser> parsers = container.lookupList(ModelParser.class);
|
||||
assertNotNull(parsers);
|
||||
assertEquals(1, parsers.size());
|
||||
Map<String, ModelParser> parsersMap = container.lookupMap(ModelParser.class);
|
||||
assertNotNull(parsersMap);
|
||||
assertEquals(1, parsersMap.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGuice() throws Exception {
|
||||
List<Binding<ModelParser>> 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<ModelParser> parsers;
|
||||
|
||||
@org.apache.maven.api.di.Inject
|
||||
Map<String, ModelParser> parsersMap;
|
||||
}
|
||||
|
||||
@Named
|
||||
@Singleton
|
||||
static class TestModelParser implements ModelParser {
|
||||
@Override
|
||||
public Optional<Source> locate(Path dir) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model parse(Source source, Map<String, ?> 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<ModelParser> parsers = container.lookupList(ModelParser.class);
|
||||
assertNotNull(parsers);
|
||||
assertEquals(1, parsers.size());
|
||||
Map<String, ModelParser> parsersMap = container.lookupMap(ModelParser.class);
|
||||
assertNotNull(parsersMap);
|
||||
assertEquals(1, parsersMap.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGuice() throws Exception {
|
||||
List<Binding<ModelParser>> 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<ModelParser> parsers;
|
||||
|
||||
@org.apache.maven.api.di.Inject
|
||||
Map<String, ModelParser> parsersMap;
|
||||
}
|
||||
|
||||
@org.apache.maven.api.di.Named
|
||||
@org.apache.maven.api.di.Singleton
|
||||
static class TestModelParser implements ModelParser {
|
||||
@Override
|
||||
public Optional<Source> locate(Path dir) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model parse(Source source, Map<String, ?> 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<ModelParser> parsers = container.lookupList(ModelParser.class);
|
||||
assertNotNull(parsers);
|
||||
assertEquals(1, parsers.size());
|
||||
Map<String, ModelParser> parsersMap = container.lookupMap(ModelParser.class);
|
||||
assertNotNull(parsersMap);
|
||||
assertEquals(1, parsersMap.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGuice() throws Exception {
|
||||
List<Binding<ModelParser>> 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<ModelParser> parsers;
|
||||
|
||||
@org.apache.maven.api.di.Inject
|
||||
Map<String, ModelParser> parsersMap;
|
||||
}
|
||||
|
||||
@org.apache.maven.api.di.Named
|
||||
static class TestModelParser implements ModelParser {
|
||||
@Override
|
||||
public Optional<Source> locate(Path dir) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model parse(Source source, Map<String, ?> options) throws ModelParserException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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> scope);
|
||||
Injector bindScope(@Nonnull Class<? extends Annotation> scopeAnnotation, @Nonnull Supplier<Scope> scope);
|
||||
|
||||
@Nonnull
|
||||
Injector bindImplicit(Class<?> cls);
|
||||
Injector bindImplicit(@Nonnull Class<?> cls);
|
||||
|
||||
@Nonnull
|
||||
<T> Injector bindInstance(Class<T> cls, T instance);
|
||||
<T> Injector bindInstance(@Nonnull Class<T> cls, @Nonnull T instance);
|
||||
|
||||
//
|
||||
// Bean access
|
||||
//
|
||||
|
||||
<T> void injectInstance(T instance);
|
||||
<T> void injectInstance(@Nonnull T instance);
|
||||
|
||||
<T> T getInstance(Class<T> key);
|
||||
@Nonnull
|
||||
<T> T getInstance(@Nonnull Class<T> key);
|
||||
|
||||
<T> T getInstance(Key<T> key);
|
||||
@Nonnull
|
||||
<T> T getInstance(@Nonnull Key<T> key);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.apache.maven.di.impl.Utils;
|
|||
* The key defines an identity of a binding. In any DI, a key is usually a type of the object along
|
||||
* with some optional tag to distinguish between bindings which make objects of the same type.
|
||||
* <p>
|
||||
* In ActiveJ Inject, a key is also a type token - special abstract class that can store type information
|
||||
* In Maven Inject, a key is also a type token - special abstract class that can store type information
|
||||
* with the shortest syntax possible in Java.
|
||||
* <p>
|
||||
* For example, to create a key of type Map<String, List<Integer>>, you can just use
|
||||
|
|
|
@ -18,10 +18,34 @@
|
|||
*/
|
||||
package org.apache.maven.di;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.maven.api.annotations.Experimental;
|
||||
import org.apache.maven.api.annotations.Nonnull;
|
||||
|
||||
/**
|
||||
* A {@code Scope} defines how visible instances are when managed by a {@link org.apache.maven.di.Injector}.
|
||||
* Typically, instances are created with <i>no scope</i>, meaning they don’t retain any state from the
|
||||
* framework’s perspective: the {@code Injector} generates the instance, injects it into the necessary class,
|
||||
* and then immediately forgets it. By linking a scope to a specific binding, the created instance can be
|
||||
* “remembered” and reused for future injections.
|
||||
* <p>
|
||||
* Instances are associated to a given scope by means of a {@link org.apache.maven.api.di.Scope @Scope}
|
||||
* annotation, usually put on another annotation. For example, the {@code @Singleton} annotation is used
|
||||
* to indicate that a given binding should be scoped as a singleton.
|
||||
* <p>
|
||||
* The following scopes are currently supported:
|
||||
* <ul>
|
||||
* <li>{@link org.apache.maven.api.di.Singleton @Singleton}</li>
|
||||
* <li>{@link org.apache.maven.api.di.SessionScoped @SessionScoped}</li>
|
||||
* <li>{@link org.apache.maven.api.di.MojoExecutionScoped @MojoExecutionScoped}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Experimental
|
||||
public interface Scope {
|
||||
|
||||
<T> Supplier<T> scope(Key<T> key, Annotation scope, Supplier<T> unscoped);
|
||||
@Nonnull
|
||||
<T> Supplier<T> scope(@Nonnull Key<T> key, @Nonnull Supplier<T> unscoped);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.apache.maven.di.Injector;
|
|||
* (missing or cyclic dependencies, incorrect annotations etc.) or in runtime when
|
||||
* you ask an {@link Injector} for an instance it does not have a {@link Binding binding} for.
|
||||
*/
|
||||
public final class DIException extends RuntimeException {
|
||||
public class DIException extends RuntimeException {
|
||||
public DIException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ public class InjectorImpl implements Injector {
|
|||
|
||||
private final Map<Key<?>, Set<Binding<?>>> bindings = new HashMap<>();
|
||||
private final Map<Class<? extends Annotation>, Supplier<Scope>> scopes = new HashMap<>();
|
||||
private final Set<String> loadedUrls = new HashSet<>();
|
||||
|
||||
public InjectorImpl() {
|
||||
bindScope(Singleton.class, new SingletonScope());
|
||||
|
@ -87,12 +88,16 @@ public class InjectorImpl implements Injector {
|
|||
try {
|
||||
Enumeration<URL> enumeration = classLoader.getResources("META-INF/maven/org.apache.maven.api.di.Inject");
|
||||
while (enumeration.hasMoreElements()) {
|
||||
try (InputStream is = enumeration.nextElement().openStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(is)))) {
|
||||
for (String line :
|
||||
reader.lines().filter(l -> !l.startsWith("#")).toList()) {
|
||||
Class<?> clazz = classLoader.loadClass(line);
|
||||
bindImplicit(clazz);
|
||||
URL url = enumeration.nextElement();
|
||||
if (loadedUrls.add(url.toExternalForm())) {
|
||||
try (InputStream is = url.openStream();
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(Objects.requireNonNull(is)))) {
|
||||
for (String line :
|
||||
reader.lines().filter(l -> !l.startsWith("#")).toList()) {
|
||||
Class<?> clazz = classLoader.loadClass(line);
|
||||
bindImplicit(clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +200,7 @@ public class InjectorImpl implements Injector {
|
|||
if (res2 != null) {
|
||||
List<Supplier<Object>> list = res2.stream().map(this::compile).collect(Collectors.toList());
|
||||
//noinspection unchecked
|
||||
return () -> (Q) list(list);
|
||||
return () -> (Q) list(list, Supplier::get);
|
||||
}
|
||||
}
|
||||
if (key.getRawType() == Map.class) {
|
||||
|
@ -214,7 +219,7 @@ public class InjectorImpl implements Injector {
|
|||
: null),
|
||||
this::compile));
|
||||
//noinspection unchecked
|
||||
return () -> (Q) map(map);
|
||||
return () -> (Q) map(map, Supplier::get);
|
||||
}
|
||||
}
|
||||
if (dep.optional()) {
|
||||
|
@ -241,7 +246,7 @@ public class InjectorImpl implements Injector {
|
|||
.orElseThrow(() -> new DIException("Scope not bound for annotation "
|
||||
+ binding.getScope().annotationType()))
|
||||
.get();
|
||||
compiled = scope.scope((Key<Q>) binding.getOriginalKey(), binding.getScope(), compiled);
|
||||
compiled = scope.scope((Key<Q>) binding.getOriginalKey(), compiled);
|
||||
}
|
||||
return compiled;
|
||||
}
|
||||
|
@ -307,8 +312,8 @@ public class InjectorImpl implements Injector {
|
|||
}
|
||||
}
|
||||
|
||||
protected <K, V> Map<K, V> map(Map<K, Supplier<V>> map) {
|
||||
return new WrappingMap<>(map, Supplier::get);
|
||||
protected <K, V, T> Map<K, V> map(Map<K, T> map, Function<T, V> mapper) {
|
||||
return new WrappingMap<>(map, mapper);
|
||||
}
|
||||
|
||||
private static class WrappingMap<K, V, T> extends AbstractMap<K, V> {
|
||||
|
@ -349,8 +354,8 @@ public class InjectorImpl implements Injector {
|
|||
}
|
||||
}
|
||||
|
||||
protected <T> List<T> list(List<Supplier<T>> bindingList) {
|
||||
return new WrappingList<>(bindingList, Supplier::get);
|
||||
protected <Q, T> List<Q> list(List<T> bindingList, Function<T, Q> mapper) {
|
||||
return new WrappingList<>(bindingList, mapper);
|
||||
}
|
||||
|
||||
private static class WrappingList<Q, T> extends AbstractList<Q> {
|
||||
|
@ -379,8 +384,7 @@ public class InjectorImpl implements Injector {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> java.util.function.Supplier<T> scope(
|
||||
Key<T> key, Annotation scope, java.util.function.Supplier<T> unscoped) {
|
||||
public <T> java.util.function.Supplier<T> scope(Key<T> key, java.util.function.Supplier<T> unscoped) {
|
||||
return (java.util.function.Supplier<T>)
|
||||
cache.computeIfAbsent(key, k -> new java.util.function.Supplier<T>() {
|
||||
volatile T instance;
|
||||
|
|
|
@ -79,6 +79,7 @@ import org.apache.maven.cli.transfer.ConsoleMavenTransferListener;
|
|||
import org.apache.maven.cli.transfer.QuietMavenTransferListener;
|
||||
import org.apache.maven.cli.transfer.SimplexTransferListener;
|
||||
import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
|
||||
import org.apache.maven.di.Injector;
|
||||
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
|
||||
import org.apache.maven.exception.DefaultExceptionHandler;
|
||||
import org.apache.maven.exception.ExceptionHandler;
|
||||
|
@ -95,7 +96,6 @@ import org.apache.maven.execution.scope.internal.MojoExecutionScope;
|
|||
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;
|
||||
|
@ -732,10 +732,20 @@ public class MavenCli {
|
|||
for (CoreExtensionEntry extension : extensions) {
|
||||
container.discoverComponents(
|
||||
extension.getClassRealm(),
|
||||
new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
try {
|
||||
container.lookup(Injector.class).discover(extension.getClassRealm());
|
||||
} catch (Throwable e) {
|
||||
// ignore
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
},
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue