Arkenv v3.2.0 - available on maven central

New repository, new features, and a look at how we got here

  1. Background
  2. New repository
  3. New features
    1. Plain class support
      1. Constructor injection
      2. Modules
    2. New feature syntax
  4. Breaking changes
  5. Further information

I am happy to announce that we have migrated from JCenter to Maven Central, and are releasing version 3.2.0 with new features, including plain class support and constructor injection. Before we dive into the news, I want to take a look back at how we got here.

Throughout its lifetime, Arkenv has offered many great learning opportunities, and having the chance to create such a project is something I wish upon every developer.

Even though it is in no way a complex, or groundbreaking venture, I still consider it an important stepping stone, being my first open-source library. Keeping the scope small and manageable is probably an advantage when starting out.

Background

There were two primary reasons for the conception of Arkenv.

Firstly, we were looking for a way to seamlessly bridge the changing configuration needs in different environments with minimal developer intervention. Starting out with command line libraries like JCommander, we soon realized that we wanted a central abstraction to define our external configuration, which didn’t depend on the configuration source. Pretty much like Environment in Spring.

For example, we wanted to be able to go from a command line-driven environment to an environment variable-driven one without having to add code or recompile.

Secondly, I really wanted to try to build something with Kotlin delegates. Another issue we had with many existing, annotation-based libraries, was the lack of type-safety and null support. Quickly, we saw that delegates were a perfect fit for these criteria, and the first version with CLI and ENV support didn’t fill more than a few lines.

The idea was to declare an immutable property, with nullability indicating whether it is optional or not, and whose name is used to resolve it.

val port: Int by argument()

Once declared, it can be provided via CLI --port 443, environment variable PORT=443, or in a profile (properties, yaml) port: 443.

Later on we added support for other sources, like .env files and Docker secrets.

New repository

With the announcement of JCenter ending support of their popular repository, many open-source projects had to migrate to Maven Central. We could have lived without this interruption, but on the other hand, it is great to be able to go with the default repository.

From now on, all new releases will be available here.

repositories {
    mavenCentral()
}

implementation("com.apurebase", "arkenv", "3.2.0")
implementation("com.apurebase", "arkenv-yaml", "3.2.0") // for yaml support

New features

Plain class support

It is no longer necessary to extend Arkenv when defining an argument class.

object Configuration {
    val port: Int by argument()
}

Arkenv.parse(Arguments, args)

Plain classes do not have a help argument by default.

Constructor injection

Instead of declaring arguments, one can now let Arkenv inject directly into the constructor of a plain class.

class Configuration(val port: Int)

// construct an instance with the parse factory function
val configuration = Arkenv.parse<Configuration>(args)

Consequently, we cannot apply any config to these arguments, but default values are supported natively.

Modules

The above approaches can be combined freely, and both support modules, too. In plain classes, modules are declared with a delegate, i.e. by module(). The module delegate function also accepts a configuration lambda with prefix support.

class SubConfig(val country: String) {
    val port: Int by argument()
}

object  Configuration {
    val subModule by module<SubConfig>()
}

Arkenv.parse(Configuration, args)
Configuration.subModule.port // member access

The above SubConfig class accepts constructor parameters and declares arguments in its body.

The Configuration object declares a module that is automatically created on parse.

New feature syntax

Features can now be configured with + and -.

val configuration = Arkenv.parse<Configuration>(args) {
    +ProfileFeature(prefix = "app")
}

Breaking changes

Most extension functions have moved to the util package. This will break your build when upgrading, but should be easy to fix, by importing the correct packages.

//import com.apurebase.arkenv.parse
import com.apurebase.arkenv.util.parse

Further information

Log any bugs or feature requests on Github.

📃 Please visit https://apurebase.gitlab.io/arkenv/ for in-depth documentation.

🤝 Ask any questions in the Arkenv channel in the official Kotlin Slack.


© 2023. All rights reserved.