Externalized Properties has powerful support for conversion of values to various types.
By enabling the default converters, you get out-of-the-box conversion support for:
- Primitives
- Lists / Collections
- Arrays
- Sets
- Enums
- Date/Time types
Externalized Properties automatically attempts to convert resolved properties to the declared proxy method (non-String) return type. The library will handle the conversion behind the scenes - using the registered Converters e.g.
public interface ApplicationProperties {
@ExternalizedProperty("timeout.millis")
int timeoutInMilliseconds();
@ExternalizedProperty("custom.type.property")
CustomType customTypeProperty();
}
public static void main(String[] args) {
ExternalizedProperties externalizedProperties = buildExternalizedProperties();
// Proxied interface.
ApplicationProperties props = externalizedProperties.initialize(ApplicationProperties.class);
// Use properties.
int timeoutInMilliseconds = props.timeoutInMilliseconds();
CustomType customType = props.customTypeProperty();
}
private static ExternalizedProperties buildExternalizedProperties() {
return ExternalizedProperties.builder()
.defaults()
.converters(new CustomTypeConverter())
.build();
}
Externalized Properties has support for generic types e.g.
public interface ApplicationProperties {
@ExternalizedProperty("list-of-numbers")
List<Integer> listOfNumbers();
}
Externalized Properties is capable of converting each item from the list-of-numbers
property to an Integer (provided a converter is registered to convert to an Integer).
An arbitraty generic type parameter depth is supported. For example,
public interface ApplicationProperties {
@ExternalizedProperty("list-of-numbers")
List<Optional<Integer>> listOfOptionalNumbers();
}
Each item in the list will be converted to an Optional<Integer>
.
Externalized Properties has support for conversion of arbitrary String values to other types. This is made possible by the @ConverterFacade annotation e.g.
(Kindly see @ConverterFacade documentation to learn more about the rules of defining a converter facade.)
public interface ProxyInterface {
@ConverterFacade
<T> T convert(String valueToConvert, TypeReference<T> targetType);
@ConverterFacade
<T> T convert(String valueToConvert, Class<T> targetType);
}
Invoking the methods annotated with @ConverterFacade will delegate the arguments to the registered Converters to do the conversion. The converted value will be returned by the method.
There are several built-in converters but it is very easy to create a custom converter by implementing the Converter interface and registering the converter via the ExternalizedProperties builder.
public class MyCustomConverter implements Converter<MyCustomType> {
@Override
public boolean canConvertTo(Class<?> targetType) {
return MyCustomType.class.equals(targetType);
}
@Override
public ConversionResult<MyCustomType> convert(
InvocationContext context,
String valueToConvert,
Type targetType
) {
// There is also a ConversionResult.skip() result to skip this converter and move to the next available one.
return ConversionResult.of(MyCustomType.valueOf(valueToConvert));
}
}
public interface ApplicationProperties {
@ExternalizedProperty("my.property")
MyCustomType myProperty();
}
private static void main(String[] args) {
ExternalizedProperties externalizedProperties = ExternalizedProperties.builder()
// Register custom resolvers here.
.converters(new MyCustomConverter())
.build();
ApplicationProperties props = externalizedProperties.initialize(ApplicationProperties.class);
// Converted using MyCustomConverter.
MyCustomType myProperty = props.myProperty();
}