diff --git a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Inject.java b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Inject.java index 29df0db7b484..eb02bb38331b 100644 --- a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Inject.java +++ b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Inject.java @@ -27,6 +27,32 @@ import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; +/** + * Marks a dependency injection point for constructor, method, or field injection. + *

+ * This annotation is used to identify injection points where the container should + * provide an instance of the requested type. It can be applied to: + *

+ *

+ * Example usage: + *

+ * public class MyService {
+ *     private final Repository repository;
+ *
+ *     {@literal @}Inject
+ *     public MyService(Repository repository) {
+ *         this.repository = repository;
+ *     }
+ * }
+ * 
+ * + * @see Named + * @since 4.0.0 + */ @Target({FIELD, CONSTRUCTOR, METHOD}) @Retention(RUNTIME) @Documented diff --git a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Named.java b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Named.java index 933c375042b3..fbd400f9f6b3 100644 --- a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Named.java +++ b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Named.java @@ -23,9 +23,37 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; +/** + * Provides a unique identifier for dependencies when multiple implementations + * of the same type are available. + *

+ * This annotation can be used in conjunction with {@link Inject} to specify + * which implementation should be injected when multiple candidates exist. + * The value represents a unique identifier for the dependency. + *

+ * Example usage: + *

+ * {@literal @}Inject
+ * {@literal @}Named("mysql")
+ * private Repository mysqlRepository;
+ * 
+ * + * @see Inject + * @see Qualifier + * @since 4.0.0 + */ @Qualifier @Retention(RUNTIME) @Documented public @interface Named { + /** + * The name identifier for the annotated element. + *

+ * If no value is specified, the default empty string will be used. + * When used as a qualifier, this value helps distinguish between different + * implementations or instances of the same type. + * + * @return the name that identifies this component + */ String value() default ""; } diff --git a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Priority.java b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Priority.java index f2eae991c5c9..dd57461be31e 100644 --- a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Priority.java +++ b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Priority.java @@ -26,9 +26,39 @@ import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; +/** + * Specifies the priority of a bean implementation when multiple implementations + * of the same type are available. + *

+ * Higher values indicate higher priority. When multiple implementations of the same + * type exist, the one with the highest priority will be selected for injection. + *

+ * Example usage: + *

+ * {@literal @}Priority(100)
+ * public class PreferredImplementation implements Service {
+ *     // Implementation
+ * }
+ * 
+ * + * @since 4.0.0 + */ @Target({TYPE, METHOD}) @Retention(RUNTIME) @Documented public @interface Priority { + /** + * The priority value for the annotated element. + *

+ * Higher values indicate higher priority. When multiple implementations + * of the same type exist in the container, the one with the highest + * priority value will be selected for injection. + *

+ * There are no predefined minimum or maximum values, but it's recommended + * to use values that allow for future adjustments (e.g., using values + * like 100, 200, 300 rather than consecutive numbers). + * + * @return the priority value for ordering + */ int value(); } diff --git a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Provides.java b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Provides.java index 2a782505ebb3..73bf7120596d 100644 --- a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Provides.java +++ b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Provides.java @@ -26,7 +26,25 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; /** - * Can be used on a static method to provide a bean. + * Marks a method as a provider of beans for dependency injection. + *

+ * This annotation can be used on static methods to programmatically create and configure + * beans that will be managed by the dependency injection container. It's particularly + * useful when the bean creation requires complex logic or when the bean needs to be + * configured based on runtime conditions. + *

+ * Example usage: + *

+ * public class Providers {
+ *     {@literal @}Provides
+ *     {@literal @}Singleton
+ *     public static Configuration provideConfiguration() {
+ *         return Configuration.load();
+ *     }
+ * }
+ * 
+ * + * @since 4.0.0 */ @Target(METHOD) @Retention(RUNTIME) diff --git a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Qualifier.java b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Qualifier.java index 863618280d20..db778db4617e 100644 --- a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Qualifier.java +++ b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Qualifier.java @@ -25,6 +25,25 @@ import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; +/** + * Meta-annotation that marks other annotations as qualifier annotations. + *

+ * Qualifiers are used to distinguish between multiple beans of the same type, + * allowing for more precise control over which implementation should be injected. + * Custom qualifier annotations should be annotated with {@code @Qualifier}. + *

+ * Example of creating a custom qualifier: + *

+ * {@literal @}Qualifier
+ * {@literal @}Retention(RUNTIME)
+ * public @interface Database {
+ *     String value();
+ * }
+ * 
+ * + * @see Named + * @since 4.0.0 + */ @Target(ANNOTATION_TYPE) @Retention(RUNTIME) @Documented diff --git a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Scope.java b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Scope.java index 80b50b5d210d..9468fbfe452e 100644 --- a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Scope.java +++ b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Scope.java @@ -25,6 +25,24 @@ import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; +/** + * Meta-annotation that marks other annotations as scope annotations. + *

+ * Scopes define the lifecycle and visibility of objects in the dependency injection + * system. Custom scope annotations should be annotated with {@code @Scope}. + *

+ * Built-in scopes include: + *

+ * + * @see Singleton + * @see SessionScoped + * @see MojoExecutionScoped + * @since 4.0.0 + */ @Target(ANNOTATION_TYPE) @Retention(RUNTIME) @Documented diff --git a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Singleton.java b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Singleton.java index 79b440ce767a..0a64845e1f55 100644 --- a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Singleton.java +++ b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Singleton.java @@ -23,6 +23,24 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; +/** + * Denotes that a bean should be created as a singleton instance. + *

+ * Singleton-scoped beans are instantiated once and reused throughout the entire + * Maven execution. This scope should be used for stateless services or components + * that can be safely shared across the entire build process. + *

+ * Example usage: + *

+ * {@literal @}Singleton
+ * public class GlobalConfiguration {
+ *     // Implementation
+ * }
+ * 
+ * + * @see Scope + * @since 4.0.0 + */ @Scope @Documented @Retention(RUNTIME) diff --git a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Typed.java b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Typed.java index d92ba9782102..dd4a3967e551 100644 --- a/api/maven-api-di/src/main/java/org/apache/maven/api/di/Typed.java +++ b/api/maven-api-di/src/main/java/org/apache/maven/api/di/Typed.java @@ -27,9 +27,44 @@ import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; +/** + * Explicitly specifies the types that should be used for dependency injection. + *

+ * This annotation allows you to limit which types of a bean should be available + * for injection. It can be used to prevent unintended automatic binding of implemented + * interfaces or extended classes. + *

+ * Example usage: + *

+ * {@literal @}Typed(ServiceImpl.class)
+ * public class ServiceImpl implements Service {
+ *     // Implementation
+ * }
+ * 
+ * + * @since 4.0.0 + */ @Target({FIELD, METHOD, TYPE}) @Retention(RUNTIME) @Documented public @interface Typed { + /** + * Specifies the types that should be considered for dependency injection. + *

+ * When specified, only the listed types will be available for injection, + * even if the class implements or extends other types. If empty, the + * default behavior is to make all supertypes available for injection. + *

+ * Example: + *

+     * {@literal @}Typed({Service.class, Monitored.class})
+     * public class ServiceImpl implements Service, Monitored, Logging {
+     *     // Only Service and Monitored will be available for injection,
+     *     // Logging interface will be ignored
+     * }
+     * 
+ * + * @return an array of classes that should be considered for injection + */ Class[] value() default {}; } diff --git a/api/maven-api-di/src/main/java/org/apache/maven/api/di/package-info.java b/api/maven-api-di/src/main/java/org/apache/maven/api/di/package-info.java new file mode 100644 index 000000000000..8cda82936a36 --- /dev/null +++ b/api/maven-api-di/src/main/java/org/apache/maven/api/di/package-info.java @@ -0,0 +1,21 @@ +/** + * A dependency injection framework for Maven that provides JSR-330 style annotations + * for managing object lifecycle and dependencies within Maven's build process. + *

+ * This package provides a set of annotations that control how objects are created, + * managed and injected throughout Maven's execution lifecycle. The framework is designed + * to be lightweight yet powerful, supporting various scopes of object lifecycle from + * singleton instances to mojo-execution-scoped beans. + *

+ * Key features include: + *

+ * + * @since 4.0.0 + */ +package org.apache.maven.api.di; diff --git a/impl/maven-di/src/main/java/org/apache/maven/di/Injector.java b/impl/maven-di/src/main/java/org/apache/maven/di/Injector.java index 56b2212650d2..8a95f0fd6f03 100644 --- a/impl/maven-di/src/main/java/org/apache/maven/di/Injector.java +++ b/impl/maven-di/src/main/java/org/apache/maven/di/Injector.java @@ -24,41 +24,141 @@ import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.di.impl.InjectorImpl; +/** + * The main entry point for Maven's dependency injection framework. + *

+ * The Injector manages the creation and injection of objects within the Maven build process. + * It provides both a builder API for configuring the injection behavior and methods for + * accessing and injecting beans. + *

+ * Example usage: + *

+ * Injector injector = Injector.create()
+ *     .discover(getClass().getClassLoader())
+ *     .bindInstance(Configuration.class, config);
+ *
+ * MyService service = injector.getInstance(MyService.class);
+ * 
+ * + * @since 4.0.0 + */ public interface Injector { - // - // Builder API - // - + /** + * Creates a new Injector instance with default settings. + * + * @return a new Injector instance + */ @Nonnull static Injector create() { return new InjectorImpl(); } + /** + * Configures the injector to discover injectable components from the specified ClassLoader. + *

+ * This method scans for classes annotated with injection-related annotations and + * automatically registers them with the injector. + * + * @param classLoader the ClassLoader to scan for injectable components + * @return this injector instance for method chaining + * @throws NullPointerException if classLoader is null + */ @Nonnull Injector discover(@Nonnull ClassLoader classLoader); + /** + * Binds a scope annotation to its implementation. + *

+ * This allows custom scopes to be registered with the injector. The scope annotation + * must be annotated with {@link org.apache.maven.api.di.Scope}. + * + * @param scopeAnnotation the annotation class that defines the scope + * @param scope the scope implementation + * @return this injector instance for method chaining + * @throws NullPointerException if either parameter is null + */ @Nonnull Injector bindScope(@Nonnull Class scopeAnnotation, @Nonnull Scope scope); + /** + * Binds a scope annotation to a supplier that creates scope implementations. + *

+ * Similar to {@link #bindScope(Class, Scope)} but allows lazy creation of scope + * implementations. + * + * @param scopeAnnotation the annotation class that defines the scope + * @param scope supplier that creates scope implementations + * @return this injector instance for method chaining + * @throws NullPointerException if either parameter is null + */ @Nonnull Injector bindScope(@Nonnull Class scopeAnnotation, @Nonnull Supplier scope); + /** + * Registers a class for implicit binding. + *

+ * Implicit bindings allow the injector to create instances of classes without + * explicit binding definitions. The class must have appropriate injection annotations. + * + * @param cls the class to register for implicit binding + * @return this injector instance for method chaining + * @throws NullPointerException if cls is null + */ @Nonnull Injector bindImplicit(@Nonnull Class cls); + /** + * Binds a specific instance to a class type. + *

+ * This method allows pre-created instances to be used for injection instead of + * having the injector create new instances. + * + * @param the type of the instance + * @param cls the class to bind to + * @param instance the instance to use for injection + * @return this injector instance for method chaining + * @throws NullPointerException if either parameter is null + */ @Nonnull Injector bindInstance(@Nonnull Class cls, @Nonnull T instance); - // - // Bean access - // - + /** + * Performs field and method injection on an existing instance. + *

+ * This method will inject dependencies into annotated fields and methods of + * the provided instance but will not create a new instance. + * + * @param the type of the instance + * @param instance the instance to inject dependencies into + * @throws NullPointerException if instance is null + */ void injectInstance(@Nonnull T instance); + /** + * Retrieves or creates an instance of the specified type. + * + * @param the type to retrieve + * @param key the class representing the type to retrieve + * @return an instance of the requested type + * @throws NullPointerException if key is null + * @throws IllegalStateException if the type cannot be provided + */ @Nonnull T getInstance(@Nonnull Class key); + /** + * Retrieves or creates an instance for the specified key. + *

+ * This method allows retrieval of instances with specific qualifiers or + * generic type parameters. + * + * @param the type to retrieve + * @param key the key identifying the instance to retrieve + * @return an instance matching the requested key + * @throws NullPointerException if key is null + * @throws IllegalStateException if the type cannot be provided + */ @Nonnull T getInstance(@Nonnull Key key); } diff --git a/impl/maven-di/src/main/java/org/apache/maven/di/Key.java b/impl/maven-di/src/main/java/org/apache/maven/di/Key.java index 6ea17f8e0b54..4186e96fc764 100644 --- a/impl/maven-di/src/main/java/org/apache/maven/di/Key.java +++ b/impl/maven-di/src/main/java/org/apache/maven/di/Key.java @@ -27,19 +27,26 @@ import org.apache.maven.di.impl.Types; /** - * 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. + * A binding key that uniquely identifies a dependency in the injection system. *

- * 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. + * Keys combine a type with an optional qualifier to uniquely identify dependencies + * within the injection system. They also serve as type tokens, allowing preservation + * of generic type information at runtime. *

- * For example, to create a key of type Map<String, List<Integer>>, you can just use - * this syntax: new Key<Map<String, List<Integer>>>(){}. - *

- * If your types are not known at compile time, you can use {@link Types#parameterizedType} to make a - * parameterized type and give it to a {@link #ofType Key.ofType} constructor. + * Example usage: + *

+ * // Simple key for a type
+ * Key<Service> simple = Key.of(Service.class);
+ *
+ * // Key with generic type information
+ * Key<List<String>> generic = new Key<List<String>>(){};
  *
- * @param  binding type
+ * // Key with qualifier
+ * Key<Service> qualified = Key.of(Service.class, "primary");
+ * 
+ * + * @param The type this key represents + * @since 4.0.0 */ public abstract class Key { private final Type type; @@ -67,10 +74,27 @@ static final class KeyImpl extends Key { } } + /** + * Creates a new Key instance for the specified type. + * + * @param the type parameter + * @param type the Class object representing the type + * @return a new Key instance + * @throws NullPointerException if type is null + */ public static Key of(Class type) { return new KeyImpl<>(type, null); } + /** + * Creates a new Key instance for the specified type with a qualifier. + * + * @param the type parameter + * @param type the Class object representing the type + * @param qualifier the qualifier object (typically an annotation instance) + * @return a new Key instance + * @throws NullPointerException if type is null + */ public static Key of(Class type, @Nullable Object qualifier) { return new KeyImpl<>(type, qualifier); } @@ -93,6 +117,13 @@ private Type getTypeParameter() { : typeArgument; } + /** + * Returns the actual type represented by this key. + *

+ * This includes full generic type information if available. + * + * @return the type represented by this key + */ public Type getType() { return type; } @@ -118,6 +149,11 @@ public Key getTypeParameter(int index) { throw new IllegalStateException("Expected type from key " + getDisplayString() + " to be parameterized"); } + /** + * Returns the qualifier associated with this key, if any. + * + * @return the qualifier object or null if none exists + */ public @Nullable Object getQualifier() { return qualifier; } diff --git a/impl/maven-di/src/main/java/org/apache/maven/di/Scope.java b/impl/maven-di/src/main/java/org/apache/maven/di/Scope.java index 5da978b64a8f..be3456ab1b89 100644 --- a/impl/maven-di/src/main/java/org/apache/maven/di/Scope.java +++ b/impl/maven-di/src/main/java/org/apache/maven/di/Scope.java @@ -24,28 +24,46 @@ 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 no scope, 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. + * Defines how object instances are managed within a specific scope. *

- * 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. + * A Scope controls the lifecycle and visibility of objects created by the injector. + * It determines when new instances are created and when existing instances can be + * reused. This allows for different caching strategies depending on the desired + * lifecycle of the objects. *

- * The following scopes are currently supported: - *

    - *
  • {@link org.apache.maven.api.di.Singleton @Singleton}
  • - *
  • {@link org.apache.maven.api.di.SessionScoped @SessionScoped}
  • - *
  • {@link org.apache.maven.api.di.MojoExecutionScoped @MojoExecutionScoped}
  • - *
+ * Example implementation for a simple caching scope: + *
+ * public class CachingScope implements Scope {
+ *     private final Map<Key<?>, Object> cache = new ConcurrentHashMap<>();
  *
+ *     {@literal @}Override
+ *     public <T> Supplier<T> scope(Key<T> key, Supplier<T> unscoped) {
+ *         return () -> {
+ *             return (T) cache.computeIfAbsent(key, k -> unscoped.get());
+ *         };
+ *     }
+ * }
+ * 
+ * + * @see org.apache.maven.api.di.Scope * @since 4.0.0 */ @Experimental public interface Scope { + /** + * Scopes a supplier of instances. + *

+ * This method wraps an unscoped instance supplier with scope-specific logic + * that controls when new instances are created versus when existing instances + * are reused. + * + * @param the type of instance being scoped + * @param key the key identifying the instance type + * @param unscoped the original unscoped instance supplier + * @return a scoped supplier that implements the scope's caching strategy + * @throws NullPointerException if key or unscoped is null + */ @Nonnull Supplier scope(@Nonnull Key key, @Nonnull Supplier unscoped); } diff --git a/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java b/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java index 720a095d8b8d..2ae17635334b 100644 --- a/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java +++ b/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java @@ -47,6 +47,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.di.Provides; import org.apache.maven.api.di.Qualifier; import org.apache.maven.api.di.Singleton; @@ -65,26 +66,29 @@ public InjectorImpl() { bindScope(Singleton.class, new SingletonScope()); } + @Nonnull @Override - public T getInstance(Class key) { + public T getInstance(@Nonnull Class key) { return getInstance(Key.of(key)); } + @Nonnull @Override - public T getInstance(Key key) { + public T getInstance(@Nonnull Key key) { return getCompiledBinding(new Dependency<>(key, false)).get(); } @SuppressWarnings("unchecked") @Override - public void injectInstance(T instance) { + public void injectInstance(@Nonnull T instance) { ReflectionUtils.generateInjectingInitializer(Key.of((Class) instance.getClass())) .compile(this::getCompiledBinding) .accept(instance); } + @Nonnull @Override - public Injector discover(ClassLoader classLoader) { + public Injector discover(@Nonnull ClassLoader classLoader) { try { Enumeration enumeration = classLoader.getResources("META-INF/maven/org.apache.maven.api.di.Inject"); while (enumeration.hasMoreElements()) { @@ -107,13 +111,15 @@ public Injector discover(ClassLoader classLoader) { return this; } + @Nonnull @Override - public Injector bindScope(Class scopeAnnotation, Scope scope) { + public Injector bindScope(@Nonnull Class scopeAnnotation, @Nonnull Scope scope) { return bindScope(scopeAnnotation, () -> scope); } + @Nonnull @Override - public Injector bindScope(Class scopeAnnotation, Supplier scope) { + public Injector bindScope(@Nonnull Class scopeAnnotation, @Nonnull Supplier scope) { if (scopes.put(scopeAnnotation, scope) != null) { throw new DIException( "Cannot rebind scope annotation class to a different implementation: " + scopeAnnotation); @@ -121,15 +127,17 @@ public Injector bindScope(Class scopeAnnotation, Supplier< return this; } + @Nonnull @Override - public Injector bindInstance(Class clazz, U instance) { + public Injector bindInstance(@Nonnull Class clazz, @Nonnull U instance) { Key key = Key.of(clazz, ReflectionUtils.qualifierOf(clazz)); Binding binding = Binding.toInstance(instance); return doBind(key, binding); } + @Nonnull @Override - public Injector bindImplicit(Class clazz) { + public Injector bindImplicit(@Nonnull Class clazz) { Key key = Key.of(clazz, ReflectionUtils.qualifierOf(clazz)); if (clazz.isInterface()) { bindings.computeIfAbsent(key, $ -> new HashSet<>()); @@ -382,9 +390,11 @@ public int size() { private static class SingletonScope implements Scope { Map, java.util.function.Supplier> cache = new ConcurrentHashMap<>(); + @Nonnull @SuppressWarnings("unchecked") @Override - public java.util.function.Supplier scope(Key key, java.util.function.Supplier unscoped) { + public java.util.function.Supplier scope( + @Nonnull Key key, @Nonnull java.util.function.Supplier unscoped) { return (java.util.function.Supplier) cache.computeIfAbsent(key, k -> new java.util.function.Supplier() { volatile T instance; diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/di/SessionScope.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/di/SessionScope.java index 95a9a08af142..b47c5acde830 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/di/SessionScope.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/di/SessionScope.java @@ -30,6 +30,7 @@ import java.util.function.Supplier; import java.util.stream.Stream; +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.Types; @@ -85,8 +86,9 @@ public void seed(Class clazz, T value) { seed(clazz, (Supplier) () -> value); } + @Nonnull @Override - public Supplier scope(Key key, Supplier unscoped) { + public Supplier scope(@Nonnull Key key, @Nonnull Supplier unscoped) { // Lazy evaluating provider return () -> { if (values.isEmpty()) {