The Configuration Component

The config component provides a Java API to load and process configuration properties in key/value form into a Config object which the application can use to retrieve config data.

Getting Started

Introducing the Config System

A brief overview of the config system helps clarify its different parts and how they work together. Most applications will typically deal with more than one of these parts.

Configuration Overview

The system reads configuration from a config source, a physical location (such as a file, a URL, or a String) which holds config data. Each config source works with a config parser which translates a particular text format (for example, Java properties or YAML) into an in-memory tree which represents the configuration’s structure and values. An optional polling strategy detects and publishes changes to the underlying config source so the config source itself or your application can respond.

Your application uses the Config object which results from building that in-memory tree to retrieve config data. The app can navigate explicitly among the nodes in the tree and fetch a node’s value

int pageSize = config
                .get("web")
                .get("page-size")
                .asInt()
                .orElse(20);
Copied

or it can address a node in the tree using the config key’s dotted name

int pageSize = config
                .get("web.page-size")
                .asInt()
                .orElse(20);
Copied

As part of retrieving a value from a node, the config system applies config filters which can change what values are returned for selected keys.

The Config object lets your application retrieve config data as a typed ConfigValue.

ConfigValue<T> can be used to obtain: * an Optional<T> value from a single node, * the T value from a single node interpreted as a basic Java type (primitive or simple object) already known to the config system (such as a boolean or a Double), or * a complex Java type from a subtree of the config tree.

+ The config system automatically knows how to return List and Map complex types, and you can provide config mappers to convert a config subtree to whatever Java types your application needs.

Your First Config Application

An easy way to start with the Config API is to follow these four steps:

  1. add config-related dependencies to your pom.xml
  2. revise your module-info.java to refer to config (if you are using Java 9)
  3. create a simple config properties file
  4. retrieve and use the default Config from your app

Add Maven Dependency on Config

Config Dependency in pom.xml
<dependencies>
    <dependency>
        <groupId>io.helidon.config</groupId>
        <artifactId>helidon-config</artifactId>
        <version>version-of-config-you-are-using</version>
    </dependency>
</dependencies>
Copied

Update module-info.java

If you are using Java 9 then create or update the module-info.java file for your application:

Config Dependency in module-info.java
module myModule {
    requires io.helidon.config;
}
Copied

Create simple Config Properties File

Example src/main/resources/application.properties config file
greeting = Hello

web.debug = true
web.page-size = 20
web.ratio = 1.3

bl.initial-id = 10000000000

origin = props
java.home=homeFromProps # will be ignored
Copied

Write Code using the Default Config

Create and Use Default Config from Java
import io.helidon.config.Config; 
...
Config config = Config.create(); 
System.out.println(String.format(
        "greeting is %s\n"
                + "web.debug is %b\n"
                + "web.page-size is %d\n"
                + "web.ratio is %f\n"
                + "bl.initial-id is %d\n"
                + "origin is %s\n"
                + "java.home is %s",
        config.get("greeting").asString().orElse("Default greeting"),  
        config.get("web.debug").asBoolean().orElse(false),
        config.get("web.page-size").asInt().orElse(50),
        config.get("web.ratio").asDouble().orElse(2.0),
        config.get("bl.initial-id").asLong().orElse(1L),
        config.get("origin").asString().orElse("defaults"),
        config.get("java.home").asString().get())); 
Copied
  • Import Config.
  • Create the root of the Config tree from the default sources.
  • Retrieve various values by their dotted names and decode them as the appropriate Java types, providing default values if the property is missing.
  • Retrieve the value (and fail with a runtime exception if missing)

When you build and run your project, the output will look like this:

greeting is Hello
web.debug is true
web.page-size is 20
web.ratio is 1.300000
bl.initial-id is 10000000000
origin is props
java.home is /Library/Java/JavaVirtualMachines/jdk-10.0.1.jdk/Contents/Home
Copied
Config Sources for the Default Config

The default config uses the following config sources, listed here from most to least important:

  1. Java system properties
  2. Environment variables
  3. application.properties, if on the classpath.

The priority (most to least important) means that if a given config key appears in more than one source, the value assigned in a more important source overrules the value from a less important source.

Verify this by noting that the program has displayed your actual java.home which Java set as a system property, not the value set in the example application.properties file.

Built-in Support for Config Formats

If you add additional Helidon config maven artifacts to your dependencies, then the config system can read formats other than Java properties format and the default configuration will search for other application file types in the following order. Note that the default configuration stops once it finds one of the files below; it does not merge all such files it can find.

Default Config Files (most to least important)
SourceHelidon maven artifact ID (group ID: io.helidon.config)Notes
application.yamlhelidon-config-yamlYAML format http://yaml.org
application.confhelidon-config-hoconHOCON format https://github.com/lightbend/config#using-hocon-the-json-superset
application.jsonhelidon-config-hoconJSON format https://json.org/
application.propertieshelidon-configJava properties format

Next Steps

Although the default configuration is very simple to use, your application can take as much control as it needs over

  • loading configuration data,

  • accessing the data once loaded, and

  • extending and modifying the behavior of the config system.

You do this by:

  • creating and invoking methods on a Config.Builder object to construct a Config instance

    Using a builder, the application can control everything about how the config system creates the resulting Config instance: config sources, parsers, polling strategy, filters, overrides, mappers, whether or not environment variables and Java system properties serve as config sources. The JavaDoc explains how to use the Config.Builder.

    or

  • creating a meta-configuration file on the runtime classpath to control how the config system prepares the default configuration.

Once created, the Config object provides many methods the application can use to retrieve config data as various Java types. See the Config JavaDoc for complete details.

The links in the following tables lead you to more information about various other config topics.

Controlling How Config is Loaded
TopicDocumentation
Where config comes fromConfig sources, meta-configuration
What format config data is expressed inConfig parsers, supported formats
How to filter, override, and dereference valuesFilters and overrides
What happens when config data changesConfig polling
How to deal with loading errorsConfig retry policies
Accessing Configuration Data
TopicDocumentation
How config data is translated into Java typesConfig mappers
How to navigate config treesNavigation
Extending and Fine-tuning the Config System
TopicDocumentation
Writing extensionsExtensions