props

Multi-layered properties and secrets management library, for JAVA.

props

This project aims to provide a library which manages properties and secrets coming from multiple sources (startup properties, environment, property files, etc.)

While props is currently implemented in JAVA, additional languages are planned in the future.

Features

Static code analysis

Quickstart

Add props as a dependency in your project.

<dependency>
  <groupId>com.mihaibojin.props</groupId>
  <artifactId>props-core</artifactId>
  <version>0.0.4</version>
</dependency>

Initialize a registry object which resolves values from the system properties and the environment.

Props props = Props.factory()
                   .withResolver(new SystemPropertyResolver())
                   .withResolver(new EnvResolver())
                   .build();

Create and bind a String property which retrieves the value of file.encoding from the system properties.

Prop<String> aProp = props.prop("file.encoding").build();

String encoding = aProp.value(); // will return an encoding such as UTF-8

Read more to see other features.

The Props registry

To use the library, you first need to initialize a Props registry.

Props props = Props.factory()
                   .withResolver(...)
                   .build();

Once configured, the Props object can:

All the examples below assume you have initialized a Props registry.

Resolvers

Props has a number of predefined resolvers. Support for the following sources is provided out of the box:

Additionally, you may define custom resolvers by implementing the Resolver interface.

The following examples assume you have already configured a Props registry.

Type-safe properties

Props supports multiple types out of the box.

For example, you can load an integer property’s value, without registering a prop with the registry:

Integer maybeValue = props.valueOf("prop.key", Cast.asInteger());

Or if you need to retrieve its value more than once, you can bind it to the registry as follows:

Prop<Integer> aProp = props.prop("prop.key", Cast.asInteger()).build();
Integer maybeValue = aProp.value(); // will return the current value, at calling time

Resolver precedence

If more than one resolver has a value for prop.key, the last one to define it will decide the property’s value.

Props props =
    Props.factory()
        .withResolver(new PropertyFileResolver(...)) // prop.key="one"
        .withResolver(new PropertyFileResolver(...)) // prop.key="two"
        .build();

String maybeValue = props.valueOf("prop.key"); // will return "two"

Configuring resolvers

Sometimes you may require to configure the resolver layers differently, depending on the environment in which the app is running.

For example, you may choose to define the resolvers in a configuration file, and specify the configuration file as an argument:

# /tmp/production.config
system
env
classpath=layer1.properties
file=/tmp/layer2.properties

# Start the app with
javac Main.java && java -DresolverConfig=production.config Main
// Main.java
String confFile = System.getProperty("resolverConfig")
Props props =
    Props.factory()
        .withResolvers(readResolverConfig(Files.newInputStream(Path.of(confFile)))
        .build();

// props will be initialized with the resolvers defined in the config file

Retrieving values from a specific resolver

Properties can be registered with a single resolver. In that case, the registry will disregard all but the configured resolver.

Props props =
    Props.factory()
        .withResolver("MY-ID", new PropertyFileResolver(...)) // prop.key="one"
        .withResolver(new PropertyFileResolver(...)) // prop.key="two"
        .build();

// retrieve a value without binding a Prop to the registry
String maybeValue = props.prop("prop.key").resolver("MY-ID").value(); // will return "one"

No value found

If no value can be found for the specified property, Prop.value() will return null.

String maybeValue = props.valueOf("unknown.prop"); // will return null

Further examples

Further examples are included as part of the examples test suite.

These examples include code samples for the following features:

Javadocs

You can find a copy of the latest Javadocs, here.

Contributing to the project

Please see the contributor guide.

License

Copyright 2020 Mihai Bojin

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.