Skip to content

Commit

Permalink
@ConfigMapping specification
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez committed Mar 7, 2024
1 parent b2c6d73 commit 14be031
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Configuration {
public @interface ConfigMapping {

/**
* The <em>configuration path</em> identifies where the configuration relevant for the annotated configuration class is found
Expand Down
2 changes: 1 addition & 1 deletion api/src/main/java/jakarta/config/Loader.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public interface Loader {
* @param path a configuration path.
* @return a new instance of the {@link Loader} class with a configured <em>path</em>.
*
* @see Configuration#path() Configuration#path
* @see ConfigMapping#path() Configuration#path
*/
Loader path(String path);

Expand Down
129 changes: 129 additions & 0 deletions spec/src/main/asciidoc/99-config-mapping.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
= Config Mapping

Config Mapping allows mapping configuration entries to complex object types (usually user defined), following certain
rules:

- A configuration path uniquely identifies object member
- A configuration value maps to the object member value type
== Mapping Rules

A complex object type uses the following rules to map configuration values to their member values:

- A configuration path is built by taking the object type prefix (or namespace) and the mapping member name
- The member name is converted to its kebab-case format
- If the member name is represented as a getter, the member name is taken from its property name equivalent, and then
converted to its kebab-case format.
- The configuration value is automatically converted to the member type
- The configuration path is required to exist with a valid configuration value or the mapping will fail.

=== Nested Types

- A nested type contributes with its name (converted to its kebab-case format)
- The configuration path is built by taking the root object type prefix (or namespace), the nested
type name and the member name of the nested type

=== Collections and Arrays

- A member with a `Collection` or `Array` type requires the configuration name to be in its indexed format
- Each configuration name, plus its index maps the configuration value to the corresponding `Collection` or
`Array` element in the object type
- TODO - Define how to represent the indexed format. A well accepted representation is the presence of square brackets
with the collection / array index inside after the name.
- The index specified in the configuration name is used to order the element in the `Collection` or `Array`. Missing
elements or gaps are removed.

=== Maps

- A member with a `Map` type requires an additional configuration name added to the configuration path of the `Map`
member to act as a map key
- The additional configuration name maps a Map entry with the configuration name as the `Map` entry key and
the configuration value as the Map entry value

=== Optionals

- A mapping can wrap any complex type with an `Optional`
- `Optional` mappings do not require the corresponding configuration path and value to be present

== Override Conventions

It is possible to override:

- The base configuration path (prefix or namespace) of the mapping
- Mapping member names
- The default Converter of a member
- Add a default value to a member

== Examples

=== Mapping definition
[source,java]
----
@ConfigMapping("my.config")
interface Server {
// my.config.host
String host();
// my.config.port
int port();
// my.config.io-threads
int ioThreads();
// my.config.endpoints[*].path
// my.config.endpoints[*].methods
List<Endpoint> endpoints();
Optional<Ssl> ssl();
// my.config.form.login-page
Map<String, String> form();
interface Ssl {
// my.config.ssl.port
int port();
// my.config.ssl.certificate
String certificate();
// my.config.ssl.protocols[*]
List<String> protocols();
}
interface Endpoint {
String path();
List<String> methods();
}
}
----

=== Programmatic Access

[source,java]
----
class Service {
Config config;
void service() {
Server server = config.load(Server.class);
}
}
----

=== Overriding Conventions

[source,java]
----
@ConfigMapping("my.config")
interface Server {
@ConfigName("hostname")
Host host();
@ConfigDefault("8080")
int port();
@ConfigConverter(IOThreadsConverter.class)
int ioThreads();
}
----
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@

package jakarta.config.tck.common;

import jakarta.config.Configuration;
import jakarta.config.ConfigMapping;

@Configuration(path = "my.configuration")
@ConfigMapping(path = "my.configuration")
public interface AnyConfiguration {
String key();
}
4 changes: 2 additions & 2 deletions tck/src/main/java/jakarta/config/tck/common/My.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@

package jakarta.config.tck.common;

import jakarta.config.Configuration;
import jakarta.config.ConfigMapping;

@Configuration(path="my")
@ConfigMapping(path="my")
public interface My {
String username();
String password();
Expand Down
4 changes: 2 additions & 2 deletions tck/src/main/java/jakarta/config/tck/common/Other.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@

package jakarta.config.tck.common;

import jakarta.config.Configuration;
import jakarta.config.ConfigMapping;

@Configuration(path = "other")
@ConfigMapping(path = "other")
public interface Other {
AnyConfiguration configuration();
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@

package jakarta.config.tck.common;

import jakarta.config.Configuration;
import jakarta.config.ConfigMapping;

@Configuration
@ConfigMapping
public interface TopLevelConfig {
My my();
Other other();
Expand Down

0 comments on commit 14be031

Please sign in to comment.