- Overview
- Getting Started
- Configuration Factory
- Configuration Keys
- Type Converters
- Configuration Types with Generics
- Spring Framework Integration
- Extras
conf4j is a library which allows accessing configuration data in object-oriented, type-safe manner.
Configuration is represented as an interface or abstract class optionally annotated with conf4j annotations.
- Simple, intuitive, annotation driven API for defining configuration types.
- All configuration properties are statically typed and validated.
- Out of the box support for all primitive types and they wrappers as well as
List
andMap
. - Integrated with Spring Framework and and Spring Boot.
- High level API for accessing configuration values.
- Minimum set of dependencies: SLF4J, commons-lang and commons-text.
To start playing with conf4j just add the dependency to com.sabre.oss.conf4j:conf4j-core or com.sabre.oss.conf4j:conf4j-spring (if you wish to integrate the library with Spring Framework).
Maven
<dependency>
<groupId>com.sabre.oss.conf4j</groupId>
<artifactId>conf4j-core</artifactId>
<version>${conf4j.version}</version>
</dependency>
Gradle
dependencies {
compile "com.sabre.oss.conf4j:conf4j-core:$conf4jVersion"
}
Of course make sure conf4j.version
variable (for Maven) or conf4jVersion
(for Gradle) is set to the proper
conf4j version.
In conf4j, a configuration is expressed as a public interface or public abstract class annotated with conf4j annotations.
@Key("connection")
public interface ConnectionConfiguration {
String getUrl();
TimeoutConfiguration getTimeouts();
}
public interface TimeoutConfiguration {
@Default("60")
int getConnectionTimeout();
@Default("30")
int getReadTimeout();
}
The configuration consists of a set of properties (which follows JavaBeans naming conventions).
Each property must be an public
, abstract
, parameter-less method which return type cannot be void
.
The return type can be any type supported by the TypeConverter
, another configuration type
or List
of configuration types.
Every configuration property has a set of configuration keys assigned which are determined
based on property name, @Key
, @FallbackKey
, @IgnorePrefix
and @IgnoreKey
annotations.
The rules that govern how the configuration key set is constructed are covered in the
Configuration Keys section.
When a value related to a configuration property is required, it is retrieved from the ConfigurationSource
.
Each key associated with the property is checked in the sequence until the value associated with the key is found
in the configuration source. It is also possible to specify a default value for the property via the
@Default
annotation and @DefaultsAnnotation
meta-annotations. See javadoc for details.
The configuration type is like a template. Before you begin accessing the configuration, a configuration instance
must first be created and bound to the configuration source. This can be done via ConfigurationFactory.createConfiguration()
as shown below.
// Create configuration source from the property file.
ConfigurationSource source = new PropertiesConfigurationSource("configuration.properties");
// Create configuration factory - it is thread safe.
ConfigurationFactory factory = new JdkProxyStaticConfigurationFactory();
// Create configuration instance and bind it to the configuration source.
ConnectionConfiguration configuration = factory.createConfiguration(ConnectionConfiguration.class, source);
// Now you can access configuration properties via configuration object.
String url = configuration.getUrl();
int connectionTimeout = configuration.getTimeouts().getConnectionTimeout();
The ConfigurationSource
allows accessing a configuration value associated with a key. Both key and value
are represented as string. Of course, very often, the configuration property type is not java.lang.String
so the value must be converted into the appropriate type.
Type converters which implement TypeConverter
interface are responsible for such conversion.
The conf4j library provides type converters for all primitive types (like boolean
, int
, double
),
primitive wrapper types (like Boolean
, Integer
, Double
), enumerations and many other types which are frequently
used (like BigDecimal
). More complex types are also supported - there is a dedicated converter for List<E>
and Map<K, V>
which is able to convert even very complex types like Map<String, Map<Integer, List<Double>>>
. Because lists and maps
are quite complex, the data must be encoded to be represented as a string. Currently JsonLikeConverter
is used
as a default implementation. It encodes List
and Map
as JSON, but by default compact mode is activated to make
the encoded string more user friendly.
For example List<String>
in compact mode is represented as [one,two,tree]
in JSON mode as ["one","two","three"]
.
Map<String, List> in compact mode: {key1:[val11,val12],key2:[val21,val22]}
in JSON: {"key1":["val11","val12"],"key2":["val21","val22"]}
.
Because quotation mark "
must be escaped in java, JSON format is very inconvenient for specifying default value in @Default
.
Please consult javadoc for JsonLikeConverter
class to get more information about the format.
Of course there is possibility to provide custom implementation of TypeConverter
.
For details, see the Type Converters section.
conf4j provides out of the box integration with Spring Framework and Spring Boot application frameworks.
First of all add dependency to com.sabre.oss.conf4j:conf4j-spring
module to your project.
<dependency>
<groupId>com.sabre.oss.conf4j</groupId>
<artifactId>conf4j-spring</artifactId>
<version>${conf4j.version}</version>
</dependency>
Then annotate the root configuration with Spring Framework @Component
annotation.
@Component
public interface ConnectionConfiguration {
String getUrl();
String getUser();
}
Assuming you would like to use annotation-based configuration, use @EnableConf4j
in your configuration class
and search for configurations with @ConfigurationsScan
as shown below.
@EnableConf4j
@ConfigurationScan
public class Application {
@Autowired
private ConnectionConfiguration connectionConfiguration;
public static void main(String[] args) {
try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(Application.class)) {
Application application = context.getBean(Application.class);
application.run();
}
}
private void run() {
String url = connectionConfiguration.getUrl();
// ...
}
@Key("connection")
public interface ConnectionConfiguration {
String getUrl();
@Key("user")
String getUserName();
}
}
For details, see Spring Framework Integration section.
The ConfigurationFactory
interface specifies how the configuration type is instantiated and bound
to the ConfigurationSource
. It takes a configuration type and configuration source and creates a configuration instance.
ConnectionConfiguration configuration = factory.createConfiguration(ConnectionConfiguration.class, source);
How a configuration instance is generated depends on the configuration factory implementation.
There are two flavors of the ConfigurationFactory
: static and dynamic configuration factories.
Static configuration factory creates static/frozen configuration instances which retrieves values from
ConfigurationSource
only during the instance-creation phase. The configuration values are then stored
in the configuration instance and never change in the future. Access to static configuration properties is very fast,
it's just a getter invocation.
Static configuration classes implements the java.io.Serializable
interface which allows a configuration instance
to be serialized, as long as all configuration property types are also serializable.
Dynamic configuration factory
creates a dynamic configuration instance which hits ConfigurationSource
every time the configuration property method is invoked. It is an ideal choice when values in configuration source
changes over time and a configuration should reflect those changes.
Bear in mind there is an overhead associated with a configuration property access. It requires getting configuration
value from the source and converting it the proper type.
conf4j provides three configuration factory families:
JdkProxyStaticConfigurationFactory
andJdkProxyDynamicConfigurationFactory
use jdk proxyjava.lang.reflect.Proxy
for creating configuration instances. These factories support configuration types which are interfaces, abstract classes are not supported due to jdk proxy limitations.JavassistStaticConfigurationFactory
andJavassistDynamicConfigurationFactory
use Javassist to generate configuration implementations on the fly.CglibStaticConfigurationFactory
andCglibDynamicConfigurationFactory
use CGLIB (to be precise - CGLIB repackaged version provided by Spring Framework). These factories are available only when you use conf4j integration with Spring Framework.
Every configuration property has an ordered set of configuration keys assigned. A property can be associated
with multiple keys, and multiple properties can be associated to the same keys. When a configuration value is required,
the keys from the key set is submitted to ConfigurationSource
in sequence until the value associated
with the key is found.
Key set is constructed based on conf4j annotations.
@Key
annotation specifies the key for a value property. If @Key
annotation is missing, the property name is used.
public interface ConnectionConfiguration {
String getUrl();
@Key("user")
String getUserName();
}
ConnectionConfiguration has two configuration properties: url and userName.
The key set for the url property consists of one key url.
When the key name is not specified by the @Key
annotation, the property name is used. @Key
annotation without
parameters is optional (as long as default, non-strict configuration model provider is used) and property name is used
as a key in such case. But using it, indicates explicitly a method is the configuration property and is a good practice.
The userName property has one key user assigned and its name is explicitly specified by the @Key
annotation.
When applied to the configuration type or property which returns sub-configuration or list of sub-configurations,
an @Key
annotation can define a prefix for the configuration keys within the hierarchy.
For the example below, url property has two keys assigned: connection.url and alternateConnection.url.
Please note the prefix and key are joined by .
(dot) character which is a delimiter used to join configuration key components.
@Key({"connection", "alternateConnection"})
public interface ConnectionConfiguration {
String getUrl();
@Key("user")
String getUserName();
}
@Key
normally specifies just one key or prefix; however, it allows you to define multiple keys or prefixes.
If the key prefix value is not specified, the uncapitalized type name or property name is used
(when the @Key
is applied to the sub-configuration).
Here is a more complex scenario with configuration and sub-configurations involved.
@Key({"connection", "alternateConnection"})
public interface ConnectionConfiguration {
String getUrl();
@Key("user")
String getUserName();
TimeoutConfiguration getTimeout();
@Key("default")
TimeoutConfiguration getDefaultTimeout();
@Key("other")
List<TimeoutConfiguration> getOtherTimeouts();
}
@Key("timeout")
public interface TimeoutConfiguration {
@Key("connect")
Integer getConnectTimeout();
@Key("read")
Integer getReadTimeout();
}
Let's create a configuration instance configuration
.
ConnectionConfiguration configuration = factory.createConfiguration(ConnectionConfiguration.class, source);
For the following invocation:
Integer connect = configuration.getTimeout().getConnectTimeout();
the key set for getConnectionTimeout()
is: connection.timeout.connect, alternateConnection.timeout.connect.
connection and alternateConnection key prefixes are defined by @Key
applied on ConfigurationConfiguration
,
timeout key prefix from @Key
applied on @TimeoutConfiguration
.
For the following invocation:
Integer connect = configuration.getDefaultTimeout().getConnectTimeout();
the key set for getConnectionTimeout()
is: connection**.default**.timeout.connect, alternateConnection**.default**.timeout.connect
because getDefaultTimeout()
is annotated with @Key("default")
A list of sub-configurations are handled a little differently. Because the list contains multiple elements, there must be a way to distinguish between keys assigned to different elements. Every element in the list has an index which becomes part of the key.
For the following invocation:
Integer connect = configuration.getOtherTimeouts().get(0).getConnectTimeout();
the key set for getConnectionTimeout()
is:
connection**.other[0]**.timeout.connect, alternateConnection**.other[0]**.timeout.connect,
connection.other.timeout.connect, alternateConnection.other.timeout.connect.
The first two keys have [0]
appended to the other
key component. conf4j uses the [index]
convention
(where index is an element index in the list) to indicate a key is associated with a list element.
Surprisingly the key set contains connection.other.timeout.connect and alternateConnection.other.timeout.connect. They are added for each element's key set as a fallback. These keys are used only when there is no value associated with indexed keys in the configuration source.
For the configuration property which returns a list of sub-configuration there is a need to provide the size of the list.
There is an additional key set associated, which is created by appending the .size suffix.
For configuration.getOtherTimeouts()
the key set is: connection.other.size, alternateConnection.other.size.
conf4j provides more annotations like @FallbackKey
or @IgnoreKey
which influence the way a key set is generated.
Please consult the javadoc for details.
Type converter allows converting a string value into the appropriate type like int
, decimal
or even List<Integer>
.
Type converter must implement a TypeConverter
interface and provide the method for converting a string into a value
of a proper type as well as a method for converting the value back to a string representation.
TypeConverter
is usually provided for simple types like int
but it may also convert complex objects and graphs,
e.g., the objects annotated with JAXB annotations.
The converter must be thread safe and stateless because it's accessed from multiple threads and different contexts. Ideally it should be symmetric so the result of value conversion to string, and then the string back to the value, produces the same value.
conf4j provides converters for commonly used types like int
, long
, boolean
, double
, enumerations, String
but also converts to List<E>
and Map<K, V>
. The former converters are generic and support any E, K, V
types
as long as converters for E, K, V
are available.
Even exotic types are supported: Map<List<String>, List<Map<Integer, Double>>
.
TypeConverter
specifies the format of the string representation of a type. For some types like int
the natural
string representation is already defined, e.g., by toString()
method. On the other hand, you may wish to change
the format slightly. For example, StringConverter
replaces new line separator with \n
character or tab with \t
- in general, it uses the same rules for escaping as Java.
ConfigurationFactory
is pre-configured with wide range of converters (it may be can be altered by setTypeConverter()
).
In case there is a need to use a type converter which is not known by ConfigurationFactory
or the type converter
registered in the factory is not appropriate (e.g. you would like to convert Integer
to hexadecimal value)
@Converter
annotation can be used as shown below:
public interface DateRange {
@Converter(DateTimeConverter.class)
DateTime getStart();
@Converter(DateTimeConverter.class)
DateTime getEnd();
}
TypeConverter
implementation pointed by @Converter
must provide public, parameterless constructor and it is instantiated
on runtime via reflection. Type converter has to be thread-safe and stateless. Because many instances of the converter are created,
make sure creating new instance is fast and created object doesn't occupy much memory.
In general favor setting up ConfigurationFactory
with the appropriate converters over using @Converter
annotation.
Many type converters support custom formats which can be specified via format meta-attribute. Format is converter specific and defines how the configuration value is converter from/to a string. In addition, converters for the numbers support locale meta-attribute - its value must be valid ISO 639 locale code.
Meta-attribute value can be assigned to a configuration property via @Meta
annotation as shown below:
public interface DisplayConfiguration {
@Meta(name="format", value="#.000")
BigDecimal getValue();
}
@Meta
annotation associates meta-attribute with a configuration value. It can be applied on the configuration
property method level as well as on the configuration interface/class level - in this case all configuration properties
defined in the interface/class inherit this meta-attribute. For more details please consult @Meta
javadoc.
meta-attributes are available for type converters and configuration value sources and can be used for any purpose. As mentioned earlier, many conf4j type converters understand format meta-attribute. Whenever type converter is asked for converting string to value (and vice versa), the format attribute's value is used and appropriate formatting applied.
@Meta
annotation can be used for meta annotating custom annotation. It is very handy and allows creating
dedicated annotation like in the example below:
@Meta(name = "format")
@Retention(RUNTIME)
@Target(METHOD)
@Documented
public @interface Format {
String value();
}
Now @Format
annotation can be used instead of @Meta(name="format", value="#.000")
:
public interface DisplayConfiguration {
@Format(value="#.000")
BigDecimal getValue();
}
The table below contains the list of available type converters and the format they support.
Converter | Supported format |
---|---|
BooleanConverter | {true value}/{false value}, for example: true/false or yes/no |
ByteConverter | As defined by DecimalFormat |
ShortConverter | As defined by DecimalFormat |
IntegerConverter | As defined by DecimalFormat |
LongConverter | As defined by DecimalFormat |
FloatConverter | As defined by DecimalFormat |
DoubleConverter | As defined by DecimalFormat |
BigDecimalConverter | As defined by DecimalFormat |
LocalDateTimeConverter | As defined by DateTimeFormatter |
InstantConverter | As defined by DateTimeFormatter |
OffsetDateTimeConverter | As defined by DateTimeFormatter |
DurationConverter | As defined by DurationFormatUtils |
conf4j configuration types supports generics. It simplifies creating configurations which shares same behaviour.
Following example demonstrates how to use generics to create a base configuration type ValidatorConfiguration
with simple properties name, enabled and customizable property constraints.
@AbstractConfiguration
@Key
public interface ValidatorConfiguration<C> {
String getName();
boolean isEnabled();
C getConstraints();
}
public interface IntegerValidatorConfiguration extends ValidatorConfiguration<IntegerConstraints> {
}
public interface IntegerConstraints {
Integer getMin();
Integer getMax();
}
public interface StringValidatorConfiguration extends ValidatorConfiguration<StringConstraints> {
}
public interface StringConstraints {
Pattern getPattern();
}
Because ValidatorConfiguration
serves as a template (actual sub-configuration type is not known), it has been marked as
an abstract using @AbstractConfiguration
annotation.
There are two concrete configurations IntegerValidatorConfiguration
and StringValidatorConfiguration
which extends ValidatorConfiguration
and specifies the constraint type.
Generics can be used not only for sub-configurations properties but for value properties too.
MinMax
abstract configuration type (see example below) has two min and max properties of generic type T.
IntegerConstraint
and SubStringConstraint
extends MinMax
and specifies the type of min and max as Integer.
@AbstractConfiguration
@Key
public interface MinMax<T extends Comparable<T>> {
T getMin();
T getMax();
}
public interface IntegerConstraint extends MinMax<Integer> {
}
public interface StringConstraint extends MinMax<String> {
Pattern getPattern();
}
More unusual generic usages for value properties are also possible.
@AbstractConfiguration
@Key
public interface AbstractExoticConfiguration<K, V> {
List<Map<K, List<V>>> getProperty();
}
public interface SomeConfiguration extends AbstractExoticConfiguration<String, Integer> {
}
conf4j provides out of the box integration with Spring Framework
First of all add dependency to com.sabre.oss.conf4j:conf4j-spring
module to your project.
Maven
<dependency>
<groupId>com.sabre.oss.conf4j</groupId>
<artifactId>conf4j-spring</artifactId>
<version>${conf4j.version}</version>
</dependency>
Gradle
dependencies {
compile "com.sabre.oss.conf4j:conf4j-spring:$conf4jVersion"
}
conf4j supports XML schema-based as well as annotation driven configurations and both types can be used simultaneously.
conf4j provides custom configuration schema http://www.sabre.com/schema/oss/conf4j
which exposes three custom tags:
<conf4j:configure/>
, <conf4j:configuration/>
, <conf4j:converter/>
, <conf4j:converter-decorator/>
and <conf4j:configuration-scan/>
.
<conf4j:configure/>
is used for activating conf4j integration with Spring Framework. It registers several infrastructure
beans (like ConfigurationFactory
, ConfigurationSource
or TypeConverter
) and post processors. Such beans are used
by conf4j for registering configuration types as beans, creating configuration instances and binding the configuration source.
<conf4j:configuration/>
registers in the context a bean for the configuration type.
This tag expects one attribute class
which specifies fully qualified name of the configuration type. It is also
possible to specify the bean name using id
attribute (by default fully qualified class name is used).
<conf4j:configuration
class="com.your.organization.configuration.package.ConnectionConfiguration"/>
<conf4j:converter/>
registers in the context a type converter.
This tag expects one attribute class
which specifies fully qualified name of the converter class. It is also
possible to specify the bean name using id
attribute (by default fully qualified class name is used).
Moreover this tag supports order
attribute, which is XML equivalent of the org.springframework.core.annotation.Order
annotation in Java
based Spring configuration.
<conf4j:converter
class="com.your.organization.configuration.package.CustomConverter"
order="1"/>
<conf4j:converter-decorator/>
registers in the context a decorating converter factory.
Converter decorator is a converter providing high level conversion policy and delegating low level details to
the inner converter. As an example consider converter for arrays. Its responsibility would be adding brackets
and separating elements with commas. Although conversion of each element would be delegated to the inner converter.
This tag allows to specify the bean name using id
attribute. By default, if factory
attribute is provided,
fully qualified factory name is used. Otherwise the bean name will be fully qualified class name with
$Conf4jDecoratingConverterFactory
suffix.
Attribute factory
specifies fully qualified name of of the com.sabre.oss.conf4j.converter.DecoratingConverterFactory
implementation. If it is not provided, com.sabre.oss.conf4j.spring.converter.DefaultDecoratingConverterFactory
with
class
attribute injected will be used.
Attribute class
states fully qualified name of the converter class. This class must provide a constructor with
com.sabre.oss.conf4j.converter.TypeConverter
parameter type.
Moreover this tag supports order
attribute, which is XML equivalent of the org.springframework.core.annotation.Order
annotation in Java based Spring configuration.
<conf4j:converter-decorator
class="com.your.organization.configuration.package.CustomConverterDecorator"
order="2"/>
<conf4j:converter-decorator
factory="com.your.organization.configuration.package.CustomDecoratingConverterFactory"
order="3"/>
<conf4:configuration-scan>
is very similar to <context:component-scan/>
provided by Spring Framework.
It searches for the configuration types in the package (and all its sub-packages) specified by base-package
attribute
and register them as a beans to the context. To make a conf4j configuration type discoverable, it must be
annotated (or meta-annotated) by @Component
annotation provided by Spring Framework. There also an option
use your own annotation (or annotations), just specify it by configuration-annotations
attribute.
<conf4j:configuration-scan
base-package="com.your.organization.configuration.package"
configuration-annotations="com.your.organization.ConfigurationAnnotation"/>
<conf4:configuration-scan>
supports filtering via include-filter
and exclude-filter
elements exactly the same way
as <context:component-scan/>
.
The example below shows how to use <conf4j:configure/>
and <conf4:configuration-scan>
to activate conf4j
and register all configuration types from com.your.organization.configuration.package in the the context.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:conf4j="http://www.sabre.com/schema/oss/conf4j"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.sabre.com/schema/oss/conf4j http://www.sabre.com/schema/oss/conf4j/conf4j.xsd"
default-lazy-init="true">
<!-- Enable conf4j -->
<conf4j:configure/>
<!-- Find configuration types from the specified package and register in the context. -->
<conf4j:configuration-scan base-package="com.your.organization.configuration.package"/>
</beans>
As mentioned earlier, <conf4j:configure/>
registers several beans with into the context. Each bean has pre-defined
name which starts with com.sabre.oss.conf4j.
prefix.
The bean com.sabre.oss.conf4j.ConfigurationSource
is used for providing configuration values and must implement ConfigurationSource
interface. conf4j registers PropertySourceConfigurationSource
by default. This configuration source integrates with
Environment
and all PropertySourcesPlaceholderConfigurer
s registered in the context
(e.g. by <context:property-placeholder .../>
or @PropertySource
).
If you would like to provide your own implementation of ConfigurationSource
(e.g. to fetch configuration values
from the database) just declare own bean or an alias with com.sabre.oss.conf4j.ConfigurationSource
name.
<bean id="com.sabre.oss.conf4j.ConfigurationSource"
class="com.your.organization.CustomConfigurationSource">
<!-- ... -->
</bean>
In general, all conf4j specific bean can be overridden this way.
The bean com.sabre.oss.conf4j.typeConverter
is used for converting string representation of the values to appropriate type.
By default conf4j registers converter provided by DefaultTypeConverters.getDefaultTypeConverter()
. This converter
is able to convert all primitive types (and they object counterparts), enumerations any combination of List and Map
e.g. Map<String, List<Integer>>
.
The bean com.sabre.oss.conf4j.configurationFactory
is used for creating configuration instances. conf4j registers
JavassistDynamicConfigurationFactory
or, if its not on the classpath, it fallbacks to CglibDynamicConfigurationFactory
.
jaavssist based implementation is preferred because it has significantly better performance. But if you don't like
an additional dependency on the classpath, CGLIB based implementation is used (to be precise, repackaged CGLIB version
available with Spring Framework is used).
JavassistDynamicConfigurationFactory
(and its static counterpart JavassistStaticConfigurationFactory
) implementation
is provided in the com.sabre.oss.conf4j:conf4j-javassist
module. If you would like to use it instead of
CglibDynamicConfigurationFactory
, make this dependency is included in your project.
Maven
<dependency>
<groupId>com.sabre.oss.conf4j</groupId>
<artifactId>conf4j-javassist</artifactId>
<version>${conf4j.version}</version>
</dependency>
Gradle
dependencies {
compile "com.sabre.oss.conf4j:conf4j-javassist:$conf4jVersion"
}
conf4j provides the following annotations which can be used with Spring Framework and Spring Boot:
@EnableConf4j
, @ConfigurationScan
, @ConfigurationType
.
The @EnableConf4j
enables conf4j integration and works as <conf4j:configure/>
tag.
The @ConfigurationScan
scans for the configuration types and its functionality is very similar to <conf4j:configuration-scan>
tag.
The @ConfigurationType
registers in the context a bean for the configuration type and its functionality is very similar to <conf4j:configuration>
tag.
conf4j annotations can be used in Spring Framework configurations classes, i.e. classes annotated or meta-annotated with @Configuration
.
The following example shows how to use @ConfigurationScan
to find all configuration classes in the package (and sub-packages).
@Configuration
@EnableConf4j
@ConfigurationScan(basePackageClasses = ConnectionConfiguration.class)
public class SampleConfiguration {
}
@Component
public interface ConnectionConfiguration {
String getUrl();
// ...
}
If you prefer explicitly listing the configuration types use @ConfigurationType
as shown below. In such case using
@Component
is redundant and can be skipped.
@Configuration
@EnableConf4j
@ConfigurationType(ConnectionConfiguration.class)
@ConfigurationType(UserConfiguration.class)
public class SampleConfiguration {
}
public interface ConnectionConfiguration {
String getUrl();
// ...
}
public interface UserConfiguration {
String getLogin();
// ...
}
conf4j integrates with Spring Boot via auto-configuration mechanism based on org.springframework.boot.autoconfigure.EnableAutoConfiguration
.
To activate it, just add dependency to com.sabre.oss.conf4j:conf4j-spring-boot
module:
Maven
<dependency>
<groupId>com.sabre.oss.conf4j</groupId>
<artifactId>conf4j-spring-boot</artifactId>
<version>${conf4j.version}</version>
</dependency>
Gradle
dependencies {
compile "com.sabre.oss.conf4j:conf4j-spring-boot:$conf4jVersion"
}
Spring Boot finds conf4j during the bootstrap phase and activates it - there is no need to use @EnableConf4j
nor <conf4j:configure/>
anymore.
@SpringBootApplication
@ConfigurationScan
@PropertySource("classpath:application.properties")
public class SimpleBootApplication implements CommandLineRunner {
@Autowired
private ConnectionConfiguration connectionConfiguration;
public static void main(String[] args) {
SpringApplication.run(SimpleBootApplication.class, args);
}
@Override
public void run(String... args) {
System.out.println("url: " + connectionConfiguration.getUrl());
//...
}
@Component
@Key("connection")
public interface ConnectionConfiguration {
String getUrl();
// ...
}
}
If you want to use javassist based configuration factories, don't forget to add dependency to com.sabre.oss.conf4j:conf4j-javassist
.
The modules grouped under conf4j-extras provides integration with additional frameworks and data formats, for example YAML.
conf4j-extras-yaml module provides integration with YAML format.
In order to use it, just add a dependency to com.sabre.oss.conf4j:conf4j-extras-yaml
module.
Maven
<dependency>
<groupId>com.sabre.oss.conf4j</groupId>
<artifactId>conf4j-extras-yaml</artifactId>
<version>${conf4j.version}</version>
</dependency>
Gradle
dependencies {
compile "com.sabre.oss.conf4j:conf4j-extras-yaml:$conf4jVersion"
}
com.sabre.oss.conf4j.yaml.converter.YamlConverter
is capable of converting POJO from/to YAML document.
By default, this converter can be applied only to the properties which have converter meta-attribute value set to yaml.
For conveniences, this attribute can assigned with com.sabre.oss.conf4j.yaml.converter.Yaml
annotation
(as shown below), but you can use regular @Meta
as well.
public interface YamlConfiguration {
@Yaml
ComplexType getComplexType();
}
Note: The class converted by YamlConverter
must be compliant with
JavaBeans specification.
com.sabre.oss.conf4j.yaml.source.YamlConfigurationSource
supports reading
configuration values from YAML document. Because YAML can be hierarchical
it must be flattened to key and value set.
For example:
users:
admin:
name: John Smith
age: 30
country: USA
jane:
name: Jane Doe
age: 25
country: PL
is flattened to:
users.admin.name=John Smith
users.admin.age=30
users.admin.country=USA
users.jane.name=Jane Doe
users.jane.age=25
users.jane.country=PL
and:
continents:
- Asia
- Africa
- North America
- South America
- Antarctica
- Europe
- Australia
is flattened to:
continents[0]=Asia
continents[1]=Africa
continents[2]=North America
continents[3]=South America
continents[4]=Antarctica
continents[5]=Europe
continents[6]=Australia
conf4j-extras-json module provides integration with JSON format.
In order to use it, just add a dependency to com.sabre.oss.conf4j:conf4j-extras-json
module.
Maven
<dependency>
<groupId>com.sabre.oss.conf4j</groupId>
<artifactId>conf4j-extras-json</artifactId>
<version>${conf4j.version}</version>
</dependency>
Gradle
dependencies {
compile "com.sabre.oss.conf4j:conf4j-extras-json:$conf4jVersion"
}
com.sabre.oss.conf4j.json.converter.JsonConverter
is capable of converting POJO from/to JSON document.
By default, this converter can be applied only to the properties which have converter meta-attribute value set to json.
For conveniences, this attribute can assigned with com.sabre.oss.conf4j.json.converter.Json
annotation
(as shown below), but you can use regular @Meta
as well.
public interface JsonConfiguration {
@Json
ComplexType getComplexType();
}
com.sabre.oss.conf4j.json.source.JsonConfigurationSource
supports reading
configuration values from JSON document. Because JSON can be hierarchical
it must be flattened to key and value set.
For example:
{
"teams": {
"ferrari": {
"engine": "ferrari",
"score": 522,
"private": false
},
"williams": {
"engine": "mercedes",
"score": 83,
"private": true
}
}
}
is flattened to:
teams.ferrari.engine=ferrari
teams.ferrari.score=522
teams.ferrari.private=false
teams.williams.engine=mercedes
teams.williams.score=83
teams.williams.private=true
and:
{
"months": {
"odd": [
"January",
"March",
"May",
"July",
"August",
"October",
"December"
],
"even": [
"April",
"June",
"September",
"November"
],
"both": "February"
}
}
is flattened to:
months.odd[0]=January
months.odd[1]=March
months.odd[2]=May
months.odd[3]=July
months.odd[4]=August
months.odd[5]=October
months.odd[6]=December
months.even[0]=April
months.even[1]=June
months.even[2]=September
months.even[3]=November
months.both=February
conf4j-extras-jaxb module provides integration with XML format, using JAXB library.
In order to use it, just add a dependency to com.sabre.oss.conf4j:conf4j-extras-jaxb
module.
Maven
<dependency>
<groupId>com.sabre.oss.conf4j</groupId>
<artifactId>conf4j-extras-jaxb</artifactId>
<version>${conf4j.version}</version>
</dependency>
Gradle
dependencies {
compile "com.sabre.oss.conf4j:conf4j-extras-jaxb:$conf4jVersion"
}
com.sabre.oss.conf4j.yaml.converter.JaxbConverter
is capable of converting POJO from/to XML document.
The class converted by JaxbConverter
must be annotated with @XmlRootElement
, for example:
@XmlRootElement(name = "book")
public class Book {
private String name;
private String author;
public String getName() {
return name;
}
public void setName(String name){
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author){
this.author = author;
}
}