Supported Types
Builtin types
The following types are supported by Coat out of the box and can directly be used as return types of the accessor methods in the annotated interface.
- java.lang.Integer
- java.lang.Long
- java.lang.Float
- java.lang.Double
- java.lang.String
- java.time.Duration
- java.time.LocalDate
- java.time.LocalDateTime
- java.time.LocalTime
- java.io.File
- java.nio.file.Path
- java.nio.charset.Charset
- java.net.InetAddress
- java.net.URI
For each supported type a converter class exists in the package
de.poiu.coat.convert.converters
. Refer to the corresponding
Java API docs
for details about the expected format of the input string.
The following primitive types are also supported by default. But those are different in that they are directly supported without any Converter.
int
Integer values can be specified in decimal (no prefix), hexadecimal (prefixed by
0x
), octal (prefixed by0
) or binary (prefixed by0b
) form.long
Long values can be specified in decimal (no prefix), hexadecimal (prefixed by
0x
), octal (prefixed by0
) or binary (prefixed by0b
) form.double
Double values can be specified in decimal (no prefix) or hexadecimal (prefixed by
0x
) form.For decimal values an optional exponent can be appended, in which case it must be separated with
e
orE
, like1.0e5
. For hexadecimal values the exponent is mandatory and must be separated withp
orP
, like0xaaP5
. In either case the exponent can optionally be signed (e. g.1.0e+5
).boolean
The strings “true" and “yes” (regardless of their case) are considered as
Boolean.TRUE
, all other Strings (including null) are considered to beBoolean.FALSE
.
Be aware that numeric types (int, long, double) do not allow the
specification of a type suffix (l
for long, d
for double, etc.) as
would be valid in a Java literal numeric value.
However, underscores for separating parts of a number (like 1_000_000
) are
supported.
Registering custom types
Coat allows registering custom types to be used in the annotated interface.
A static method Coat#registerGlobalConverter()
is provided to register
a converter for a specific type. To do this, the interface
de.poiu.coat.convert.Converter
must be implemented for that specific type and
registered with the above mentioned method.
The Coat#registerGlobalConverter()
method must be called before creating
a config object using such a type.
The Coat#registerGlobalConverter()
method can additionally be used for overriding
the builtin converter for a type. For example if durations should be
specified in some other format than the default converter supports, write a
custom converter for the java.time.Duration
type and register it via
1Coat.registerGlobalConverter(new MyDurationConverter());
As support for primitive types is directly implemented and not via
Converter it is currently not possible to override the parsing of primitive
types with a custom Converter. If different parsing of such types is
necessary the corresponding object type must be used and a Converter for
that type be written (e. g. a Converter<Integer>
).
Additionally to the above mentioned method of registering custom converters at runtime, they can also be specified declaratively on the corresponding annotations. See the description of these annotation parameters on the type and on the field level annotations for more information.
Currently unsupported types
At the moment the primitive types short
, float
, char
and byte
are not supported. Therefore the next “bigger” types must be used (e. g.
int
instead of short
) or the corresponding class (e. g. Short
instead
of short
).
Collection types
Since version 0.0.4 Coat supports Arrays and collections as return values of accessor methods.
- Arrays
- java.util.List
- java.util.Set
Arrays are only supported for object types, not primitive types. Be aware that Arrays are by nature mutable. For that reason Lists should be preferred instead.
By default the values of collection types are expected to be separated by
whitespace. Whitespace inside a single value can be used by prefixing each
such whitespace character with a backslash. For example the value one\ two three
would then be split into a collection with the two values one two
and
three
.
Additionally, since version 1.0.0 a CommaSeparatedListParser is provided for splitting around commas (ignoring any whitespace around the commas). It will not be used by default and must be explicitly declared as a custom ListParser.
Default values are supported for arrays and collections as well.
1@Coat.Config
2public AppConfig {
3 @Coat.Param(defaultValue = "UTF-8 US-ASCII")
4 public Charset[] allowedCharsets();
5}
Registering custom ListParser
Coat allows for different formats than the default whitespace separated values
by registering a custom ListParser. Each generated config class provides
a static method registerListParser()
to register a custom parser for such
values. Additionally such a ListParser can be declared on the
@Coat.Config annotation as well as on the @Coat.Param annotation.
A custom ListParser must implement the de.poiu.coat.convert.ListParser
interface.
Optional values
Config entries that are optional must be encapsulated in java.util.Optional
or the more specialized variants OptionalInt
, OptionalLong
or
OptionalDouble
need to be used. All other config values are considered
mandatory. Missing mandatory values will throw an exception at validation time.
Embedded types may be optional, too. They are considered present if at least one config entry with the corresponding key and separator was found. In that case all mandatory values of the embedded config must be present.
Optional collections are not supported out of the box. The generation will succeed, but no converter will be found at runtime. Most of the time an optional collection does not make much sense and an empty collection should be returned in case no value is specified. Optional collections may be supported by providing a custom converter for that specific collection, for example:
1public class IntListConverter implements Converter<List<Integer>> {
2 private final IntegerConverter ic= new IntegerConverter();
3
4 @Override
5 public List<Integer> convert(final String stringValue) throws TypeConversionException {
6 final String[] splitString= stringValue.split("\\s+");
7 final List<Integer> result= new ArrayList(splitString.length);
8 for (final String s : splitString) {
9 result.add(ic.convert(s));
10 }
11
12 return result;
13 }
14}