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: + *
+ * 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: + *
+ * 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 extends Annotation> 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 extends Annotation> scopeAnnotation, @Nonnull Supplier
+ * 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
+ * This method will inject dependencies into annotated fields and methods of
+ * the provided instance but will not create a new instance.
+ *
+ * @param
+ * This method allows retrieval of instances with specific qualifiers or
+ * generic type parameters.
+ *
+ * @param
- * 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:
- * 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:
+ *
+ * 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:
- *
+ * 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 new Key<Map<String, List<Integer>>>(){}.
- *
+ * // 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
+ *
+ * @param
- *
+ * 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.
+ *