///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

///////////////////////////////////////////////////////////////////////////////

:javadoc-base-url-api: {javadoc-base-url}?io/helidon/config

= Property Mapping
:description: Helidon config property mapping
:keywords: helidon, config

Although config values are originally text, you can use the config system's 
built-in conversions or add your own to translate text
into Java primitive types and simple objects (such as `Double`) and to
express parts of the config tree as complex types (`List`, `Map`, and
custom types specific to your application). This section introduces how to
use the built-in mappings and your own custom ones to convert to simple and
complext types.

== Converting Configuration to Simple Types
The link:{javadoc-base-url-api}/Config.html[`Config`] class itself provides many 
conversions to Java types. See the JavaDoc for the complete list. 

The methods which support Java primitive types and their related classes follow a 
common pattern. The examples in the table below deal with conversion to a boolean 
 but the same pattern applies to many data types listed in the JavaDoc. 

Assume a local variable has been assigned something like 
[source,java]
Config config = Config.get("someKey");

.Built-in Conversions to Simple Types (e.g., boolean)
|===
|Java type |Example usage ^1^

|`boolean` |`boolean b = config.asBoolean();` ^2^ 

`boolean defaultedB = config.asBoolean(true);` ^3^
|`Supplier<Boolean>` |`Boolean b = config.asBooleanSupplier().get();` 
|`Optional<Boolean>` |`Boolean b = config.asOptionalBoolean().orElse(Boolean.TRUE);` ^4^
|`Supplier<Optional<Boolean>>` |
`Boolean b = config.asOptionalBooleanSupplier().get().orElse(Boolean.TRUE);`
|===


Notes on Built-in Conversions to Simple Types
====
^1^ All conversions can throw `MissingValueException` (if no value exists at the 
requested key) and `ConfigMappingException` (if some error occurred performing
the data mapping).

^2^ The `Config.asXXX` methods internally use the Java-provided `XXX.parseXXX` methods, so here 
a missing or unparseable string gives `false` because that is how `Boolean.parseBoolean`
behaves.

^3^ User code defaults the value to `true`.

^4^ User code defaults the value to `Boolean.TRUE` if absent; otherwise parses 
the value using `Boolean.parseBoolean`.
====

The numerous conversions defined on the `Config` class for other types (integers, 
doubles, etc.) will satisfy 
many of your application's needs. The link:{javadoc-base-url-api}/ConfigMappers.html[`ConfigMappers`] class 
includes other related mappings from `String` (rather than from `Config`) to 
Java types (described in the JavaDoc).

For additional simple type mapping, you can use these methods defined on `Config`:
[source,java]
T as(Class<? extends T> type);
T as(Class<? extends T> type, T defaultValue);

which maps a single `String` config value to a type. 

The next example, and later 
ones below showing complex type mapping, use the example 
<<config/01_introduction.adoc#app-properties,`application.properties`>> configuration 
from the config introduction. Part of that example includes this line:
[source]
----
bl.initial-id = 10000000000
----
Your application can use `Config.as` to interpret the value as a `BigDecimal`:
[source,java]
BigDecimal initialId = config.get("bl.initial-id").as(BigDecimal.class);


== Converting Configuration to Complex Types

The <<config/03_hierarchical-features.adoc,hierarchical features>> section describes
the tree structure used to represent config data. The config system can map subtrees
of a config tree to complex Java types.

=== Built-in Conversions to `List` and `Map`
The `Config` class exposes several methods for mapping a structured config node 
to a Java `List` or `Map`. The link:{javadoc-base-url-api}/Config.html[JavaDoc] 
contains complete details, but briefly your application can convert a structured `Config` node into:

* a `List<T>` of a given type, with or without default values,
* an `Optional<List<T>>`,
* a `Map<String, String>` in which each key is the fully-qualified key `String` for a
config entry and the value is its `String` value, or
* an `Optional<Map<String, String>>`.

=== Custom Conversions
Often your code will be simpler if you can treat parts of the configuration as
custom, application-specific Java objects, rather than as a group of `String` keys and 
values. You will need customized conversions to do so.

The config system provides many ways to accomplish this, described in
the link:{javadoc-base-url-api}/package-summary.html#conversions[`io.helidon.config` 
package JavaDoc].

Some of those approaches require that the target class -- the class to which
you want to convert the configuration data -- have certain characteristics
 or that you add a method to the class to help do the mapping.
You might want to avoid changing the target class or you
might not even be able to if you do not control its source.

Here are two approaches that will always work without requiring changes
to the target class. For both you write your own
custom link:{javadoc-base-url-api}/ConfigMapper.html[`ConfigMapper`] class. 
The difference is in how your application triggers the use of that mapper.

==== Use Custom Mapper Explicitly: `Config.map` method
Any time your application has a `Config` instance to map to the target class
it invokes `Config.map` passing an instance of the corresponding `ConfigMapper`
implementation:
[source,java]
----
Config config = Config.get("web");
WebConfig web = config.map(new WebConfigMapper());
----
You do not necessarily need a new instance of the mapper every time you want to use
it.

In this approach, everywhere your application needs to perform this conversion it specifies the
mapper to use. If you decided to change which mapper to use you would need
to update each of those places in your application.

==== Register Custom Mapper Once, Use Implicitly: `Config.as` method
In this approach, your application:

1. Tells each `Config.Builder`
that needs to know about the custom mapper by either:
   a. registering an instance of your mapper by invoking `Config.Builder.addMapper`, or
   b. implementing 
link:{javadoc-base-url-api}/spi/ConfigMapperProvider.html[`ConfigMapperProvider`] 
so it returns an instance of your mapper (see the JavaDoc for complete information) 
and creating or editing the file `io.helidon.config.spi.ConfigMapperProvider` 
so it contains 
a line with the fully-qualified class name of your `ConfigMapperProvider`. The
config system will use the Java service loader to find and invoke all 
`ConfigMapperProvider` classes listed and add the mappers they provide to each 
`Config.Builder` automatically.
2. Converts using the mapper by invoking the
`Config.as` method which accepts the target type to convert to, _not_ the
mapper itself that does the conversion. 

If your application converts to the same 
target type in several places in the code, this approach allows you to change which mapper it uses by
changing only the _registration_ of the mapper, not each use of it. 

==== Continuing the `Web` Example
The following examples build on the example configuration from the
<<config/01_introduction.adoc#create-simple-config-props,`application.properties`>>
example file in the introduction.


[source,java]
.Java POJO to Hold `web` Properties Config
----
public class WebConfig {
    private boolean debug;
    private int pageSize;
    private double ratio;

    public WebConfig(boolean debug, int pageSize, double ratio) {
        this.debug = debug;
        this.pageSize = pageSize;
        this.ratio = ratio;
    }

    public boolean isDebug() {
        return debug;
    }

    public int getPageSize() {
        return pageSize;
    }

    public double getRatio() {
        return ratio;
    }
}
----

[source,java]
.Custom Mapper Class
----
public class WebConfigMapper implements ConfigMapper<WebConfig> {

        @Override
        public WebConfig apply(Config config) throws ConfigMappingException, MissingValueException {
            WebConfig web = new WebConfig(
                config.get("debug").asBoolean(false),
                config.get("page-size").asInt(10),
                config.get("ratio").asDouble(1.0)
            );

            return web;
        }
    }
----

[source,java]
.Explicitly Using the Mapper
----
...
    Config config = Config.withSources(classpath("application.properties"))
        .build();

    WebConfig web = config.get("web")
        .map(new WebConfigMapper());
----

[source,java]
.Registering and Implicitly Using the Mapper
----
...
    Config config = Config.withSources(classpath("application.properties"))
        .addMapper(WebConfig.class, new WebConfigMapper())
        .build();

    WebConfig web = config.get("web")
        .as(WebConfig.class);
----
Either of the two approaches just described will _always_ work without requiring you to change 
the POJO class.

== Advanced Conversions using Explicit Mapping Logic 
If the target Java class you want to use meets certain conditions -- or if you can change
it to meet one of those conditions -- you might not need to write a separate mapper 
class. Instead, you add the mapping logic to the POJO itself in one of
several ways and the config system 
uses Java reflection to search for those ways to perform the mapping. 

Your application facilitates this implicit mapping either by adding to the 
POJO class or by providing a builder class for it.

=== Adding the Mapping to the POJO
If you can change the target class you can add any one of the following methods or 
constructors to the POJO class which the config system will find and use for mapping.

.Methods Supporting Auto-mapping
|===

|`static WebConfig from(Config);`
|`static WebConfig from(String);`
|`static WebConfig valueOf(Config);`
|`static WebConfig valueOf(String);`
|`static WebConfig fromConfig(Config);`
|`static WebConfig fromString(String);`
|===

.Constructors Supporting Auto-mapping
|===

|`WebConfig(Config);`
|`WebConfig(String);`
|===

If the config system finds any of these methods or constructors when the
application invokes

[source,java]
WebConfig wc = config.as(WebConfig.class);

it will invoke the one it found to
map the config data to a new instance of the target class. You do not need to
write a separate class to do the mapping or register it with the `Config.Builder`
for the config instance.

=== Writing a Builder Method and Class for the POJO
You can limit the changes to the POJO class by adding a single 
`builder` method to the POJO which returns a builder class for the POJO:
[source,java]
public class WebConfig {
...
    static WebConfigBuilder builder() {
        return new WebConfigBuilder();
    }
...
}

The builder class `WebConfigBuilder` is expected to be a Java Bean with

1. bean properties named for the config properties of interest, and 
2. a method `WebConfig build()` which creates the mapped instance
from the builder's own bean properties.

When your application invokes `config.as(WebConfig.class)` the config system

1. finds and invokes the `WebConfig.builder()` method,
2. assigns the bean properties on the returned builder from the config subtree
rooted at `config`, and
3. invokes the builder's `build()` method yielding the resulting `WebConfig` instance.


== Conversions using JavaBean Deserialization
////
10. a factory method `from(...)` with parameters (loaded from config sub-nodes)
 creates new instance of a bean.
11. a _factory_ constructor with parameters (loaded from config sub-nodes).
12. a no-parameter constructor to create new instance of type and apply
 recursively same mapping behaviour
described above on each JavaBean property of such object,
a.k.a. <<Config-PropertyMapping-Deserialization,JavaBean deserialization>>.
////

The config system can also interpret your classes as JavaBeans and use 
the normal bean naming conventions to map configuration data to your POJO classes,
using one of these patterns:

1. <<pojoAsJavaBean,POJO as JavaBean>> - The config system treats the target class itself as
a JavaBean, assigning values from the config to the bean properties of the POJO
class.
2. <<builderAsJavaBean,builder as JavaBean>> - The config system invokes the POJO's `builder()` 
method to obtain a builder for that POJO type and treats the _builder_ 
class as a JavaBean, assigning values from the config to the builder's
bean properties and then invoking the builder's `build` method to create
an instance of the target POJO class.
3. <<pojoWithFactoryMethodOrConstructor,POJO with factory method or decorated constructor>> - The 
config system finds a `from` method or a constructor on 
the POJO class itself which accepts annotated arguments, then invokes that method
or constructor
passing the specified arguments based on the config. The `from` method returns
an instance of the POJO class initialized with the values passed as arguments.

The following sections describe these patterns in more detail.

=== POJO as JavaBean [[pojoAsJavaBean]]
If your POJO target class is already a JavaBean -- or you can modify it
to become one -- you might be able to avoid writing any explicit
mapping code yourself. 

The config system invokes the no-args constructor on the target class to create
a new instance. It treats each public setter method and each public non-final field
as a JavaBean property. The config system processes any non-primitive property 
recursively as a JavaBean. In this way the config system builds up the target
object from the config data.

By default, the system matches potential JavaBean property names with 
config keys in the configuration. 

Use the link:{javadoc-base-url-api}/Config.Value.html[`Config.Value`] annnotation to control some of the JavaBean processing for a 
given property.

.`Config.Value` Annotation
|===
|Attribute |Usage

|`key` |Indicates which config key should match this JavaBean property
|`withDefault` |`String` used for the bean property default value if none is set in the config
|`withDefaultSupplier` |`Supplier` of the default bean property value if nont is set in the config
|===

To exclude a bean property from the config system bean processing annotate it with 
link:{javadoc-base-url-api}/Config.Transient.html[`Config.Transient`]. 

Here is an example using the `app` portion of the example configuration from the
introduction.

[source,java]
.Java bean to load `app` propeties into via setters
----
public class AppConfig {
    private Instant timestamp;
    private String greeting;
    private int pageSize;
    private List<Integer> basicRange;

    public AppConfig() {                                          // <1>
    }

    public void setGreeting(String greeting) {                    // <2>
        this.greeting = greeting;
    }
    public String getGreeting() {
        return greeting;
    }

    @Config.Value(key = "page-size",                              // <3>
                  withDefault = "10")                             // <4>
    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }
    public int getPageSize() {
        return pageSize;
    }

    @Config.Value(key = "basic-range",                            // <5>
                  withDefaultSupplier = BasicRangeSupplier.class) // <6>
    public void setBasicRange(List<Integer> basicRange) {
        this.basicRange = basicRange;
    }
    public List<Integer> getBasicRange() {
        return basicRange;
    }

    @Config.Transient                                             // <7>
    public void setTimestamp(Instant timestamp) {
        this.timestamp = timestamp;
    }
    public Instant getTimestamp() {
        return timestamp;
    }

    public static class BasicRangeSupplier
            implements Supplier<List<Integer>> {                  // <8>
        @Override
        public List<Integer> get() {
            return List.of(-10, 10);
        }
    }
}
----

<1> Public no-parameter constructor.
<2> Property `greeting` is not customized and will be set from the config node with
 the key `greeting`, if present in the config.
<3> Property `pageSize` is matched to the config key `page-size`.
<4> If the `page-size` config node does not exist, the `pageSize` bean property defaults to `10`.
<5> Property `basicRange` is matched to the config key `basic-range`.
<6> If the `basic-range` config node does not exist, a `BasicRangeSupplier` instance will provide
the default value.
<7> The `timestamp` bean property is never set, even if the config contains a node
 with the key `timestamp`.
<8> `BasicRangeSupplier` is used to supply the `List<Integer>` default value.

Here is an example of code loading config and mapping part of it to the `AppConfig`
bean above.

[source,java]
.Map `app` config node into `AppConfig` class
----
Config config = Config.from(classpath("application.conf"));

AppConfig app = config.get("app")
        .as(AppConfig.class);                               // <1>

//assert that all values are loaded from file
assert app.getGreeting().equals("Hello");
assert app.getPageSize() == 20;
assert app.getBasicRange().size() == 2
        && app.getBasicRange().get(0) == -20
        && app.getBasicRange().get(1) == 20;

//assert that Transient property is not set
assert app.getTimestamp() == null;                          // <2>
----

<1> The config system finds no registered `ConfigMapper` for `AppConfig` and so
applies the JavaBean pattern to convert the config to an `AppConfig` instance.
<2> Because the bean property `timestamp` was marked as transient, the
config system did not set it.


=== Builder as JavaBean [[builderAsJavaBean]]
If the target class includes the public static method `builder()` that returns any object, 
then the config system will make sure that the return type has a method `build()` 
which returns an instance of the target class. If so, the config system treats
the _builder_ as a JavaBean and

1. invokes the `builder()` method to instantiate the builder class,
2. treats the _builder_ as a JavaBean and maps the `Config` subtree to it,
3. invokes the builder's `build()` method to create the new instance of the target
class.

There are two ways to use this feature:
1. <<addBuilderToTargetClass,Augment the target class with the public static `builder()` method.>>
2. <<writeSeparateBuilder,Write a separate builder class and tell the `Config.Builder` to associate the 
target class and the builder class.>>

==== Add `builder()` to Target Class [[addBuilderToTargetClass]]

Here is one way to use this feature:

[source,java]
.JavaBean for `app` properties, via a `Builder`
----
public class AppConfig {
    private String greeting;
    private int pageSize;
    private List<Integer> basicRange;

    private AppConfig(String greeting, int pageSize, List<Integer> basicRange) { // <1>
        this.greeting = greeting;
        this.pageSize = pageSize;
        this.basicRange = basicRange;
    }

    public String getGreeting() {
        return greeting;
    }

    public int getPageSize() {
        return pageSize;
    }

    public List<Integer> getBasicRange() {
        return basicRange;
    }

    public static Builder builder() {                                            // <2>
        return new Builder();
    }

    public static class Builder {                                                // <3>
        private String greeting;
        private int pageSize;
        private List<Integer> basicRange;

        private Builder() {
        }

        public void setGreeting(String greeting) {                               // <4>
            this.greeting = greeting;
        }

        @Config.Value(key = "page-size",
                      withDefault = "10")
        public void setPageSize(int pageSize) {                                  // <5>
            this.pageSize = pageSize;
        }

        @Config.Value(key = "basic-range",
                      withDefaultSupplier = BasicRangeSupplier.class)
        public void setBasicRange(List<Integer> basicRange) {                    // <6>
            this.basicRange = basicRange;
        }

        public AppConfig build() {                                               // <7>
            return new AppConfig(greeting, pageSize, basicRange);
        }
    }
}
----

<1> The target class's constructor can be `private` in this case because new instances are created 
from the inner class `Builder` which has access to `AppConfig`'s private members.
<2> The target class contains `public static` method `builder()` which returns
an object that itself exposes the method `AppConfig build()`, so the config system
recognizes it.
<3> The config system treats the `AppConfig.Builder` (not the enclosing
target class) as a JavaBean.
<4> The builder's property `greeting` is not customized and is set from config node with
 `greeting` key, if one exists.
<5> The builder's property `pageSize` maps to the config key `page-size` and
defaults to `10` if absent.
<6> The builder's property `basicRange` maps to the config key `basic-range`
and uses a `BasicRangeSupplier` instance to get a default value if needed.
<7> Finally, the config system invokes the builder's public method `build()`,
creating the new instance of `AppConfig` for use by the application.

==== Write a Builder Separate from the Target Class [[writeSeparateBuilder]]
If you cannot or do not want to add the `builder()` method to the target class,
you can instead associate a separate builder to be processed as a JavaBean with
the target class.

This example shows the target type as a Java interface instead of a class. Either
will work.

[source,java]
.Target Type `IAppConfig`
----
public interface IAppConfig {
    String getGreeting();
    int getPageSize();
    List<Integer> getBasicRange();
}
----

[source,java]
.Separate `BuilderImpl` with an implementation `AppConfigImpl` of IAppConfig
----
public class BuilderImpl {                                        // <1>
    private String greeting;
    private int pageSize;
    private List<Integer> basicRange;

    public BuilderImpl() {                                        // <1>
    }

    @Config.Value(key = "greeting")
    public BuilderImpl greeting(String greeting) {                // <2>
        this.greeting = greeting;
        return this;
    }

    @Config.Value(key = "page-size", withDefault = "10")
    public BuilderImpl pageSize(int pageSize) {                   // <2>
        this.pageSize = pageSize;
        return this;
    }

    @Config.Value(key = "basic-range",
                  withDefaultSupplier = BasicRangeSupplier.class)
    public BuilderImpl basicRange(List<Integer> basicRange) {     // <2>
        this.basicRange = basicRange;
        return this;
    }

    public IAppConfig build() {                                   // <3>
        return new AppConfigImpl(greeting, pageSize, basicRange);
    }

    /**
     * Private implementation provided by {@link BuilderImpl}.
     */
    private static class AppConfigImpl implements IAppConfig {    // <4>
        private String greeting;
        private int pageSize;
        private List<Integer> basicRange;

        private AppConfigImpl(String greeting,
                              int pageSize,
                              List<Integer> basicRange) {
            this.greeting = greeting;
            this.pageSize = pageSize;
            this.basicRange = basicRange;
        }
        @Override
        public String getGreeting() {
            return greeting;
        }
        @Override
        public int getPageSize() {
            return pageSize;
        }
        @Override
        public List<Integer> getBasicRange() {
            return basicRange;
        }
    }
}
----

<1> Class `BuilderImpl` must be public including, its public no-args
 constructor, because the config system instantiates it. 
<2> The builder can use the _builder_ pattern (the methods return the builder 
itself so the caller can chain calls together) instead of the usual JavaBean setter
method pattern. In that case, decorate each builder method (e.g, `greeting`) using
 `@Config.Value` to associate it with the correct config key.
<3> The builder's `build()` is declared to return `IAppConfig` and in fact returns 
an instance of `AppConfigImpl` which implements `IAppConfig`.
<4> The `AppConfigImpl` class can be private to the builder because the builder
itself instantiates it and all other code will use the `IAppConfig` interface
to access the mapped config data.

Because the config system cannot infer a link between the target class and the 
separate builder, the application makes that link explicit to the `Config.Builder`:

[source,java]
.Register `BuilderImpl` as `IAppConfig` mapper
----
Config config = Config.withSources(classpath("application.conf"))
        .addMapper(IAppConfig.class,                                        // <1>
                   ConfigMappers.from(IAppConfig.class, BuilderImpl.class)) // <2>
        .build();

IAppConfig app = config.get("app")
        .as(IAppConfig.class);                                              // <3>
----

<1> Programmatically registers the mapper for the `IAppConfig` interface.
<2> Creates a config mapper for `IAppConfig` that uses `BuilderImpl` by invoking
the convenience method `ConfigMappers.from(type, builder)`.
<3> Config system uses `BuilderImpl` to map the config subtree to `IAppConfig`.


=== Target Class with Annotated Factory Method or Constructor [[pojoWithFactoryMethodOrConstructor]]

Another option is to annotate the parameters to a _factory method_ or to a constructor
on the target class. You can add a _factory method_ to the target class, a `public static`
method `from` with parameters annotated to link them to the corresponding config
keys. Or you can add or modify a constructor with parameters, similarly annotated
to form the link from each parameter to the corresponding config key.

[WARNING]
=========
Be sure to annotate each parameter of the `from` method or constructor with `@Value` 
and specify the key to use for the mapping. The parameter names in the Java code
are not always available at runtime to map to config keys. (They might be `arg0`,
 `arg1`, etc.)
=========

[source,java]
.Target Class with Factory Method `from`
----
public class AppConfig {
    private final String greeting;
    private final int pageSize;
    private final List<Integer> basicRange;

    private AppConfig(String greeting, int pageSize, List<Integer> basicRange) { // <1>
        this.greeting = greeting;
        this.pageSize = pageSize;
        this.basicRange = basicRange;
    }

    public String getGreeting() {
        return greeting;
    }

    public int getPageSize() {
        return pageSize;
    }

    public List<Integer> getBasicRange() {
        return basicRange;
    }

    public static AppConfig from(                                                // <2>
            @Config.Value(key = "greeting")
                    String greeting,                                             // <3>
            @Config.Value(key = "page-size",
                          withDefault = "10")
                    int pageSize,
            @Config.Value(key = "basic-range",
                          withDefaultSupplier = BasicRangeSupplier.class)
                    List<Integer> basicRange) {
        return new AppConfig(greeting, pageSize, basicRange);
    }
}
----

<1> The target class constructor can be `private` because the factory method on
the same class has access to it.
<2> The config system invokes the factory method `from(...)`, passing 
arguments it has fetched from the correspondingly-named config subtrees.
The factory method returns the new initialized `AppConfig` instance.
Note the consistent use of `@Config.Value(key = "...")` on each parameter.
<3> Because the property `greeting` does not specify a default value 
the property is **mandatory** and must appear in the configuration source.
Otherwise the config system throws a `ConfigMappingException`.

Alternatively, you can use an annotated constructor instead of a static factory 
method. Revising the example above, make the constructor public, annotate its
parameters, and remove the now-unneeded `from` factory method.

[source,java]
.Target Class with Annotated Public Constructor
----
public class AppConfig {
    ...
    public AppConfig( // <1>
        @Config.Value(key = "greeting") // <2>
                String greeting, 
        @Config.Value(key = "page-size",
                          withDefault = "10")
                int pageSize, 
        @Config.Value(key = "basic-range",
                          withDefaultSupplier = BasicRangeSupplier.class)
                List<Integer> basicRange) {
        this.greeting = greeting;
        this.pageSize = pageSize;
        this.basicRange = basicRange;
    }
----
<1> Constructor is `public`.
<2> Each parameter has the `ConfigValue` annotation to at least specify the 
config key name.

When the application invokes `config.as(AppConfig.class)`, the config system locates
the public annotated constructor and invokes it, passing as arguments the data it fetches 
from the configuration matching the annotation `key` names with the configuration
keys.
