CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-micronaut

Modern, JVM-based framework for building modular, easily testable microservice and serverless applications with compile-time DI and fast startup.

Pending
Overview
Eval results
Files

configuration.mddocs/

Configuration

Micronaut's configuration system provides type-safe property binding, environment-specific configuration loading, and hot-reload support for development with comprehensive validation and nested object support.

Capabilities

Configuration Properties

Bind configuration properties to typed objects with validation and nested configuration support.

/**
 * Basic configuration properties
 */
@ConfigurationProperties("app.database")
public class DatabaseConfiguration {
    private String host = "localhost";
    private int port = 5432;
    private String username;
    private String password;
    private String database;
    private boolean ssl = false;
    
    // 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; }
    
    // ... other getters and setters
}

/**
 * Configuration with validation
 */
@ConfigurationProperties("app.server")
public class ServerConfiguration {
    
    @NotBlank
    private String name;
    
    @Min(1024)
    @Max(65535)
    private int port = 8080;
    
    @Email
    private String adminEmail;
    
    @URL
    private String baseUrl;
    
    @Valid
    private SslConfig ssl;
    
    // getters and setters
}

/**
 * Nested configuration
 */
public static class SslConfig {
    private boolean enabled = false;
    private String keyStore;
    private String keyStorePassword;
    private String protocol = "TLS";
    
    // getters and setters
}

Environment-Specific Configuration

Load different configurations based on the active environment.

/**
 * Environment-specific configuration
 */
@ConfigurationProperties("cache")
@Requires(env = Environment.DEVELOPMENT)
public class DevelopmentCacheConfiguration {
    private String type = "caffeine";
    private long maxSize = 100;
    private Duration expireAfterWrite = Duration.ofMinutes(5);
    
    // getters and setters
}

@ConfigurationProperties("cache") 
@Requires(env = Environment.PRODUCTION)
public class ProductionCacheConfiguration {
    private String type = "redis";
    private String host = "redis.example.com";
    private int port = 6379;
    private Duration expireAfterWrite = Duration.ofHours(1);
    
    // getters and setters
}

/**
 * Conditional configuration based on properties
 */
@ConfigurationProperties("monitoring")
@Requires(property = "monitoring.enabled", value = "true")
public class MonitoringConfiguration {
    private String endpoint;
    private Duration interval = Duration.ofMinutes(1);
    private List<String> metrics = new ArrayList<>();
    
    // getters and setters
}

Property Value Injection

Inject individual property values into beans and methods.

/**
 * Property value injection in beans
 */
@Singleton
public class ApiService {
    
    @Value("${api.base-url}")
    private String baseUrl;
    
    @Value("${api.timeout:30s}")
    private Duration timeout;
    
    @Value("${api.retries:3}")
    private int maxRetries;
    
    @Value("${api.enabled:true}")
    private boolean enabled;
    
    public ApiService(@Value("${api.key}") String apiKey,
                     @Value("${api.version:v1}") String version) {
        // Constructor injection of properties
    }
}

/**
 * Property injection in configuration methods
 */
@Factory
public class ServiceFactory {
    
    @Bean
    @Singleton
    public ExternalService externalService(@Value("${external.service.url}") String url,
                                          @Value("${external.service.token}") String token) {
        return new ExternalService(url, token);
    }
}

Dynamic Configuration

Support for configuration that can change at runtime with refresh capabilities.

/**
 * Refreshable configuration
 */
@ConfigurationProperties("feature-flags")
@Refreshable 
public class FeatureFlagConfiguration {
    private Map<String, Boolean> flags = new HashMap<>();
    private boolean debugMode = false;
    
    public boolean isFeatureEnabled(String feature) {
        return flags.getOrDefault(feature, false);
    }
    
    // getters and setters
}

/**
 * Using refreshable configuration
 */
@Singleton
public class FeatureService {
    private final FeatureFlagConfiguration featureConfig;
    
    public FeatureService(FeatureFlagConfiguration featureConfig) {
        this.featureConfig = featureConfig;
    }
    
    public boolean isNewUiEnabled() {
        return featureConfig.isFeatureEnabled("new-ui");
    }
}

/**
 * Configuration refresh event handling
 */
@Singleton
public class ConfigurationRefreshListener {
    
    @EventListener
    public void onRefresh(RefreshEvent event) {
        log.info("Configuration refreshed: {}", event.getSource());
        // React to configuration changes
    }
}

List and Map Configuration

Configure collections and complex nested structures.

/**
 * List and map configuration
 */
@ConfigurationProperties("app")
public class ApplicationConfiguration {
    
    private List<String> allowedOrigins = new ArrayList<>();
    private Map<String, String> headers = new HashMap<>();
    private List<ServerConfig> servers = new ArrayList<>();
    
    // getters and setters
    public List<String> getAllowedOrigins() { return allowedOrigins; }
    public void setAllowedOrigins(List<String> allowedOrigins) { 
        this.allowedOrigins = allowedOrigins; 
    }
    
    public Map<String, String> getHeaders() { return headers; }
    public void setHeaders(Map<String, String> headers) { 
        this.headers = headers; 
    }
}

/**
 * Nested object in lists
 */
public static class ServerConfig {
    private String name;
    private String host;
    private int port;
    private List<String> protocols = new ArrayList<>();
    
    // getters and setters
}

/**
 * Multiple configuration instances using @EachProperty
 */
@EachProperty("databases")
@ConfigurationProperties("databases")
public class DatabaseInstanceConfiguration {
    private String name;
    private String url;
    private String driver;
    private int maxConnections = 10;
    
    // This will create separate configuration instances for:
    // databases.primary.*, databases.secondary.*, etc.
    
    // getters and setters
}

Configuration Builders

Use builder pattern for complex configuration objects.

/**
 * Configuration with builder support
 */
@ConfigurationProperties("http-client")
public class HttpClientConfiguration {
    
    @ConfigurationBuilder(prefixes = "")
    private ConnectionPoolConfiguration connectionPool = 
        ConnectionPoolConfiguration.builder().build();
    
    @ConfigurationBuilder(prefixes = "ssl")
    private SslConfiguration ssl = SslConfiguration.builder().build();
    
    private Duration readTimeout = Duration.ofSeconds(30);
    private boolean followRedirects = true;
    
    // getters and setters
}

/**
 * Builder-based configuration classes
 */
public class ConnectionPoolConfiguration {
    private int maxConnections = 10;
    private Duration idleTimeout = Duration.ofMinutes(5);
    private boolean keepAlive = true;
    
    public static Builder builder() {
        return new Builder();
    }
    
    public static class Builder {
        private ConnectionPoolConfiguration config = new ConnectionPoolConfiguration();
        
        public Builder maxConnections(int maxConnections) {
            config.maxConnections = maxConnections;
            return this;
        }
        
        public Builder idleTimeout(Duration idleTimeout) {
            config.idleTimeout = idleTimeout;
            return this;
        }
        
        // other builder methods
        
        public ConnectionPoolConfiguration build() {
            return config;
        }
    }
    
    // getters
}

Configuration Sources

Configure multiple sources for properties with precedence handling.

/**
 * Custom property source
 */
@Singleton
@Primary
public class DatabasePropertySource implements PropertySource {
    
    @Override
    public String getName() {
        return "database-config";
    }
    
    @Override
    public Object get(String key) {
        // Load from database
        return configRepository.findByKey(key);
    }
    
    @Override
    public Iterator<String> iterator() {
        return configRepository.findAllKeys().iterator();
    }
    
    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE;
    }
}

/**
 * Property source loader for custom formats
 */
@Singleton
public class YamlPropertySourceLoader implements PropertySourceLoader {
    
    @Override
    public Set<String> getExtensions() {
        return Set.of("yml", "yaml");
    }
    
    @Override
    public Optional<PropertySource> load(String resourceName, InputStream inputStream) {
        try {
            // Parse YAML and create property source
            Map<String, Object> properties = yamlParser.parse(inputStream);
            return Optional.of(PropertySource.of(resourceName, properties));
        } catch (Exception e) {
            return Optional.empty();
        }
    }
}

Configuration Validation

Validate configuration at startup with custom validators.

/**
 * Configuration with Bean Validation annotations
 */
@ConfigurationProperties("payment")
public class PaymentConfiguration {
    
    @NotBlank(message = "Payment provider is required")
    private String provider;
    
    @Valid
    @NotNull
    private ProviderConfig config;
    
    @Min(value = 1, message = "Timeout must be at least 1 second")
    @Max(value = 300, message = "Timeout cannot exceed 5 minutes")
    private int timeoutSeconds = 30;
    
    @Pattern(regexp = "^[A-Z]{3}$", message = "Currency must be 3-letter ISO code")
    private String defaultCurrency = "USD";
    
    // getters and setters
}

/**
 * Custom validator for configuration
 */
@Singleton
public class PaymentConfigurationValidator {
    
    @EventListener
    public void validateOnStartup(StartupEvent event) {
        ApplicationContext context = event.getSource();
        PaymentConfiguration config = context.getBean(PaymentConfiguration.class);
        
        if (!isValidProvider(config.getProvider())) {
            throw new ConfigurationException(
                "Invalid payment provider: " + config.getProvider());
        }
    }
    
    private boolean isValidProvider(String provider) {
        return Set.of("stripe", "paypal", "square").contains(provider.toLowerCase());
    }
}

Types

// Core configuration interfaces
public interface Environment extends PropertyResolver {
    Set<String> getActiveNames();
    Collection<PropertySource> getPropertySources();
    Environment addPropertySource(PropertySource propertySource);
    Environment removePropertySource(PropertySource propertySource);
    
    static final String DEVELOPMENT = "dev";
    static final String TEST = "test";
    static final String PRODUCTION = "prod";
}

public interface PropertySource extends Iterable<String> {
    String getName();
    Object get(String key);
    int getOrder();
    
    static PropertySource of(String name, Map<String, Object> values);
    static PropertySource of(Map<String, Object> values);
}

public interface PropertyResolver {
    boolean containsProperty(String name);
    boolean containsProperties(String name);
    <T> Optional<T> getProperty(String name, Class<T> requiredType);
    <T> T getProperty(String name, Class<T> requiredType, T defaultValue);
    String getProperty(String name, String defaultValue);
    Optional<String> getProperty(String name);
}

// Configuration binding
public interface PropertyPlaceholderResolver {
    Optional<String> resolvePlaceholders(String str);
    String resolveRequiredPlaceholders(String str);
}

public interface ConversionService {
    <T> Optional<T> convert(Object object, Class<T> targetType);
    <T> Optional<T> convert(Object object, Argument<T> targetType);
    <T> T convert(Object object, Class<T> targetType, T defaultValue);
}

// Configuration events
public class RefreshEvent extends ApplicationEvent {
    public RefreshEvent(Object source) {
        super(source);
    }
}

public class ConfigurationChangedEvent extends ApplicationEvent {
    private final String propertyName;
    private final Object oldValue;
    private final Object newValue;
    
    // constructors and getters
}

// Property source loaders
public interface PropertySourceLoader {
    Set<String> getExtensions();
    Optional<PropertySource> load(String resourceName, InputStream inputStream);
    Map<String, PropertySourceLoader> getLoadersMap();
}

// Configuration exceptions
public class ConfigurationException extends RuntimeException {
    public ConfigurationException(String message);
    public ConfigurationException(String message, Throwable cause);
}

public class PropertyNotFoundException extends ConfigurationException {
    public PropertyNotFoundException(String property);
}

Install with Tessl CLI

npx tessl i tessl/maven-micronaut

docs

aop.md

configuration.md

dependency-injection.md

functions.md

http-client.md

http-server.md

index.md

management.md

messaging.md

reactive.md

retry.md

scheduling.md

websocket.md

tile.json