mirror of https://github.com/apache/maven.git
DI improvements (#1717)
* Code cleanup * Provide build path with causes when an exception occur * Fix toString to display meaningful info * Javadoc * Add @NonNull and @Overrides annotations * Support for @Nullable on fields and parameters
This commit is contained in:
parent
36de1c6e51
commit
bcd5d9c9f9
|
@ -29,6 +29,13 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
/**
|
||||
* Indicates that the annotated bean has a lifespan limited to a given mojo execution,
|
||||
* which means each mojo execution will result in a different instance being injected.
|
||||
* <p>
|
||||
* The following objects will be bound to the mojo execution scope:
|
||||
* <ul>
|
||||
* <li>{@code org.apache.maven.api.MojoExecution}</li>
|
||||
* <li>{@code org.apache.maven.api.Project}</li>
|
||||
* <li>{@code org.apache.maven.api.plugin.Log}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
|
|
|
@ -29,6 +29,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
/**
|
||||
* Indicates that annotated component should be instantiated before session execution starts
|
||||
* and discarded after session execution completes.
|
||||
* <p>
|
||||
* A {@code org.apache.maven.api.Session} object is available in the scope of this annotation.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
|
|
|
@ -30,5 +30,5 @@ import java.lang.annotation.RetentionPolicy;
|
|||
*/
|
||||
@Experimental
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Nullable {}
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.apache.maven.di.Injector;
|
|||
import org.apache.maven.di.Key;
|
||||
import org.apache.maven.di.impl.Binding;
|
||||
import org.apache.maven.di.impl.DIException;
|
||||
import org.apache.maven.di.impl.Dependency;
|
||||
import org.apache.maven.di.impl.InjectorImpl;
|
||||
import org.apache.maven.execution.scope.internal.MojoExecutionScope;
|
||||
import org.apache.maven.session.scope.internal.SessionScope;
|
||||
|
@ -66,7 +67,8 @@ public class SisuDiBridgeModule extends AbstractModule {
|
|||
|
||||
injector = new InjectorImpl() {
|
||||
@Override
|
||||
public <Q> Supplier<Q> getCompiledBinding(Key<Q> key) {
|
||||
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);
|
||||
|
@ -119,6 +121,9 @@ public class SisuDiBridgeModule extends AbstractModule {
|
|||
// ignore
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (dep.optional()) {
|
||||
return () -> null;
|
||||
}
|
||||
throw new DIException("No binding to construct an instance for key "
|
||||
+ key.getDisplayString() + ". Existing bindings:\n"
|
||||
+ getBoundKeys().stream()
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.apache.maven.di;
|
|||
import java.lang.annotation.Annotation;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.maven.api.annotations.Nonnull;
|
||||
import org.apache.maven.di.impl.InjectorImpl;
|
||||
|
||||
public interface Injector {
|
||||
|
@ -29,18 +30,24 @@ public interface Injector {
|
|||
// Builder API
|
||||
//
|
||||
|
||||
@Nonnull
|
||||
static Injector create() {
|
||||
return new InjectorImpl();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
Injector discover(ClassLoader classLoader);
|
||||
|
||||
@Nonnull
|
||||
Injector bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope);
|
||||
|
||||
@Nonnull
|
||||
Injector bindScope(Class<? extends Annotation> scopeAnnotation, Supplier<Scope> scope);
|
||||
|
||||
@Nonnull
|
||||
Injector bindImplicit(Class<?> cls);
|
||||
|
||||
@Nonnull
|
||||
<T> Injector bindInstance(Class<T> cls, T instance);
|
||||
|
||||
//
|
||||
|
|
|
@ -34,16 +34,16 @@ import org.apache.maven.di.Key;
|
|||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
public abstract class Binding<T> {
|
||||
private final Set<Key<?>> dependencies;
|
||||
private final Set<Dependency<?>> dependencies;
|
||||
private Annotation scope;
|
||||
private int priority;
|
||||
private Key<?> originalKey;
|
||||
|
||||
protected Binding(Key<? extends T> originalKey, Set<Key<?>> dependencies) {
|
||||
protected Binding(Key<? extends T> originalKey, Set<Dependency<?>> dependencies) {
|
||||
this(originalKey, dependencies, null, 0);
|
||||
}
|
||||
|
||||
protected Binding(Key<?> originalKey, Set<Key<?>> dependencies, Annotation scope, int priority) {
|
||||
protected Binding(Key<?> originalKey, Set<Dependency<?>> dependencies, Annotation scope, int priority) {
|
||||
this.originalKey = originalKey;
|
||||
this.dependencies = dependencies;
|
||||
this.scope = scope;
|
||||
|
@ -56,15 +56,18 @@ public abstract class Binding<T> {
|
|||
|
||||
public static <R> Binding<R> to(Key<R> originalKey, TupleConstructorN<R> constructor, Class<?>[] types) {
|
||||
return Binding.to(
|
||||
originalKey, constructor, Stream.of(types).map(Key::of).toArray(Key<?>[]::new));
|
||||
originalKey,
|
||||
constructor,
|
||||
Stream.of(types).map(c -> new Dependency<>(Key.of(c), false)).toArray(Dependency<?>[]::new));
|
||||
}
|
||||
|
||||
public static <R> Binding<R> to(Key<R> originalKey, TupleConstructorN<R> constructor, Key<?>[] dependencies) {
|
||||
public static <R> Binding<R> to(
|
||||
Key<R> originalKey, TupleConstructorN<R> constructor, Dependency<?>[] dependencies) {
|
||||
return to(originalKey, constructor, dependencies, 0);
|
||||
}
|
||||
|
||||
public static <R> Binding<R> to(
|
||||
Key<R> originalKey, TupleConstructorN<R> constructor, Key<?>[] dependencies, int priority) {
|
||||
Key<R> originalKey, TupleConstructorN<R> constructor, Dependency<?>[] dependencies, int priority) {
|
||||
return new BindingToConstructor<>(originalKey, constructor, dependencies, priority);
|
||||
}
|
||||
|
||||
|
@ -94,13 +97,17 @@ public abstract class Binding<T> {
|
|||
this.scope,
|
||||
this.priority) {
|
||||
@Override
|
||||
public Supplier<T> compile(Function<Key<?>, Supplier<?>> compiler) {
|
||||
public Supplier<T> compile(Function<Dependency<?>, Supplier<?>> compiler) {
|
||||
final Supplier<T> compiledBinding = Binding.this.compile(compiler);
|
||||
final Consumer<T> consumer = bindingInitializer.compile(compiler);
|
||||
return () -> {
|
||||
T instance = compiledBinding.get();
|
||||
consumer.accept(instance);
|
||||
return instance;
|
||||
try {
|
||||
T instance = compiledBinding.get();
|
||||
consumer.accept(instance);
|
||||
return instance;
|
||||
} catch (DIException e) {
|
||||
throw new DIException("Error while initializing binding " + Binding.this, e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -111,9 +118,9 @@ public abstract class Binding<T> {
|
|||
};
|
||||
}
|
||||
|
||||
public abstract Supplier<T> compile(Function<Key<?>, Supplier<?>> compiler);
|
||||
public abstract Supplier<T> compile(Function<Dependency<?>, Supplier<?>> compiler);
|
||||
|
||||
public Set<Key<?>> getDependencies() {
|
||||
public Set<Dependency<?>> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
|
@ -122,7 +129,7 @@ public abstract class Binding<T> {
|
|||
}
|
||||
|
||||
public String getDisplayString() {
|
||||
return dependencies.stream().map(Key::getDisplayString).collect(joining(", ", "[", "]"));
|
||||
return dependencies.stream().map(Dependency::getDisplayString).collect(joining(", ", "[", "]"));
|
||||
}
|
||||
|
||||
public Key<?> getOriginalKey() {
|
||||
|
@ -152,7 +159,7 @@ public abstract class Binding<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Supplier<T> compile(Function<Key<?>, Supplier<?>> compiler) {
|
||||
public Supplier<T> compile(Function<Dependency<?>, Supplier<?>> compiler) {
|
||||
return () -> instance;
|
||||
}
|
||||
|
||||
|
@ -164,17 +171,17 @@ public abstract class Binding<T> {
|
|||
|
||||
public static class BindingToConstructor<T> extends Binding<T> {
|
||||
final TupleConstructorN<T> constructor;
|
||||
final Key<?>[] args;
|
||||
final Dependency<?>[] args;
|
||||
|
||||
BindingToConstructor(
|
||||
Key<? extends T> key, TupleConstructorN<T> constructor, Key<?>[] dependencies, int priority) {
|
||||
Key<? extends T> key, TupleConstructorN<T> constructor, Dependency<?>[] dependencies, int priority) {
|
||||
super(key, new HashSet<>(Arrays.asList(dependencies)), null, priority);
|
||||
this.constructor = constructor;
|
||||
this.args = dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<T> compile(Function<Key<?>, Supplier<?>> compiler) {
|
||||
public Supplier<T> compile(Function<Dependency<?>, Supplier<?>> compiler) {
|
||||
return () -> {
|
||||
Object[] args =
|
||||
Stream.of(this.args).map(compiler).map(Supplier::get).toArray();
|
||||
|
@ -184,7 +191,7 @@ public abstract class Binding<T> {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BindingToConstructor[" + constructor + "]" + getDependencies();
|
||||
return "BindingToConstructor[" + getOriginalKey() + "]" + getDependencies();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,32 +25,30 @@ import java.util.function.Consumer;
|
|||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.maven.di.Key;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
public abstract class BindingInitializer<T> {
|
||||
|
||||
private final Set<Key<?>> dependencies;
|
||||
private final Set<Dependency<?>> dependencies;
|
||||
|
||||
protected BindingInitializer(Set<Key<?>> dependencies) {
|
||||
protected BindingInitializer(Set<Dependency<?>> dependencies) {
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
|
||||
public Set<Key<?>> getDependencies() {
|
||||
public Set<Dependency<?>> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
public abstract Consumer<T> compile(Function<Key<?>, Supplier<?>> compiler);
|
||||
public abstract Consumer<T> compile(Function<Dependency<?>, Supplier<?>> compiler);
|
||||
|
||||
public static <T> BindingInitializer<T> combine(List<BindingInitializer<T>> bindingInitializers) {
|
||||
Set<Key<?>> deps = bindingInitializers.stream()
|
||||
Set<Dependency<?>> deps = bindingInitializers.stream()
|
||||
.map(BindingInitializer::getDependencies)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(toSet());
|
||||
return new BindingInitializer<T>(deps) {
|
||||
return new BindingInitializer<>(deps) {
|
||||
@Override
|
||||
public Consumer<T> compile(Function<Key<?>, Supplier<?>> compiler) {
|
||||
public Consumer<T> compile(Function<Dependency<?>, Supplier<?>> compiler) {
|
||||
return instance -> bindingInitializers.stream()
|
||||
.map(bindingInitializer -> bindingInitializer.compile(compiler))
|
||||
.forEach(i -> i.accept(instance));
|
||||
|
|
|
@ -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.di.impl;
|
||||
|
||||
import org.apache.maven.di.Key;
|
||||
|
||||
public record Dependency<T>(Key<T> key, boolean optional) {
|
||||
public String getDisplayString() {
|
||||
String s = key.getDisplayString();
|
||||
if (optional) {
|
||||
s = "?" + s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
|
@ -64,12 +64,14 @@ public class InjectorImpl implements Injector {
|
|||
bindScope(Singleton.class, new SingletonScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInstance(Class<T> key) {
|
||||
return getInstance(Key.of(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInstance(Key<T> key) {
|
||||
return getCompiledBinding(key).get();
|
||||
return getCompiledBinding(new Dependency<>(key, false)).get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -88,7 +90,7 @@ public class InjectorImpl implements Injector {
|
|||
try (InputStream is = enumeration.nextElement().openStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(is)))) {
|
||||
for (String line :
|
||||
reader.lines().filter(l -> !l.startsWith("#")).collect(Collectors.toList())) {
|
||||
reader.lines().filter(l -> !l.startsWith("#")).toList()) {
|
||||
Class<?> clazz = classLoader.loadClass(line);
|
||||
bindImplicit(clazz);
|
||||
}
|
||||
|
@ -100,10 +102,12 @@ public class InjectorImpl implements Injector {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Injector bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) {
|
||||
return bindScope(scopeAnnotation, () -> scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Injector bindScope(Class<? extends Annotation> scopeAnnotation, Supplier<Scope> scope) {
|
||||
if (scopes.put(scopeAnnotation, scope) != null) {
|
||||
throw new DIException(
|
||||
|
@ -112,6 +116,7 @@ public class InjectorImpl implements Injector {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> Injector bindInstance(Class<U> clazz, U instance) {
|
||||
Key<?> key = Key.of(clazz, ReflectionUtils.qualifierOf(clazz));
|
||||
Binding<U> binding = Binding.toInstance(instance);
|
||||
|
@ -133,7 +138,7 @@ public class InjectorImpl implements Injector {
|
|||
return this;
|
||||
}
|
||||
|
||||
private LinkedHashSet<Key<?>> current = new LinkedHashSet<>();
|
||||
private final LinkedHashSet<Key<?>> current = new LinkedHashSet<>();
|
||||
|
||||
private Injector doBind(Key<?> key, Binding<?> binding) {
|
||||
if (!current.add(key)) {
|
||||
|
@ -175,7 +180,8 @@ public class InjectorImpl implements Injector {
|
|||
return bindings;
|
||||
}
|
||||
|
||||
public <Q> Supplier<Q> getCompiledBinding(Key<Q> key) {
|
||||
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);
|
||||
|
@ -211,6 +217,9 @@ public class InjectorImpl implements Injector {
|
|||
return () -> (Q) map(map);
|
||||
}
|
||||
}
|
||||
if (dep.optional()) {
|
||||
return () -> null;
|
||||
}
|
||||
throw new DIException("No binding to construct an instance for key "
|
||||
+ key.getDisplayString() + ". Existing bindings:\n"
|
||||
+ getBoundKeys().stream()
|
||||
|
@ -312,14 +321,13 @@ public class InjectorImpl implements Injector {
|
|||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return new AbstractSet<Entry<K, V>>() {
|
||||
return new AbstractSet<>() {
|
||||
@Override
|
||||
public Iterator<Entry<K, V>> iterator() {
|
||||
Iterator<Entry<K, T>> it = delegate.entrySet().iterator();
|
||||
return new Iterator<Entry<K, V>>() {
|
||||
return new Iterator<>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
|
|
|
@ -171,14 +171,14 @@ public final class ReflectionUtils {
|
|||
List<Constructor<?>> constructors = Arrays.asList(cls.getDeclaredConstructors());
|
||||
List<Constructor<?>> injectConstructors = constructors.stream()
|
||||
.filter(c -> c.isAnnotationPresent(Inject.class))
|
||||
.collect(toList());
|
||||
.toList();
|
||||
|
||||
List<Method> factoryMethods = Arrays.stream(cls.getDeclaredMethods())
|
||||
.filter(method -> method.getReturnType() == cls && Modifier.isStatic(method.getModifiers()))
|
||||
.collect(toList());
|
||||
.toList();
|
||||
List<Method> injectFactoryMethods = factoryMethods.stream()
|
||||
.filter(method -> method.isAnnotationPresent(Inject.class))
|
||||
.collect(toList());
|
||||
.toList();
|
||||
|
||||
if (!injectConstructors.isEmpty()) {
|
||||
if (injectConstructors.size() > 1) {
|
||||
|
@ -240,10 +240,12 @@ public final class ReflectionUtils {
|
|||
public static <T> BindingInitializer<T> fieldInjector(Key<T> container, Field field) {
|
||||
field.setAccessible(true);
|
||||
Key<Object> key = keyOf(container.getType(), field.getGenericType(), field);
|
||||
return new BindingInitializer<T>(Collections.singleton(key)) {
|
||||
boolean optional = field.isAnnotationPresent(Nullable.class);
|
||||
Dependency<Object> dep = new Dependency<>(key, optional);
|
||||
return new BindingInitializer<T>(Collections.singleton(dep)) {
|
||||
@Override
|
||||
public Consumer<T> compile(Function<Key<?>, Supplier<?>> compiler) {
|
||||
Supplier<?> binding = compiler.apply(key);
|
||||
public Consumer<T> compile(Function<Dependency<?>, Supplier<?>> compiler) {
|
||||
Supplier<?> binding = compiler.apply(dep);
|
||||
return (T instance) -> {
|
||||
Object arg = binding.get();
|
||||
try {
|
||||
|
@ -258,10 +260,10 @@ public final class ReflectionUtils {
|
|||
|
||||
public static <T> BindingInitializer<T> methodInjector(Key<T> container, Method method) {
|
||||
method.setAccessible(true);
|
||||
Key<?>[] dependencies = toDependencies(container.getType(), method);
|
||||
Dependency<?>[] dependencies = toDependencies(container.getType(), method);
|
||||
return new BindingInitializer<T>(new HashSet<>(Arrays.asList(dependencies))) {
|
||||
@Override
|
||||
public Consumer<T> compile(Function<Key<?>, Supplier<?>> compiler) {
|
||||
public Consumer<T> compile(Function<Dependency<?>, Supplier<?>> compiler) {
|
||||
return instance -> {
|
||||
Object[] args = getDependencies().stream()
|
||||
.map(compiler)
|
||||
|
@ -279,35 +281,31 @@ public final class ReflectionUtils {
|
|||
};
|
||||
}
|
||||
|
||||
public static Key<?>[] toDependencies(@Nullable Type container, Executable executable) {
|
||||
Key<?>[] keys = toArgDependencies(container, executable);
|
||||
public static Dependency<?>[] toDependencies(@Nullable Type container, Executable executable) {
|
||||
Dependency<?>[] keys = toArgDependencies(container, executable);
|
||||
if (executable instanceof Constructor || Modifier.isStatic(executable.getModifiers())) {
|
||||
return keys;
|
||||
} else {
|
||||
Key<?>[] nkeys = new Key[keys.length + 1];
|
||||
nkeys[0] = Key.ofType(container);
|
||||
Dependency<?>[] nkeys = new Dependency[keys.length + 1];
|
||||
nkeys[0] = new Dependency<>(Key.ofType(container), false);
|
||||
System.arraycopy(keys, 0, nkeys, 1, keys.length);
|
||||
return nkeys;
|
||||
}
|
||||
}
|
||||
|
||||
private static Key<?>[] toArgDependencies(@Nullable Type container, Executable executable) {
|
||||
private static Dependency<?>[] toArgDependencies(@Nullable Type container, Executable executable) {
|
||||
Parameter[] parameters = executable.getParameters();
|
||||
Key<?>[] dependencies = new Key<?>[parameters.length];
|
||||
Dependency<?>[] dependencies = new Dependency<?>[parameters.length];
|
||||
if (parameters.length == 0) {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
Type type = parameters[0].getParameterizedType();
|
||||
Parameter parameter = parameters[0];
|
||||
dependencies[0] = keyOf(container, type, parameter);
|
||||
|
||||
Type[] genericParameterTypes = executable.getGenericParameterTypes();
|
||||
boolean hasImplicitDependency = genericParameterTypes.length != parameters.length;
|
||||
for (int i = 1; i < dependencies.length; i++) {
|
||||
type = genericParameterTypes[hasImplicitDependency ? i - 1 : i];
|
||||
parameter = parameters[i];
|
||||
dependencies[i] = keyOf(container, type, parameter);
|
||||
for (int i = 0; i < dependencies.length; i++) {
|
||||
Type type = genericParameterTypes[i];
|
||||
Parameter parameter = parameters[i];
|
||||
boolean optional = parameter.isAnnotationPresent(Nullable.class);
|
||||
dependencies[i] = new Dependency<>(keyOf(container, type, parameter), optional);
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
|
@ -353,7 +351,7 @@ public final class ReflectionUtils {
|
|||
public static <T> Binding<T> bindingFromConstructor(Key<T> key, Constructor<T> constructor) {
|
||||
constructor.setAccessible(true);
|
||||
|
||||
Key<?>[] dependencies = toDependencies(key.getType(), constructor);
|
||||
Dependency<?>[] dependencies = toDependencies(key.getType(), constructor);
|
||||
|
||||
Binding<T> binding = Binding.to(
|
||||
key,
|
||||
|
|
|
@ -186,8 +186,7 @@ public class Types {
|
|||
if (type instanceof Class) {
|
||||
return type;
|
||||
}
|
||||
if (type instanceof TypeVariable<?>) {
|
||||
TypeVariable<?> typeVariable = (TypeVariable<?>) type;
|
||||
if (type instanceof TypeVariable<?> typeVariable) {
|
||||
Type actualType = bindings.apply(typeVariable);
|
||||
if (actualType == null) {
|
||||
throw new TypeNotBoundException("Type variable not found: " + typeVariable + " ( "
|
||||
|
@ -195,8 +194,7 @@ public class Types {
|
|||
}
|
||||
return actualType;
|
||||
}
|
||||
if (type instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
if (type instanceof ParameterizedType parameterizedType) {
|
||||
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||
Type[] typeArguments2 = new Type[typeArguments.length];
|
||||
for (int i = 0; i < typeArguments.length; i++) {
|
||||
|
@ -209,8 +207,7 @@ public class Types {
|
|||
Type componentType = ((GenericArrayType) type).getGenericComponentType();
|
||||
return new GenericArrayTypeImpl(bind(componentType, bindings));
|
||||
}
|
||||
if (type instanceof WildcardType) {
|
||||
WildcardType wildcardType = (WildcardType) type;
|
||||
if (type instanceof WildcardType wildcardType) {
|
||||
Type[] upperBounds = wildcardType.getUpperBounds();
|
||||
Type[] upperBounds2 = new Type[upperBounds.length];
|
||||
for (int i = 0; i < upperBounds.length; i++) {
|
||||
|
@ -309,8 +306,7 @@ public class Types {
|
|||
return original;
|
||||
}
|
||||
|
||||
if (original instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) original;
|
||||
if (original instanceof ParameterizedType parameterizedType) {
|
||||
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||
Type[] repackedTypeArguments = simplifyTypes(typeArguments);
|
||||
|
||||
|
@ -329,8 +325,7 @@ public class Types {
|
|||
throw new IllegalArgumentException("Key should not contain a type variable: " + original);
|
||||
}
|
||||
|
||||
if (original instanceof WildcardType) {
|
||||
WildcardType wildcardType = (WildcardType) original;
|
||||
if (original instanceof WildcardType wildcardType) {
|
||||
Type[] upperBounds = wildcardType.getUpperBounds();
|
||||
if (upperBounds.length == 1) {
|
||||
Type upperBound = upperBounds[0];
|
||||
|
@ -398,8 +393,7 @@ public class Types {
|
|||
private static boolean isAssignable(Type to, Type from, boolean strict) {
|
||||
if (to instanceof WildcardType || from instanceof WildcardType) {
|
||||
Type[] toUppers, toLowers;
|
||||
if (to instanceof WildcardType) {
|
||||
WildcardType wildcardTo = (WildcardType) to;
|
||||
if (to instanceof WildcardType wildcardTo) {
|
||||
toUppers = wildcardTo.getUpperBounds();
|
||||
toLowers = wildcardTo.getLowerBounds();
|
||||
} else {
|
||||
|
@ -408,10 +402,9 @@ public class Types {
|
|||
}
|
||||
|
||||
Type[] fromUppers, fromLowers;
|
||||
if (from instanceof WildcardType) {
|
||||
WildcardType wildcardTo = (WildcardType) to;
|
||||
fromUppers = wildcardTo.getUpperBounds();
|
||||
fromLowers = wildcardTo.getLowerBounds();
|
||||
if (from instanceof WildcardType wildcardFrom) {
|
||||
fromUppers = wildcardFrom.getUpperBounds();
|
||||
fromLowers = wildcardFrom.getLowerBounds();
|
||||
} else {
|
||||
fromUppers = new Type[] {from};
|
||||
fromLowers = strict ? fromUppers : NO_TYPES;
|
||||
|
@ -523,10 +516,9 @@ public class Types {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof ParameterizedType)) {
|
||||
if (!(other instanceof ParameterizedType that)) {
|
||||
return false;
|
||||
}
|
||||
ParameterizedType that = (ParameterizedType) other;
|
||||
return this.getRawType().equals(that.getRawType())
|
||||
&& Objects.equals(this.getOwnerType(), that.getOwnerType())
|
||||
&& Arrays.equals(this.getActualTypeArguments(), that.getActualTypeArguments());
|
||||
|
@ -613,10 +605,9 @@ public class Types {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof WildcardType)) {
|
||||
if (!(other instanceof WildcardType that)) {
|
||||
return false;
|
||||
}
|
||||
WildcardType that = (WildcardType) other;
|
||||
return Arrays.equals(this.getUpperBounds(), that.getUpperBounds())
|
||||
&& Arrays.equals(this.getLowerBounds(), that.getLowerBounds());
|
||||
}
|
||||
|
@ -671,10 +662,9 @@ public class Types {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof GenericArrayType)) {
|
||||
if (!(other instanceof GenericArrayType that)) {
|
||||
return false;
|
||||
}
|
||||
GenericArrayType that = (GenericArrayType) other;
|
||||
return this.getGenericComponentType().equals(that.getGenericComponentType());
|
||||
}
|
||||
|
||||
|
@ -700,8 +690,7 @@ public class Types {
|
|||
return Arrays.stream(((ParameterizedType) type).getActualTypeArguments())
|
||||
.map(Types::getSimpleName)
|
||||
.collect(joining(",", "<", ">"));
|
||||
} else if (type instanceof WildcardType) {
|
||||
WildcardType wildcardType = (WildcardType) type;
|
||||
} else if (type instanceof WildcardType wildcardType) {
|
||||
Type[] upperBounds = wildcardType.getUpperBounds();
|
||||
Type[] lowerBounds = wildcardType.getLowerBounds();
|
||||
return "?"
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.maven.api.annotations.Nullable;
|
||||
import org.apache.maven.api.di.Inject;
|
||||
import org.apache.maven.api.di.Named;
|
||||
import org.apache.maven.api.di.Priority;
|
||||
|
@ -42,6 +43,7 @@ import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
|||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class InjectorImplTest {
|
||||
|
@ -328,4 +330,49 @@ public class InjectorImplTest {
|
|||
@Named
|
||||
static class Third {}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNullableOnField() {
|
||||
Injector injector = Injector.create().bindImplicit(NullableOnField.class);
|
||||
NullableOnField.MyMojo mojo = injector.getInstance(NullableOnField.MyMojo.class);
|
||||
assertNotNull(mojo);
|
||||
assertNull(mojo.service);
|
||||
}
|
||||
|
||||
static class NullableOnField {
|
||||
|
||||
@Named
|
||||
interface MyService {}
|
||||
|
||||
@Named
|
||||
static class MyMojo {
|
||||
@Inject
|
||||
@Nullable
|
||||
MyService service;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNullableOnConstructor() {
|
||||
Injector injector = Injector.create().bindImplicit(NullableOnConstructor.class);
|
||||
NullableOnConstructor.MyMojo mojo = injector.getInstance(NullableOnConstructor.MyMojo.class);
|
||||
assertNotNull(mojo);
|
||||
assertNull(mojo.service);
|
||||
}
|
||||
|
||||
static class NullableOnConstructor {
|
||||
|
||||
@Named
|
||||
interface MyService {}
|
||||
|
||||
@Named
|
||||
static class MyMojo {
|
||||
private final MyService service;
|
||||
|
||||
@Inject
|
||||
public MyMojo(@Nullable MyService service) {
|
||||
this.service = service;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue