Skip to content

GuicedEE/microprofile-config

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

29 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

GuicedEE MicroProfile Config

Build Maven Central Snapshot License

Java 25+ Guice 7 Vert.X 5 Maven 4

MicroProfile Config implementation for GuicedEE applications using SmallRye Config and Google Guice. Inject configuration values with @ConfigProperty, resolve from environment variables, system properties, and META-INF/microprofile-config.properties β€” all wired automatically through SPI discovery and Guice bindings.

Built on SmallRye Config Β· MicroProfile Config Β· Google Guice Β· Vert.x Β· JPMS module com.guicedee.microprofile.config Β· Java 25+

πŸ“¦ Installation

<dependency>
  <groupId>com.guicedee.microprofile</groupId>
  <artifactId>config</artifactId>
</dependency>
Gradle (Kotlin DSL)
implementation("com.guicedee.microprofile:config:2.0.1-SNAPSHOT")

✨ Features

  • CDI-style injection β€” @ConfigProperty(name = "key") with automatic type conversion for String, Boolean, Integer, Long, Double, Float, and Optional<T> wrappers
  • Standards-compliant β€” implements org.eclipse.microprofile.config APIs and annotations via SmallRye Config
  • Deterministic source ordering β€” environment variables (highest), system properties, and classpath META-INF/microprofile-config.properties (lowest)
  • Custom converters β€” register Converter<T> implementations via ServiceLoader for application-specific types
  • Profile support β€” profile-specific properties (e.g. %dev.key=value) resolved by SmallRye Config
  • Guice-native β€” SmallRyeConfig is bound as a singleton via SmallRyeConfigProvider; @ConfigProperty fields are scanned and bound at startup
  • Vert.x-aware initialization β€” config is built on a Vert.x worker thread to avoid blocking the event loop
  • JPMS-ready β€” named module with proper exports, provides, and opens directives

πŸš€ Quick Start

Step 1 β€” Add a microprofile-config.properties file:

# src/main/resources/META-INF/microprofile-config.properties
messaging.enabled=true
messaging.bootstrap.servers=localhost:9092
liveness.port=8081

Step 2 β€” Inject configuration values:

import org.eclipse.microprofile.config.inject.ConfigProperty;

public class MessagingService {

    @ConfigProperty(name = "messaging.enabled", defaultValue = "true")
    boolean enabled;
    
    @ConfigProperty(name = "messaging.bootstrap.servers")
    String bootstrapServers;

    public void start() {
        if (enabled) {
            // use bootstrapServers
        }
    }
}

Step 3 β€” Register via JPMS:

module my.app {
    requires com.guicedee.microprofile.config;
}

The MicroProfileConfigContext initializes SmallRye Config automatically during IGuicePreStartup, and MicroProfileConfigBinder scans for all @ConfigProperty fields and binds them into Guice.

πŸ“ Architecture

flowchart TD
    n1["IGuiceContext.instance()"]
    n2["IGuiceConfigurator hooks"]
    n1 --> n2
    n3["ScanConfig<br/>enables field, annotation, classpath scanning"]
    n2 --> n3
    n4["IGuicePreStartup hooks"]
    n1 --> n4
    n5["MicroProfileConfigContext<br/>builds SmallRyeConfig on Vert.x worker thread"]
    n4 --> n5
    n6["addDefaultSources()<br/>env vars, system props, microprofile-config.properties"]
    n5 --> n6
    n7["addDiscoveredSources()<br/>ServiceLoader-discovered ConfigSource SPIs"]
    n5 --> n7
    n8["addDiscoveredConverters()<br/>ServiceLoader-discovered Converter<T> SPIs"]
    n5 --> n8
    n9["addDiscoveredInterceptors()<br/>ConfigSourceInterceptor SPIs"]
    n5 --> n9
    n10["IGuiceModule hooks"]
    n1 --> n10
    n11["MicroProfileConfigBinder<br/>Guice AbstractModule"]
    n10 --> n11
    n12["bind SmallRyeConfig via SmallRyeConfigProvider<br/>singleton"]
    n11 --> n12
    n13["scan @ConfigProperty fields via ClassGraph"]
    n11 --> n13
    n14["bind each field type: String, Boolean, Integer, Long, Double, Float, Optional<T>"]
    n11 --> n14
    n15["InjectionPointProvider"]
    n1 --> n15
    n16["InjectionPointProvision<br/>registers @ConfigProperty as a Guice injection point"]
    n15 --> n16
Loading

βš™οΈ Configuration Sources and Resolution

MicroProfile Config defines a composite of sources with numeric ordinals. Higher ordinal wins when keys overlap:

Source Ordinal Example
Environment variables 300 MESSAGING_ENABLED=true
System properties 200 -Dmessaging.enabled=true
META-INF/microprofile-config.properties 100 messaging.enabled=true

Key mapping

Environment variable names follow MicroProfile Config rules:

  • Dots (.) and hyphens (-) are replaced with underscores (_)
  • Names are uppercased
  • e.g. messaging.bootstrap.servers β†’ MESSAGING_BOOTSTRAP_SERVERS

Profiles

SmallRye Config supports profile-specific properties using the %profile. prefix:

# META-INF/microprofile-config.properties
db.url=jdbc:postgresql://prod-host:5432/mydb

# Profile-specific override
%dev.db.url=jdbc:postgresql://localhost:5432/mydb

Activate a profile with mp.config.profile=dev (system property or environment variable).

πŸ”„ Programmatic Access

Inject the SmallRyeConfig instance directly for programmatic lookups:

import jakarta.inject.Inject;
import io.smallrye.config.SmallRyeConfig;

public class HealthProbe {

    @Inject
    SmallRyeConfig config;

    public int livenessPort() {
        return config.getOptionalValue("liveness.port", Integer.class).orElse(8081);
    }
}

Or use the standard MicroProfile Config interface:

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;

Config config = ConfigProvider.getConfig();
String value = config.getValue("messaging.enabled", String.class);

πŸ”Œ Supported Injection Types

MicroProfileConfigBinder scans all classes with @ConfigProperty-annotated fields and creates Guice bindings for each:

Field type Binding
String Direct value from config
boolean / Boolean Parsed via Boolean.parseBoolean()
int / Integer Parsed via Integer.parseInt()
long / Long Parsed via Long.parseLong()
double / Double Parsed via Double.parseDouble()
float / Float Parsed via Float.parseFloat()
Optional<String> Wrapped optional
Optional<Boolean> Wrapped optional
Optional<Integer> Wrapped optional
Optional<Long> Wrapped optional
Optional<Double> Wrapped optional
Optional<Float> Wrapped optional

Default values are supported via @ConfigProperty(defaultValue = "...").

🧩 Custom Converters

Register custom Converter<T> implementations via ServiceLoader for application-specific types:

import org.eclipse.microprofile.config.spi.Converter;
import java.time.Duration;

public class DurationConverter implements Converter<Duration> {

    @Override
    public Duration convert(String value) {
        if (value.endsWith("ms")) return Duration.ofMillis(Long.parseLong(value.replace("ms", "")));
        if (value.endsWith("s")) return Duration.ofSeconds(Long.parseLong(value.replace("s", "")));
        throw new IllegalArgumentException("Unsupported duration format: " + value);
    }
}

Register via META-INF/services/org.eclipse.microprofile.config.spi.Converter:

com.example.DurationConverter

And then with JPMS:

module my.app {
    provides org.eclipse.microprofile.config.spi.Converter
        with com.example.DurationConverter;
}

πŸ”§ SPI Extension Points

All SPIs are discovered via ServiceLoader. Register implementations with JPMS provides...with or META-INF/services.

SPI Purpose
IGuicePreStartup MicroProfileConfigContext β€” builds the SmallRyeConfig instance
IGuiceModule MicroProfileConfigBinder β€” scans @ConfigProperty fields and binds to Guice
IGuiceConfigurator ScanConfig β€” enables classpath, annotation, and field scanning
InjectionPointProvider InjectionPointProvision β€” registers @ConfigProperty as an injection point
ConfigSource (MicroProfile) Add custom config sources with custom ordinals
Converter<T> (MicroProfile) Register custom type converters
ConfigSourceInterceptor (SmallRye) Intercept and transform config values

πŸ—ΊοΈ Module Graph

flowchart LR
    com_guicedee_microprofile_config["com.guicedee.microprofile.config"]
    com_guicedee_microprofile_config --> io_smallrye_config_core["io.smallrye.config.core<br/>SmallRye Config β€” MicroProfile Config implementation"]
    com_guicedee_microprofile_config --> com_guicedee_vertx["com.guicedee.vertx<br/>Vert.x lifecycle β€” worker thread initialization"]
    com_guicedee_microprofile_config --> com_guicedee_client["com.guicedee.client<br/>GuicedEE client β€” SPI contracts, IGuiceContext"]
    com_guicedee_microprofile_config --> com_google_guice["com.google.guice<br/>Guice DI β€” injection bindings"]
Loading

πŸ—οΈ Key Classes

Class Package Role
MicroProfileConfigContext config IGuicePreStartup β€” builds SmallRyeConfig on a Vert.x worker thread at startup
MicroProfileConfigBinder implementations IGuiceModule β€” scans @ConfigProperty fields and creates Guice bindings per type
SmallRyeConfigProvider implementations Guice Provider<SmallRyeConfig> β€” returns the shared config instance
InjectionPointProvision implementations InjectionPointProvider β€” registers @ConfigProperty for Guice injection point processing
ScanConfig implementations IGuiceConfigurator β€” enables classpath, annotation, and field scanning

🧩 JPMS

Module name: com.guicedee.microprofile.config

The module:

  • exports com.guicedee.microprofile.config
  • requires transitive io.smallrye.config.core, com.guicedee.vertx
  • provides IGuicePreStartup with MicroProfileConfigContext
  • provides IGuiceModule with MicroProfileConfigBinder
  • provides InjectionPointProvider with InjectionPointProvision
  • provides IGuiceConfigurator with ScanConfig
  • opens com.guicedee.microprofile.config.implementations to com.google.guice

In non-JPMS environments, META-INF/services discovery still works.

πŸ§ͺ Testing

import com.guicedee.client.IGuiceContext;
import com.google.inject.Injector;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class ConfigTest {

    @Test
    void configPropertyFieldsAreInjected() {
        Injector injector = IGuiceContext.getContext().inject();
        MyConfigBean bean = injector.getInstance(MyConfigBean.class);
        assertNotNull(bean.getServerHost());
    }
}

Provide test configuration in src/test/resources/META-INF/microprofile-config.properties:

server.host=localhost
server.port=8080

🀝 Contributing

Issues and pull requests are welcome β€” please add tests for new type converters, config sources, or binding changes.

πŸ“„ License

Apache 2.0

About

The MicroProfile Config addon for GuicedEE

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages