How to Set the Default Configuration Properties for a Micronaut Library

Micronaut is a very extensible framework which allows you to easily create new libraries. Generally speaking, you can create a set of beans which will be injected into your application and ship them as a separate JAR. The problem may arise when you are also using configurations and you want to preset some default values. There is one recommended way — use default values in the configuration class. If you for any reason can't use this approach I will show you two other approaches — each of them must be used with caution.

Setting Default Values in Configuration Object

Setting default values in the configuration class or interface is the recommended way. If you use plain classes then you can simply set the default value as a default value of the fields.

@ConfigurationProperties("simple.two")
public class SimpleConfigurationTwo {

public String getFoo() {
return foo;
}

public void setFoo(String foo) {
this.foo = foo;
}

public String getBar() {
return bar;
}

public void setBar(String bar) {
this.bar = bar;
}

@NotBlank
private String foo = "FOO2";
private String bar;

}

There is a new option in Micronaut 1.3.x to create immutable configurations using interfaces. In that case, you need to use @Bindable annotation to set the default values.

@ConfigurationProperties("simple.one")
public interface SimpleConfigurationOne {

@NotBlank
@Bindable(defaultValue = "FOO1")
String getFoo();

String getBar();

}

You can override the defaults in your application.yml file:

micronaut:
application:
name: simple-application
simple:
one:
foo: CHANGED_FOO_1
bar: BAR_1
two:
bar: BAR_2

There are certain use cases in which you can’t set the default directly in the configuration class. One of the examples might be if you want to preconfigure a declarative HTTP. Then you have to preset the defaults using some another approach.

Setting Default Values using Custom Property Source

When you create a new Micronaut application then a new file Application is created:

public class Application {

public static void main(String[] args) {
Micronaut.run(Application.class);
}
}

There is usually no need to edit this file. But you can use it to customize the creation of the application context. For example, you can add another PropertySource:

public class Application {

public static void main(String[] args) {
Micronaut.build(args)
.propertySources(PropertySourceConfigurationOne.defaults())
.classes(Application.class)
.start();
}
}

The major drawback with this approach is that there is an additional nonstandard step required. There is a high probability that the library user will forget to configure the property source properly. To be sure that the property source is registered you can create a meaningless property which the only purpose is to guarantee the property source has been set up properly. Here's a complete example of such a configuration object.

@ConfigurationProperties("sources.one")
public interface PropertySourceConfigurationOne {

String getFoo();
String getBar();

/**
* Not used at all.
*
* This is a signal property which verifies
* that the defaults has been set properly.
*
* <code>
* Micronaut.build(args)
* .propertySources(
* PropertySourceConfigurationOne.defaults()
* )
* .classes(Application.class)
* .start();
* </code>
*
*
@return literally "cafebabe"
*/
@NotBlank @MatchesPattern("cafebabe") String getCafebabe();

static PropertySource defaults() {
Map<String, Object> defaults = CollectionUtils.mapOf(
"sources.one.foo", "DEFAULT_FOO",
"sources.one.bar", "DEFAULT_BAR",
"sources.one.cafebabe", "cafebabe"
);
return PropertySource.of(
"property-source-one", // any unique name
defaults, // configuration defaults
-10000 // priority
);
}

}

You can see that configuration property sources.one.cafebabe is only used to verify that the defaults() property source has been applied to the application context. Using any negative number lesser than -1000 should move the property source down the evaluation stack so it will only be evaluated if the property is not specified elsewhere.

Another even tricker approach is to leave application.yml file for library configurations and always use environment-specific files such as application-development.yml or application-production.yml, system properties or environment variables to override the defaults.

Setting Default Values in application.yml Files

The rule of thumb is that you should never create application.yml files in the libraries! When the application is processed by the Shadow JAR Gradle plugin you never know which application.yml file is chosen to be copied into the fat JAR.

The only acceptable (but still not preferred) situation is when you have full control of the library (i.e. internal library) and the application. Then you can merge the application.yml files by altering the Gradle configuration:

shadowJar {
mergeServiceFiles()
// append application.yml files from the libraries
append 'application.yml'
}

You must be also sure that the content of the files is wrapped into --- part separators so each file will create a separate part of the YAML file:

---
merge:
one:
foo: DEFAULT_FOO_1
bar: DEFAULT_BAR_1
---

The biggest drawback is that you will have to always use environment-specific files such as application-development.yml or similar to override the defaults:

---
micronaut:
application:
name: sources-application
merge:
one:
foo: CHANGED_FOO_1
two:
bar: CHANGED_BAR_2
---

In production, you will probably override the configuration properties using environment variables anyway.

--

--

--

Agorapulse is a leading Social Media Management platform. This is our story and feedback from the ground.

Recommended from Medium

Form submission in Django 3

district0x Dev Update - March 17th, 2020

PUBG MOBILE Esports launches Between The Battlegrounds episode 4 Ft. Futbolist and Bigetron

The Next Generation of Cross Browser Testing is Ultrafast

Leading and Lagging Indicators

WeasleyClock

@aurora

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Vladimír Oraný

Vladimír Oraný

Full Stack Developer and Test Facilitator at @agorapulse

More from Medium

Return different type of data with Seald Class in Kotlin

How we handle query parameter breaking changes in Whoz API

Mustache, rendering and localitazion email in Kotlin

KMock — A humble mocking library for Kotlin Multiplatform.