Interface Config


  • public interface Config

    Configuration

    Immutable tree-structured configuration.

    Loading Configuration

    Load the default configuration using the create() method.
    
     Config config = Config.create();
     
    Use Config.Builder to construct a new Config instance from one or more specific ConfigSources using the builder().

    The application can affect the way the system loads configuration by implementing interfaces defined in the SPI, by explicitly constructing the Config.Builder which assembles the Config, and by using other classes provided by the config system that influence loading.

    Some Config SPI Interfaces
    Class.Method Application-implemented Interface Purpose
    ConfigSources.create(io.helidon.config.Config) ConfigSource Loads configuration from a different type of origin. Each ConfigSource implementation handles a type of location. Different instances of a given ConfigSource implementation represent separate sources of that location type.
    Config.Builder.addParser(io.helidon.config.spi.ConfigParser) ConfigParser Converts one format of config representation into the corresponding Config tree.
    Config.Builder.addFilter(io.helidon.config.spi.ConfigFilter) ConfigFilter Changes the String representation of each config value from one String to another as the Config tree is built from its sources.
    OverrideSources Replaces config String values during loading based on their keys. Programs provide overrides in Java property file format on the classpath, at a URL, or in a file, or by invoking OverrideSources.create(java.util.Map<java.lang.String, java.lang.String>) and passing the name-matching expressions and the corresponding replacement value as a Map.
    Config.Builder.addMapper(Class, Function) Implements conversion from a Config node (typically with children) to an application-specific Java type.

    Navigating in a Configuration Tree

    Each loaded configuration is a tree of Config objects. The application can access an arbitrary node in the tree by passing its fully-qualified name to get(java.lang.String):
    
     Config greeting = config.get("greeting");
     
    Method key() always returns fully-qualified Config.Key of a config node.
    
     assert greeting.key().toString().equals("greeting")
     
    These are equivalent ways of obtaining the same Config instance, and the two assertions will succeed:
    
     Config name1 = config.get("app.services.svc1.name");
     Config name2 = config.get("app").get("services.svc1.name");
     Config name3 = config.get("app.services").get("svc1").get("name");
     Config name4 = config.get("app").get("services").get("svc1").get("name");
    
     assert name4.key().equals(Key.create("app.services.svc1.name"))
     assert name1 == name2 == name3 == name4
     
    The get(java.lang.String) method always returns a Config object, even if no configuration is present using the corresponding key. The application can invoke the type() method to find out the type of the node, represented by one of the Config.Type enum values. The exists() method tells whether or not the Config node represents existing configuration.
    
     if (!config.get("very.rare.prop42").exists()) {
         // node 'very.rare.prop42' does NOT exist
     }
     
    The traverse() method visits all nodes in a subtree. This example gathers all nodes with keys matching logging.**.level -- that is, all nodes within the "logging" subtree that have a key ending in "level" and also has a single value:
    
     Map<String,String> loggingLevels = config.get("logging")  // find "logging" subtree
         .traverse()                                           // traverse through logging' nodes
         .filter(node -> node.isLeaf())                        // filter leaf values
         .filter(node -> node.name().equals("level"))          // filter key suffix '.level'
         .collect(Collectors.toMap(Config::key, Config::asString));
     

    To retrieve children of a config node use asNodeList()

    • on an object node to get all object members,
    • on a list node to get all list elements.

    To get node value, use as(Class) to access this config node as a ConfigValue

    Converting Configuration Values to Types

    Explicit Conversion by the Application

    The interpretation of a configuration node, including what datatype to use, is up to the application. To interpret a node's value as a type other than String the application can invoke one of these convenience methods:
    • as<typename> such as asBoolean, asDouble, asInt, etc. which return ConfigValue representing Java primitive data values (boolean, double, int, etc.)

      The ConfigValue can be used to access the value or use optional style methods. The config value provides access to the value in multiple ways. See ConfigValue for reference. Basic usages:

      
       // throws a MissingValueException in case the config node does not exist
       long l1 = config.asLong().get();
       // returns 42 in case the config node does not exist
       long l2 = config.asLong().orElse(42L);
       // invokes the method "timeout(long)" if the value exists
       config.asLong().ifPresent(this::timeout);
       
    • as(Class) to convert the config node to an instance of the specified class, if there is a configured mapper present that supports the class.
      
         // throws a MissingValueException in case the config node does not exist
         // throws a ConfigMappingException in case the config node cannot be converted to Long
         long l1 = config.as(Long.class).get();
         // returns 42 in case the config node does not exist
         // throws a ConfigMappingException in case the config node cannot be converted to Long
         long l2 = config.as(Long.class).orElse(42L);
         // invokes the method "timeout(long)" if the value exists
         // throws a ConfigMappingException in case the config node cannot be converted to Long
         config.as(Long.class).ifPresent(this::timeout);
         
    • as(Function) to convert the config node using the function provided. Let's assume there is a method public static Foo create(Config) on a class Foo:
      
        // throws a MissingValueException in case the config node does not exist
        // throws a ConfigMappingException in case the config node cannot be converted to Foo
        Foo f1 = config.as(Foo::create).get();
        // throws a ConfigMappingException in case the config node cannot be converted to Foo
        Foo f2 = config.as(Foo::create).orElse(Foo.DEFAULT);
        // invokes the method "foo(Foo)" if the value exists
        // throws a ConfigMappingException in case the config node cannot be converted to Foo
        config.as(Foo::create).ifPresent(this::foo);
       
    • as(GenericType) to convert the config node to an instance of the specified generic type, if there is a configured mapper present that supports the generic type.
      
        // throws a MissingValueException in case the config node does not exist
        // throws a ConfigMappingException in case the config node cannot be converted to Map<String, Integer>
        Map<String, Integer> m1 = config.as(new GenericType<Map<String, Integer>() {}).get();
        // throws a ConfigMappingException in case the config node cannot be converted to Map<String, Integer>
        Map<String, Integer> m1 = config.as(new GenericType<Map<String, Integer>() {}).orElseGet(Collections::emptyMap);
        // invokes the method "units(Map)" if the value exists
        // throws a ConfigMappingException in case the config node cannot be converted to Map<String, Integer>
        config.as(new GenericType<Map<String, Integer>() {}).ifPresent(this::units);
       
    To deal with application-specific types, the application can provide its own mapping logic by:

    If there is no explicitly registered mapping function in a Config.Builder for converting a given type then the config system throws ConfigMappingException, unless you use the config beans support, that can handle classes that fulfill some requirements (see documentation), such as a public constructor, static "create(Config)" method etc.

    Handling Multiple Configuration Sources

    A Config instance, including the default Config returned by create(), might be associated with multiple ConfigSources. The config system deals with multiple sources as follows.

    The ConfigSources.CompositeBuilder class handles multiple config sources; in fact the config system uses an instance of that builder automatically when your application invokes create() and builder(java.util.function.Supplier<io.helidon.config.spi.ConfigSource>...), for example. Each such composite builder has a merging strategy that controls how the config system will search the multiple config sources for a given key. By default each CompositeBuilder uses the FallbackMergingStrategy: configuration sources earlier in the list have a higher priority than the later ones. The system behaves as if, when resolving a value of a key, it checks each source in sequence order. As soon as one source contains a value for the key the system returns that value, ignoring any sources that fall later in the list.

    Your application can set a different strategy by constructing its own CompositeBuilder and invoking ConfigSources.CompositeBuilder.mergingStrategy(ConfigSources.MergingStrategy), passing the strategy to be used:

     Config.withSources(ConfigSources.create(source1, source2, source3)
                          .mergingStrategy(new MyMergingStrategy());
     
    • Method Detail

      • empty

        static Config empty()
        Returns empty instance of Config.
        Returns:
        empty instance of Config.
      • empty

        static Config empty​(Config config)
        Create an empty configuration with mappers copied from another config.
        Parameters:
        config - config to get mappers from
        Returns:
        an empty config instance (empty Object)
      • create

        static Config create()
        Returns a new default Config loaded using one of the configuration files available on the classpath and/or using the runtime environment.

        The config system loads the default configuration using a default Config.Builder which loads configuration data as described below. In contrast, the application can control how and from where configuration is loaded by explicitly creating and fine-tuning one or more Builder instances itself.

        1. Meta-configuration

          Meta-configuration specifies at least one ConfigSource or Config.Builder from which the system can load configuration. The config system searches for at most one of the following meta-configuration locations on the classpath, in this order:

          1. meta-config.yaml - meta configuration file in YAML format
          2. meta-config.conf - meta configuration file in HOCON format
          3. meta-config.json - meta configuration file in JSON format
          4. meta-config.properties - meta configuration file in Java Properties format
        2. Configuration

          In the absence of meta-configuration the config system loads the default configuration from all of the following sources:

          1. environment variables;
          2. system properties
          3. at most one of following locations on the classpath, in this order:
            1. application.yaml - configuration file in YAML format
            2. application.conf - configuration file in HOCON format
            3. application.json - configuration file in JSON format
            4. application.properties - configuration file in Java Properties format
          The config system uses only the first application.* location it finds for which it can locate a ConfigParser that supports the corresponding media type.

          When creating the default configuration the config system detects parsers that were loaded using the ServiceLoader mechanism or, if it finds none loaded, a built-in parser provided by the config system.

        Every invocation of this method creates a new Config instance which has neither a polling strategy nor a retry policy. To set up these and other behaviors the application should create explicitly a Config.Builder, tailor it accordingly, and then use its build method to create the Config instance as desired.
        Returns:
        new instance of Config
        See Also:
        loadSourcesFrom(Supplier[])
      • context

        default Config.Context context()
        Returns the Context instance associated with the current Config node that allows the application to access the last loaded instance of the node or to request that the entire configuration be reloaded.
        Returns:
        Context instance associated with specific Config node
      • timestamp

        Instant timestamp()
        Returns when the configuration tree was created.

        Each config node of single Config tree returns same timestamp.

        Returns:
        timestamp of created instance of whole configuration tree.
        See Also:
        context(), Config.Context.timestamp()
      • key

        Config.Key key()
        Returns the fully-qualified key of the Config node.

        The fully-qualified key is a sequence of tokens derived from the name of each node along the path from the config root to the current node. Tokens are separated by . (the dot character). See name() for more information on the format of each token.

        Returns:
        current config node key
        See Also:
        name()
      • name

        default String name()
        Returns the last token of the fully-qualified key for the Config node.

        The name of a node is the last token in its fully-qualified key.

        The exact format of the name depends on the Type of the containing node:

        • from a Config.Type.OBJECT node the token for a child is the name of the object member;
        • from a Config.Type.LIST node the token for a child is a zero-based index of the element, an unsigned base-10 integer value with no leading zeros.

        The ABNF syntax of config key is:

        
         config-key = *1( key-token *( "." key-token ) )
          key-token = *( unescaped / escaped )
          unescaped = %x00-2D / %x2F-7D / %x7F-10FFFF
                    ; %x2E ('.') and %x7E ('~') are excluded from 'unescaped'
            escaped = "~" ( "0" / "1" )
                    ; representing '~' and '.', respectively
         
        Returns:
        current config node key
        See Also:
        key(), Config.Key.name()
      • get

        default Config get​(String key)
        Returns the single sub-node for the specified sub-key.

        The format of the key is described on key() method.

        Parameters:
        key - sub-key of requested sub-node
        Returns:
        config node for specified sub-key, never returns null.
        See Also:
        get(Key)
      • get

        Config get​(Config.Key key)
        Returns the single sub-node for the specified sub-key.
        Parameters:
        key - sub-key of requested sub-node
        Returns:
        config node for specified sub-key, never returns null.
        See Also:
        get(String)
      • detach

        Config detach()
        Returns a copy of the Config node with no parent.

        The returned node acts as a root node for the subtree below it. Its key is the empty string; "". The original config node is unchanged, and the original and the copy point to the same children.

        Consider the following configuration:

         app:
              name: Example 1
              page-size: 20
         logging:
              app.level = INFO
              level = WARNING
         
        The Config instances name1 and name2 represents same data and in fact refer to the same object:
         Config name1 = config
                          .get("app")
                          .get("name");
         Config name2 = config
                          .get("app")
                          .detach()               //DETACHED node
                          .get("name");
        
         assert name1.asString() == "Example 1";
         assert name2.asString() == "Example 1";  //DETACHED node
         
        The only difference is the key each node returns:
         assert name1.key() == "app.name";
         assert name2.key() == "name";            //DETACHED node
         

        See asMap() for example of config detaching.

        Returns:
        returns detached Config instance of same config node
      • type

        Config.Type type()
        Provides the Config.Type of the Config node.
        Returns:
        the Type of the configuration node
      • exists

        default boolean exists()
        Returns true if the node exists, whether an object, a list, or a value node.
        Returns:
        true if the node exists
      • isLeaf

        default boolean isLeaf()
        Returns true if this node exists and is a leaf node (has no children).

        A leaf node has no nested configuration subtree and has a single value.

        Returns:
        true if the node is existing leaf node, false otherwise.
      • hasValue

        boolean hasValue()
        Returns true if this configuration node has a direct value.

        This may be a value node (e.g. a leaf) or object node or a list node (e.g. a branch with value). The application can invoke methods such as as(Class) on nodes that have value.

        Returns:
        true if the node has direct value, false otherwise.
      • ifExists

        default void ifExists​(Consumer<Config> action)
        Performs the given action with the config node if node exists, otherwise does nothing.
        Parameters:
        action - the action to be performed if the node exists
        See Also:
        exists(), type()
      • traverse

        default Stream<Config> traverse()
        Iterative deepening depth-first traversal of the node and its subtree as a Stream<Config>.

        If the config node does not exist or is a leaf the returned stream is empty.

        Depending on the structure of the configuration the returned stream can deliver a mix of object, list, and leaf value nodes. The stream will include and traverse through object members and list elements.

        Returns:
        stream of deepening depth-first sub-nodes
      • traverse

        Stream<Config> traverse​(Predicate<Config> predicate)
        Iterative deepening depth-first traversal of the node and its subtree as a Stream<Config>, qualified by the specified predicate.

        If the config node does not exist or is a leaf the returned stream is empty.

        Depending on the structure of the configuration the returned stream can deliver a mix of object, list, and leaf value nodes. The stream will include and traverse through object members and list elements.

        The traversal continues as long as the specified predicate evaluates to true. When the predicate evaluates to false the node being traversed and its subtree will be excluded from the returned Stream<Config>.

        Parameters:
        predicate - predicate evaluated on each visited Config node to continue or stop visiting the node
        Returns:
        stream of deepening depth-first subnodes
      • convert

        <T> T convert​(Class<T> type,
                      String value)
               throws ConfigMappingException
        Convert a String to a specific type. This is a helper method to allow for processing of default values that cannot be typed (e.g. in annotations).
        Type Parameters:
        T - type
        Parameters:
        type - type of the property
        value - String value
        Returns:
        instance of the correct type
        Throws:
        ConfigMappingException - in case the String provided cannot be converted to the type expected
        See Also:
        as(Class)
      • as

        <T> ConfigValue<T> as​(GenericType<T> genericType)
        Typed value as a ConfigValue for a generic type. If appropriate mapper exists, returns a properly typed generic instance.

        Example:

         
         ConfigValue<Map<String, Integer>> myMapValue = config.as(new GenericType<Map<String, Integer>>(){});
         myMapValue.ifPresent(map -> {
              Integer port = map.get("service.port");
          }
         
         
        Type Parameters:
        T - type of the returned value
        Parameters:
        genericType - a (usually anonymous) instance of generic type to prevent type erasure
        Returns:
        properly typed config value
      • asBoolean

        default ConfigValue<Boolean> asBoolean()
        Boolean typed value.
        Returns:
        typed value
      • asString

        default ConfigValue<String> asString()
        String typed value.
        Returns:
        typed value
      • asLong

        default ConfigValue<Long> asLong()
        Long typed value.
        Returns:
        typed value
      • asDouble

        default ConfigValue<Double> asDouble()
        Double typed value.
        Returns:
        typed value
      • asList

        <T> ConfigValue<List<T>> asList​(Function<Config,​T> mapper)
                                 throws ConfigMappingException
        Returns this node as a list converting each list value using the provided mapper.
        Type Parameters:
        T - type of list elements
        Parameters:
        mapper - mapper to convert each list node into a typed value
        Returns:
        a typed list with values
        Throws:
        ConfigMappingException - in case the mapper fails to map the values
      • asMap

        ConfigValue<Map<String,​String>> asMap()
                                             throws MissingValueException
        Transform all leaf nodes (values) into Map instance.

        Fully qualified key of config node is used as a key in returned Map. Detach config node before transforming to Map in case you want to cut current Config node key prefix.

        Let's say we work with following configuration:

         app:
              name: Example 1
              page-size: 20
         logging:
              app.level = INFO
              level = WARNING
         
        Map app1 contains two keys: app.name, app.page-size.
        
         Map<String, String> app1 = config.get("app").asMap();
         
        Detaching app config node returns new Config instance with "reset" local root.
        
         Map<String, String> app2 = config.get("app").detach().asMap();
         
        Map app2 contains two keys without app prefix: name, page-size.
        Returns:
        new Map instance that contains all config leaf node values
        Throws:
        MissingValueException - in case the node is Config.Type.MISSING.
        See Also:
        traverse(), detach()
      • changes

        @Deprecated
        default Flow.Publisher<Config> changes()
        Deprecated.
        Allows to subscribe on change on whole Config as well as on particular Config node.

        A user can subscribe on root Config node and than will be notified on any change of Configuration. You can also subscribe on any sub-node, i.e. you will receive notification events just about sub-configuration. No matter how much the sub-configuration has changed you will receive just one notification event that is associated with a node you are subscribed on. If a user subscribes on older instance of Config and ones has already been published the last one is automatically submitted to new-subscriber.

        The Config notification support is based on ConfigSource changes support.

        Method Flow.Subscriber.onError(Throwable) is never called. Method Flow.Subscriber.onComplete() is called in case an associated ConfigSource's changes Publisher signals onComplete as well.

        Note: It does not matter what instance version of Config (related to single Config.Builder initialization) a user subscribes on. It is enough to subscribe just on single (e.g. on the first) Config instance. There is no added value to subscribe again on new Config instance.

        Returns:
        Flow.Publisher to be subscribed in. Never returns null.
        See Also:
        onChange(Function)
      • onChange

        @Deprecated
        default void onChange​(Function<Config,​Boolean> onNextFunction)
        Deprecated.
        use onChange(Consumer) instead
        Directly subscribes onNextFunction function on change on whole Config or on particular Config node.

        It automatically creates Flow.Subscriber that will delegate Flow.Subscriber.onNext(Object) to specified onNextFunction function. Created subscriber automatically requests all events in it's Flow.Subscriber.onSubscribe(Flow.Subscription) method. Function onNextFunction returns false in case user wants to cancel current subscription.

        A user can subscribe on root Config node and than will be notified on any change of Configuration. You can also subscribe on any sub-node, i.e. you will receive notification events just about sub-configuration. No matter how much the sub-configuration has changed you will receive just one notification event that is associated with a node you are subscribed on. If a user subscribes on older instance of Config and ones has already been published the last one is automatically submitted to new-subscriber.

        The Config notification support is based on ConfigSource changes support.

        Note: It does not matter what instance version of Config (related to single Config.Builder initialization) a user subscribes on. It is enough to subscribe just on single (e.g. on the first) Config instance. There is no added value to subscribe again on new Config instance.

        Parameters:
        onNextFunction - Flow.Subscriber.onNext(Object) functionality
        See Also:
        changes(), ConfigHelper.subscriber(Function)
      • onChange

        default void onChange​(Consumer<Config> onChangeConsumer)
        Register a Consumer that is invoked each time a change occurs on whole Config or on a particular Config node.

        A user can subscribe on root Config node and than will be notified on any change of Configuration. You can also subscribe on any sub-node, i.e. you will receive notification events just about sub-configuration. No matter how much the sub-configuration has changed you will receive just one notification event that is associated with a node you are subscribed on. If a user subscribes on older instance of Config and ones has already been published the last one is automatically submitted to new-subscriber.

        Note: It does not matter what instance version of Config (related to single Config.Builder initialization) a user subscribes on. It is enough to subscribe just on single (e.g. on the first) Config instance. There is no added value to subscribe again on new Config instance.

        Parameters:
        onChangeConsumer - consumer invoked on change