Built-in converters
Ravel provides converters (priority 1) for these types, automatically applied during config.getValue() and config.getOptionalValue():
| Type | Behavior |
|---|---|
|
Pass-through (no conversion) |
|
Truthy values: |
|
Via |
|
Via |
|
Via |
|
Via |
|
Via |
|
Converts the value to |
|
ISO-8601 format: |
|
ISO-8601 format: |
|
ISO format: |
|
ISO format: |
|
ISO format: |
|
ISO format: |
|
ISO format: |
|
ISO format: |
|
ISO format: |
|
Via |
Enum types |
Match by enum constant name (case-sensitive) |
|
CSV: comma-separated values, converted to list of |
Arrays
// microprofile-config.properties
app.items=foo,bar,baz
app.ids=1,2,3,4
// Code
String[] items = config.getValue("app.items", String[].class);
// Result: ["foo", "bar", "baz"]
Integer[] ids = config.getValue("app.ids", Integer[].class);
// Result: [1, 2, 3, 4]
Collections
List<String> items = config.getValue("app.items", List.class);
Set<Integer> ids = config.getValue("app.ids", Set.class);
Collection<Duration> timeouts = config.getValue("app.timeouts", Collection.class);
Implicit converters
If a type doesn’t have a built-in converter, Ravel attempts to use an implicit converter (priority 2):
-
Public constructor taking
String:new MyType(string) -
Static method
valueOf(String):MyType.valueOf(string) -
Static method
parse(CharSequence):MyType.parse(charseq)
public class MyDuration {
private final long millis;
// This public constructor enables implicit conversion
public MyDuration(String iso8601) {
this.millis = Duration.parse("PT" + iso8601).toMillis();
}
}
// microprofile-config.properties
app.timeout=1H30M
// Code
MyDuration timeout = config.getValue("app.timeout", MyDuration.class);
// Internally calls: new MyDuration("1H30M")
Custom converters
Register a custom Converter<T> for types not covered by built-in or implicit converters:
import org.eclipse.microprofile.config.spi.Converter;
public class ColorConverter implements Converter<Color> {
@Override
public Color convert(String value) {
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException("Color cannot be empty");
}
if (value.startsWith("#")) {
// Hex format: #RRGGBB
return Color.decode(value);
} else if (value.equalsIgnoreCase("red")) {
return Color.RED;
} else if (value.equalsIgnoreCase("green")) {
return Color.GREEN;
} else if (value.equalsIgnoreCase("blue")) {
return Color.BLUE;
}
throw new IllegalArgumentException("Unknown color: " + value);
}
}
Converter priority
When resolving a type, Ravel applies converters in this order:
-
Built-in converters (priority 1)
-
Implicit converters (priority 2)
-
Custom converters via ServiceLoader (priority >= 3)
-
Converters from
ConfigBuilder.withConverter()(highest priority)
The first converter that claims to handle the type is used. If none match, IllegalArgumentException is thrown.
Example: JSON converter
public class JsonConverter<T> implements Converter<T> {
private final ObjectMapper mapper;
private final Class<T> targetType;
public JsonConverter(Class<T> type) {
this.targetType = type;
this.mapper = new ObjectMapper(); // or your serialization library
}
@Override
public T convert(String value) {
try {
return mapper.readValue(value, targetType);
} catch (Exception e) {
throw new IllegalArgumentException("Invalid JSON for " + targetType.getName(), e);
}
}
}
// Usage
MyConfigClass config = configProvider.getConfig()
.getValue("app.config.json", MyConfigClass.class);
Next
-
Property Expressions — reference other configuration values
-
CDI Integration — inject converted values via
@ConfigProperty