CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-micronaut--micronaut-inject

Core dependency injection interfaces and components for the Micronaut Framework

Pending
Overview
Eval results
Files

annotations.mddocs/

Annotations and Qualifiers

Micronaut's annotation system provides comprehensive support for dependency injection, bean scoping, conditional loading, and configuration binding. It combines Jakarta Inject standard annotations with Micronaut-specific enhancements for advanced features.

Jakarta Inject Annotations

@Inject

Marks constructors, methods, and fields for dependency injection.

@Target({METHOD, CONSTRUCTOR, FIELD})
@Retention(RUNTIME)
public @interface Inject {
}

Usage Examples:

import jakarta.inject.Inject;
import jakarta.inject.Singleton;

@Singleton
public class UserService {
    
    // Constructor injection (preferred)
    private final UserRepository repository;
    private final EmailService emailService;
    
    @Inject
    public UserService(UserRepository repository, EmailService emailService) {
        this.repository = repository;
        this.emailService = emailService;
    }
    
    // Field injection
    @Inject
    private ValidationService validationService;
    
    // Method injection  
    @Inject
    public void setAuditService(AuditService auditService) {
        this.auditService = auditService;
    }
}

@Singleton

Marks a class as a singleton bean - only one instance will be created.

@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Scope
public @interface Singleton {
}

Usage Examples:

import jakarta.inject.Singleton;

@Singleton
public class ConfigurationService {
    public String getConfigValue(String key) {
        // Implementation
        return "value";
    }
}

// Singleton factory method
@Singleton
public class ServiceFactory {
    
    @Singleton
    public DatabaseService createDatabaseService() {
        return new DatabaseService("jdbc:postgresql://localhost/db");
    }
}

@Named

Provides a name qualifier for bean selection when multiple beans of the same type exist.

@Target({TYPE, METHOD, FIELD, PARAMETER})
@Retention(RUNTIME)
@Qualifier
public @interface Named {
    String value() default "";
}

Usage Examples:

import jakarta.inject.Named;
import jakarta.inject.Singleton;
import jakarta.inject.Inject;

// Named bean definitions
@Singleton
@Named("mysql")
public class MySQLDatabaseService implements DatabaseService {
    // MySQL implementation
}

@Singleton
@Named("postgresql")  
public class PostgreSQLDatabaseService implements DatabaseService {
    // PostgreSQL implementation
}

// Named injection
@Singleton
public class DataProcessor {
    
    @Inject
    @Named("mysql")
    private DatabaseService primaryDb;
    
    @Inject  
    @Named("postgresql")
    private DatabaseService backupDb;
}

Micronaut Bean Annotations

@Bean

Marks a method or class as a bean definition, typically used in factory classes.

@Target({METHOD, TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
public @interface Bean {
    boolean typed() default true;
    boolean preDestroy() default true;
}

Usage Examples:

import io.micronaut.context.annotation.Bean;
import io.micronaut.context.annotation.Factory;
import jakarta.inject.Singleton;

@Factory
public class ServiceFactory {
    
    @Bean
    @Singleton
    public HttpClient createHttpClient() {
        return HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();
    }
    
    @Bean
    public ObjectMapper createObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapper;
    }
}

@Factory

Marks a class as a factory for creating beans, similar to @Configuration in Spring.

@Target({TYPE})
@Retention(RUNTIME)
public @interface Factory {
}

Usage Examples:

import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Bean;
import jakarta.inject.Singleton;

@Factory
public class DatabaseFactory {
    
    @Bean
    @Singleton
    public DataSource createDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:postgresql://localhost/mydb");
        config.setUsername("user");
        config.setPassword("password");
        return new HikariDataSource(config);
    }
    
    @Bean
    @Singleton  
    public JdbcTemplate createJdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

@Primary

Marks a bean as primary when multiple beans of the same type exist, making it the default choice.

@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface Primary {
}

Usage Examples:

import io.micronaut.context.annotation.Primary;
import jakarta.inject.Singleton;

// Multiple implementations
@Singleton
public class EmailService implements NotificationService {
    // Email implementation
}

@Singleton
@Primary  // This will be injected by default
public class SmsService implements NotificationService {
    // SMS implementation  
}

@Singleton
public class NotificationController {
    
    @Inject
    private NotificationService service; // SmsService will be injected due to @Primary
}

@Prototype

Marks a bean as prototype scoped - a new instance is created for each injection.

@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Scope
public @interface Prototype {
}

Usage Examples:

import io.micronaut.context.annotation.Prototype;

@Prototype
public class RequestHandler {
    private final String requestId;
    
    public RequestHandler() {
        this.requestId = UUID.randomUUID().toString();
    }
    
    public void processRequest() {
        System.out.println("Processing request: " + requestId);
    }
}

@Singleton
public class RequestProcessor {
    
    @Inject
    private RequestHandler handler; // New instance each time
}

Configuration Annotations

@Value

Injects configuration values using property placeholders.

@Target({FIELD, PARAMETER, METHOD})
@Retention(RUNTIME)
public @interface Value {
    String value();
}

Usage Examples:

import io.micronaut.context.annotation.Value;
import jakarta.inject.Singleton;

@Singleton
public class ApiService {
    
    @Value("${api.base-url}")
    private String baseUrl;
    
    @Value("${api.timeout:30}")  // Default value of 30
    private int timeoutSeconds;
    
    @Value("${api.key}")
    private String apiKey;
    
    // Constructor injection with @Value
    public ApiService(@Value("${api.version:v1}") String apiVersion) {
        this.apiVersion = apiVersion;
    }
}

@Property

Injects specific property values with optional defaults.

@Target({FIELD, PARAMETER, METHOD})
@Retention(RUNTIME)
public @interface Property {
    String name();
    String defaultValue() default "";
}

Usage Examples:

import io.micronaut.context.annotation.Property;
import jakarta.inject.Singleton;

@Singleton
public class DatabaseService {
    
    private final String url;
    private final String username;
    private final int maxConnections;
    
    public DatabaseService(
        @Property(name = "database.url") String url,
        @Property(name = "database.username") String username,
        @Property(name = "database.max-connections", defaultValue = "10") int maxConnections) {
        
        this.url = url;
        this.username = username;
        this.maxConnections = maxConnections;
    }
}

@ConfigurationProperties

Maps configuration properties to a bean, enabling type-safe configuration.

@Target({TYPE})
@Retention(RUNTIME)
public @interface ConfigurationProperties {
    String value() default "";
    boolean cliPrefix() default false;
}

Usage Examples:

import io.micronaut.context.annotation.ConfigurationProperties;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Min;

@ConfigurationProperties("redis")
public class RedisConfiguration {
    
    @NotBlank
    private String host = "localhost";
    
    @Min(1)
    private int port = 6379;
    
    private String password;
    private int database = 0;
    private int timeout = 2000;
    
    // Getters and setters
    public String getHost() { return host; }
    public void setHost(String host) { this.host = host; }
    
    public int getPort() { return port; }  
    public void setPort(int port) { this.port = port; }
    
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    
    public int getDatabase() { return database; }
    public void setDatabase(int database) { this.database = database; }
    
    public int getTimeout() { return timeout; }
    public void setTimeout(int timeout) { this.timeout = timeout; }
}

// Usage
@Singleton
public class RedisService {
    
    private final RedisConfiguration config;
    
    @Inject
    public RedisService(RedisConfiguration config) {
        this.config = config;
    }
    
    public void connect() {
        System.out.println("Connecting to Redis at " + config.getHost() + ":" + config.getPort());
    }
}

Conditional Annotations

@Requires

Conditionally loads beans based on various criteria.

@Target({PACKAGE, TYPE, METHOD})
@Retention(RUNTIME) 
@Repeatable(Requirements.class)
public @interface Requires {
    String property() default "";
    String[] value() default {};
    String defaultValue() default "";
    Class<?>[] beans() default {};
    Class<?>[] missingBeans() default {};
    String[] env() default {};
    String[] notEnv() default {};
    Class<? extends Condition>[] condition() default {};
    String os() default "";
    String[] notOs() default {};
    String sdk() default "";
    String[] classes() default {};
    String[] missingClasses() default {};
    String[] resources() default {};
    String[] missingProperties() default {};
}

Usage Examples:

import io.micronaut.context.annotation.Requires;
import jakarta.inject.Singleton;

// Conditional on property value
@Singleton
@Requires(property = "cache.enabled", value = "true")
public class CacheService {
    // Only created if cache.enabled=true
}

// Conditional on environment
@Singleton
@Requires(env = "prod")
public class ProductionDatabaseService implements DatabaseService {
    // Only loaded in production environment
}

// Conditional on missing bean
@Singleton
@Requires(missingBeans = DatabaseService.class)
public class DefaultDatabaseService implements DatabaseService {
    // Only created if no other DatabaseService exists
}

// Conditional on class presence
@Singleton
@Requires(classes = "org.springframework.data.redis.core.RedisTemplate")
public class RedisIntegrationService {
    // Only created if Redis classes are on classpath
}

// Multiple conditions
@Singleton
@Requires(property = "features.analytics", value = "true")
@Requires(env = {"prod", "staging"})
@Requires(beans = DatabaseService.class)
public class AnalyticsService {
    // Created only if all conditions are met
}

@Requirements

Groups multiple @Requires conditions.

@Target({PACKAGE, TYPE, METHOD})
@Retention(RUNTIME)
public @interface Requirements {
    Requires[] value();
}

Usage Examples:

import io.micronaut.context.annotation.Requirements;
import io.micronaut.context.annotation.Requires;

@Singleton
@Requirements({
    @Requires(property = "email.enabled", value = "true"),
    @Requires(classes = "javax.mail.internet.MimeMessage"),
    @Requires(beans = EmailConfiguration.class)
})
public class EmailService {
    // Created only if all requirements are satisfied
}

Qualifier Annotations

Custom Qualifiers

import io.micronaut.context.annotation.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Database {
    DatabaseType value();
}

public enum DatabaseType {
    MYSQL, POSTGRESQL, H2
}

// Usage
@Singleton
@Database(DatabaseType.MYSQL)
public class MySQLService implements DatabaseService {
    // MySQL implementation
}

@Singleton  
@Database(DatabaseType.POSTGRESQL)
public class PostgreSQLService implements DatabaseService {
    // PostgreSQL implementation
}

@Singleton
public class DataService {
    
    @Inject
    @Database(DatabaseType.MYSQL)
    private DatabaseService mysqlService;
    
    @Inject
    @Database(DatabaseType.POSTGRESQL) 
    private DatabaseService postgresService;
}

Lifecycle Annotations

@PostConstruct

Marks methods to be called after bean construction and dependency injection.

@Target(METHOD)
@Retention(RUNTIME)
public @interface PostConstruct {
}

@PreDestroy

Marks methods to be called before bean destruction.

@Target(METHOD)
@Retention(RUNTIME)
public @interface PreDestroy {
}

Usage Examples:

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.inject.Singleton;

@Singleton
public class DatabaseConnectionManager {
    
    private Connection connection;
    
    @PostConstruct
    public void initialize() {
        System.out.println("Initializing database connection...");
        this.connection = DriverManager.getConnection("jdbc:h2:mem:test");
    }
    
    @PreDestroy
    public void cleanup() {
        System.out.println("Closing database connection...");
        try {
            if (connection != null && !connection.isClosed()) {
                connection.close();
            }
        } catch (SQLException e) {
            System.err.println("Error closing connection: " + e.getMessage());
        }
    }
    
    public void executeQuery(String sql) {
        // Use connection
    }
}

Scope Annotations

Custom Scope

import io.micronaut.context.scope.CustomScope;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@CustomScope
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestScope {
}

// Implementation of the custom scope
@Singleton
public class RequestScopeImpl implements CustomScope<RequestScope> {
    
    private final Map<String, Object> requestBeans = new ConcurrentHashMap<>();
    
    @Override
    public Class<RequestScope> annotationType() {
        return RequestScope.class;
    }
    
    @Override
    public <T> T get(BeanCreationContext<T> creationContext) {
        String key = creationContext.id().toString();
        return (T) requestBeans.computeIfAbsent(key, k -> 
            creationContext.create()
        );
    }
    
    public void clearScope() {
        requestBeans.clear();
    }
}

// Usage
@RequestScope
public class RequestDataHolder {
    private Map<String, Object> data = new HashMap<>();
    
    public void setData(String key, Object value) {
        data.put(key, value);
    }
    
    public Object getData(String key) {
        return data.get(key);
    }
}

Qualifier Utility Classes

Qualifiers

Utility class for creating qualifiers programmatically.

public final class Qualifiers {
    public static <T> Qualifier<T> byName(String name);
    public static <T> Qualifier<T> byType(Class<?>... types);
    public static <T> Qualifier<T> byAnnotation(Annotation annotation);
    public static <T> Qualifier<T> byTypeArguments(Class<?>... types);
    public static <T> Qualifier<T> byTypeArgumentsClosest(Class<?>... types);
}

Usage Examples:

import io.micronaut.context.ApplicationContext;
import io.micronaut.context.Qualifier;
import io.micronaut.inject.qualifiers.Qualifiers;

public class QualifierExample {
    public static void main(String[] args) {
        try (ApplicationContext context = ApplicationContext.run()) {
            // Get bean by name qualifier
            Qualifier<DatabaseService> nameQualifier = Qualifiers.byName("mysql");
            DatabaseService mysqlService = context.getBean(DatabaseService.class, nameQualifier);
            
            // Get bean by annotation qualifier
            Database databaseAnnotation = () -> DatabaseType.POSTGRESQL;
            Qualifier<DatabaseService> annotationQualifier = Qualifiers.byAnnotation(databaseAnnotation);
            DatabaseService postgresService = context.getBean(DatabaseService.class, annotationQualifier);
        }
    }
}

Advanced Configuration Annotations

@EachBean

Creates a bean for each bean of the specified type that exists in the context.

@Target({TYPE})
@Retention(RUNTIME)
@Documented
public @interface EachBean {
    /**
     * The bean type to iterate over
     */
    Class<?> value();
}

Usage Examples:

import io.micronaut.context.annotation.EachBean;

@EachBean(DataSource.class)
@Singleton
public class DatabaseService {
    
    private final DataSource dataSource;
    
    public DatabaseService(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    public Connection getConnection() {
        return dataSource.getConnection();
    }
}

// If there are 3 DataSource beans, 3 DatabaseService beans will be created

@EachProperty

Creates a bean for each property prefix that exists in configuration.

@Target({TYPE})
@Retention(RUNTIME)
@Documented
public @interface EachProperty {
    /**
     * The property prefix to iterate over
     */
    String value();
    
    /**
     * Primary bean marker
     */
    boolean primary() default false;
}

Usage Examples:

import io.micronaut.context.annotation.EachProperty;
import io.micronaut.context.annotation.ConfigurationProperties;

@EachProperty("datasources")
@ConfigurationProperties("datasources")
public class DataSourceConfig {
    private String url;
    private String username;
    private String password;
    
    // getters and setters
}

// Configuration:
// datasources.primary.url=jdbc:h2:mem:primary
// datasources.secondary.url=jdbc:h2:mem:secondary
// Creates DataSourceConfig beans for "primary" and "secondary"

@ConfigurationBuilder

Enables configuration of complex objects through builder pattern integration.

@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
@Documented
public @interface ConfigurationBuilder {
    /**
     * Property prefix for configuration values
     */
    String value() default "";
    
    /**
     * Configuration prefix for nested configuration
     */
    String configurationPrefix() default "";
    
    /**
     * Method prefixes to include
     */
    String[] includes() default {};
    
    /**
     * Method prefixes to exclude
     */
    String[] excludes() default {};
    
    /**
     * Whether to allow zero args methods
     */
    boolean allowZeroArgs() default false;
}

Usage Examples:

import io.micronaut.context.annotation.ConfigurationBuilder;
import io.micronaut.context.annotation.ConfigurationProperties;

@ConfigurationProperties("redis")
public class RedisConfig {
    
    @ConfigurationBuilder(configurationPrefix = "jedis")
    private final JedisPoolConfig jedisConfig = new JedisPoolConfig();
    
    @ConfigurationBuilder(configurationPrefix = "lettuce", 
                         includes = {"timeout", "database"})
    private final LettuceConnectionFactory.Builder lettuceBuilder = 
        LettuceConnectionFactory.builder();
    
    public JedisPoolConfig getJedisConfig() {
        return jedisConfig;
    }
    
    public LettuceConnectionFactory.Builder getLettuceBuilder() {
        return lettuceBuilder;
    }
}

// Configuration:
// redis.jedis.max-total=20
// redis.jedis.max-idle=10
// redis.lettuce.timeout=5000
// redis.lettuce.database=0

@Executable

Marks methods as executable for reflection-free method invocation.

@Target({METHOD})
@Retention(RUNTIME)
@Documented
public @interface Executable {
    /**
     * Whether the method can be invoked when reflection is not available
     */
    boolean processOnStartup() default false;
}

Usage Examples:

import io.micronaut.context.annotation.Executable;

@Singleton
public class BusinessService {
    
    @Executable
    public String processData(String input) {
        return "Processed: " + input;
    }
    
    @Executable(processOnStartup = true)
    public void initialize() {
        System.out.println("Service initialized");
    }
    
    // Non-executable method - won't be optimized
    private void internalMethod() {
        // Internal logic
    }
}

@Mapper

Enables automatic bean mapping functionality.

@Target({TYPE})
@Retention(RUNTIME)
@Documented
public @interface Mapper {
    /**
     * The mapping strategy
     */
    Strategy strategy() default Strategy.DEFAULT;
    
    /**
     * Configuration for the mapper
     */
    String config() default "";
    
    enum Strategy {
        DEFAULT, CONSTRUCTOR, SETTER, FIELD
    }
}

Usage Examples:

import io.micronaut.context.annotation.Mapper;

@Mapper
public interface UserMapper {
    
    UserDto toDto(User user);
    User fromDto(UserDto dto);
    
    @Mapping(target = "fullName", source = "firstName,lastName")
    UserSummary toSummary(User user);
}

// Micronaut generates implementation at compile time

Conditional and Validation Annotations

@Any

Qualifier that matches any bean of the specified type.

@Target({FIELD, PARAMETER, METHOD, TYPE})
@Retention(RUNTIME)
@Qualifier
public @interface Any {
}

@Secondary

Marks a bean as secondary - used when @Primary is not available.

@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface Secondary {
}

Usage Examples:

import io.micronaut.context.annotation.Secondary;

@Singleton
@Primary
public class PrimaryEmailService implements EmailService {
    // Primary implementation
}

@Singleton
@Secondary
public class BackupEmailService implements EmailService {
    // Secondary implementation - used if primary fails
}

Types

Annotation Metadata Types

public interface AnnotationMetadata {
    <T extends Annotation> Optional<T> getAnnotation(Class<T> annotationClass);
    boolean hasAnnotation(Class<? extends Annotation> annotation);
    boolean hasStereotype(Class<? extends Annotation> stereotype);
    Set<String> getAnnotationNames();
    Set<String> getDeclaredAnnotationNames();
    OptionalValues<Object> getValues(String annotation);
    <T> Optional<T> getValue(String annotation, Class<T> requiredType);
    String[] stringValues(Class<? extends Annotation> annotation);
    String[] stringValues(String annotation, String member);
}
}

Install with Tessl CLI

npx tessl i tessl/maven-io-micronaut--micronaut-inject

docs

annotations.md

application-context.md

bean-definition.md

bean-factory.md

bean-processing.md

bean-providers.md

environment-config.md

events.md

exceptions.md

index.md

scoping.md

tile.json