Few months ago I’ve started my journey with Play Framework and Akka. I loved their configuration syntax, the HOCON – Human-Optimized Config Object Notation.
If you don’t know what I’am
talking writing about, you have to follow these links below to see what the word “awesome” means 😉
I want to show you how easily HOCON can be adopted into your (JVM-based) projects.
Set up your project
This step will be indecently straightforward since everything you need to do is just ensure that appropriate JAR is present in the application’s class path. No matter what programming language are you using – Java, Scala, Groovy, yet another or maybe all of them.
If you are using Maven or SBT just add following dependency:
Before We start..
Say hello to com.typesafe.config.Config interface which provides API for obtaining values (or even whole nested documents as a Config instance) for given path.
You can find more (up-to-date) informations in the Config’s JavaDoc.
You will be working almost only with this single interface, so I it’s recommended to read this JavaDoc. It is short and you will get comprehension about differences between Config vs ConfigObject, Keys vs Paths and immutability aspects.
It’s absolutely must-read if you want to know not only how to use library but also how it works and how do they did it.
Let’s create our first Config instance!
You can get Config instance using the com.typesafe.config.ConfigFactory, a dedicated factory.
The simplest way to start with Typesafe’s Config is to place application.conf containing JSON/HOCON configurations and load them using:
You can find a lot of other methods in the ConfigFactory’s documentation.
Don’t omit description of the ConfigFactory.load() method – it provides useful informations about customizing config location on deployment environment (in a nutshell – using ConfigFactory.load() invocation you can set appropriate property and let Config to load contents from given URL or a file with specified path) or how to get a fresh configuration (instead of the cached one).
Examples source code
All of examples will be presented in Scala (because of conicise syntax).
If you aren’t familiar with Scala you can find these examples written in Java at my github repository -> https://github.com/mkubala/typesafe-config-examples.
I encourage you to cloning/forking my repo, modifying the code and having fun 😉
All of my examples uses the same HOCON file as a configuration source:
First, Let’s try to read some values:
Pretty simple, isn’t it?
As you may already noticed my cofiguration has tree-like structure.
You can easily extract only a particular bunch of branches (node with its children) to the new Config object:
When it may be useful? Consider following use-case:
We want to allow further application’s administrator to define some set of predefined users.
We’ve defined UserObject which will be Config consumer:
We also provide some sample configuration:
The rest is pretty simple:
- extract a list of nested user Configs (using .getConfigList(“path”))
- pass them with the UserObject’s constructor, transforming (mapping) list from step #1 into a collection of UserObjects
You can also compose many Config instances into a fallback chain:
It will be useful when you want to provide some default values which will be open for overriding and closed for modification.
Iterating over paths and values
Here is how I kill two birds with one stone – I get a rid of all unnecessary values outside a specific path (“my.organization”), iterate throught each of Config’s entries and extract the keys.
Method .withOnlyPath(..) used at the above example will clone the config, retaining only the given path (and its children) – all sibling paths will be removed.
Use Config.atPath(..) If you want to preserve siblings.
There’s also similar method – Config.atPath(..) which places the config inside another Config at the given path, preserving siblings:
The section’s title doesn’t need explanation, so let’s look at the examples:
Hey, what happened at line #5 – substitution expresions weren’t re-evaluated after replacing value! To be honest – I have no idea how to make it working.. Yet 😉
It’s worth to mention that you can override values using env variables.
Try to run examples with -Dmy.organization.project.description=”overriden by env” and see what happens 😉
You can find more examples at the Config’s repository, right here.
Now it’s time for the missing part of the official Config’s examples – document generation and rendering.
We have seen before how to load/create new Config objects using ConfigFactory.load, Config.atPath, Config.withOnlyPath, Config.getConfig and Config.getConfigList.
But how to create a Config from scratch?
You can use ConfigFactory.empty() factory method which returns an empty Config.
When you’ll be going to fill them using Config.withValue(..), you have to keep in mind that Config is immutable! This means that each invocation of withValue(..) produces a new Config instead of modifying object on which you invoke it.
I’m a bit hungry so the next example will be course-related. It represents pseudo-recipe for one of my favourite dish:
Rendering Config as a HOCON
Ok, let’s try to produce a valid HOCON document (as a String) representing previously created recipe:
Note: If you omit the .setJson(false) invocation, you will get a JSON document as an output, instead of HOCON.
Typesafe Config is a simple and powerful tool. It supports not only the HOCON but also Java properties and JSON as an input.
There is still few useful features not covered in this blog post.
You can find them, well described, at the official documentation (for example config validation).
Please feel free to share your reflections about library or this note.
English isn’t my native language therefore I’ll be grateful for any feedback about my grammar and/or vocabulary.