2.0.0

  • Custom ListParsers on @Coat.Config annotation are now correctly applied to that class only. Previously they influenced all other classes, too.

  • A new default converter for URIs is provided by Coat.

  • The runtime performance of calling the accessor methods of the config object has been massively improved by executing all validation and type conversion at creation time of the config object.

  • BREAKING CHANGE: The publicly visible generated class in now not the concrete implementation of the config interface anymore, but instead the builder to create it. The actual implementation is now hidden. To create an instance of the builder an new static Builder#create() method is provided.

  • BREAKING CHANGE: The name of the generated builder class can be specified as was the case with the generated implementation before. But the special handling of a leading underscore has been removed.

  • BREAKING CHANGE: Validation is now always done on creating the config object via builder. Therefore no separate validate method will be available anymore. That also means that the ConfigValidationException will be thrown on calling the build() method of the builder or one of the static factory methods.

  • BREAKING CHANGE: Custom global converters and list parsers are not registered on the config implementation anymore, but instead on the Coat class that also provides the annotations.

  • BREAKING CHANGE: The MessageDigestConverter that was provided by default before has been dropped. As it is a stateful object it is not thread-safe and therefore doesn’t fit the Coat concept. Of course it can still be provided by the application itself if the missing thread-safety is of no concern. It just isn’t provided by default anymore.

  • The example app now uses a List instead of an array as arrays are always mutable and should be avoided in Coat config classes.

Migration guide

While the list above is mainly comprised of breaking changes, they are all very straight forward and migration from an older version of Coat is rather easy. The static factory methods of the previously generated config class are provided by the builder now.

For example a using the static factory methods before was:

1final ImmutableMyConfig config= ImmutableMyConfig.from(new File("/path/to/config.properties"));
2
3CoatConfig.registerConverter(new MyCustomConverter());
4
5try {
6  config.validate();
7} catch (ConfigValidationException ex) {
8  
9}

and now becomes:

1Coat.registerGlobalConverter(new MyCustomConverter());
2
3try {
4  final MyConfig config= MyConfigBuilder.from(new File("/path/to/config.properties"));
5} catch (ConfigValidationException ex) {
6  
7}

Using the builder before was:

1final ImmutableMyConfig config= ImmutableMyConfig.builder().add(props).addEnvVars().build();
2
3try {
4  config.validate();
5} catch (ConfigValidationException ex) {
6  
7}

and now becomes:

1try {
2  final MyConfig config= MyConfigBuilder.create().add(props).addEnvVars().build();
3} catch (ConfigValidationException ex) {
4  
5}