Skip to content

Latest commit

 

History

History
321 lines (231 loc) · 10.8 KB

README.md

File metadata and controls

321 lines (231 loc) · 10.8 KB

LinkedIn Apache V2 License Maven Central Run Unit Tests

Property Aggregator Logo

Property Aggregator

Simplify Java property handling and create a single source of truth!

Property Aggregator

This project takes care of various properties sources in Java like system and environment variables as well as properties files. It allows you to specify which sources override others, filter them and give them default values in order to have one single aggregated source of application properties.

Changelog

All changes can be seen in the linked changelog.

Maven dependency

<dependency>
    <groupId>blog.softwaretester</groupId>
    <artifactId>property-aggregator</artifactId>
    <version>Check the version number above</version>
</dependency>

Usage

General usage

Building a PropertyAggregator

The Property Aggregator uses a simple builder pattern to specify property sources and options.

PropertyAggregator propertyAggregator =
    new PropertyAggregator.Builder(true)
    .withEnvironmentProperties()
    .withPropertiesFile("path/to/Test1.properties")
    .build();

The boolean parameter inside Builder() determines if logs should be shown or not. The false option can be useful if the PropertyAggregator should be a "silent part" of another library.

In this case,

  1. environment properties (aka environment variables) are loaded first
  2. a Test1.properties file is loaded which overrides existing properties from the step before

You can specify multiple sources like this in any order to create your custom property hierarchies.

When the final build() method is called, all property sources are combined, filters are applied and default values are set.

Retrieving properties

To query for certain properties, use it as shown below:

propertyAggregator.getProperty("property1")

Specifying property sources

System properties

To use system properties as a property source, use the withSystemProperties() option:

PropertyAggregator propertyAggregator =
    new PropertyAggregator.Builder(true)
    .withSystemProperties()
    .build();

Environment variables

To use environment properties as a property source, use the withEnvironmentProperties() option:

PropertyAggregator propertyAggregator =
    new PropertyAggregator.Builder(true)
    .withEnvironmentProperties()
    .build();

Properties files

Properties file in a fixed path

To use a properties file as a property source, use the withPropertiesFile() option:

PropertyAggregator propertyAggregator = 
    new PropertyAggregator.Builder(true)
    .withPropertiesFile("path/to/custom.properties")
    .build();

Properties file in the application's class path

If the properties file can be anywhere inside the application's class path, use this method to retrieve them:

PropertyAggregator propertyAggregator = 
    new PropertyAggregator.Builder(true)
    .withPropertiesFileInClassPath(pathToProperties)
    .build();

Specifying property hierarchies

The power of Property Aggregator is the ability to specify which properties have a higher order than others.

This enables hierarchies such as:

  1. the application's standard property file application.properties
  2. this can be overwritten with system properties
  3. this can be overwritten with environment properties.

This example would look like this in code:

PropertyAggregator propertyAggregator =
    new PropertyAggregator.Builder(true)
    .withPropertiesFile("path/to/application.properties")
    .withSystemProperties()
    .withEnvironmentProperties()
    .build();

If properties do not exist in a higher source but only in a lower one, the lower one is added to the final properties. That means that higher sources overwrite properties that already exist in a lower one.

Querying properties

To retrieve a property value by key, just use

String propertyValue =
    propertyAggregator.getProperty("propertyKey"));

This returns the property value from the final processed and filtered set of properties or an appropriate default value if it exists. Otherwise, the return value will be null.

Filtering property keys during the build

Especially when using environment properties, they can be quite large and not all of them may be relevant for your application. It is possible to add a filter in this case to remove all properties whose keys are not required.

List<String> filteredKeys =
    List.of("property1", "property2");

PropertyAggregator propertyAggregator =
    new PropertyAggregator.Builder(true)
    .withEnvironmentProperties()
    .withFilteredKeys(filteredKeys)
    .build();

Here, all environment properties that are not called "property1" or "property2" are stripped out of the PropertyAggregator instance.

Note: The filter is applied when the final build() is called on the PropertyAggregator builder. That means that it is applied after all property sources are combined.

Specifying custom filters during the build

If you want to permanently filter properties in the final list based on custom predicates, you can do it like this:

Predicate<? super Map.Entry<String, String>> myAppFilter =
        (Predicate<Map.Entry<String, String>>) entry ->
                entry.getKey().startsWith("myApp");

PropertyAggregator propertyAggregator = new PropertyAggregator.Builder(true)
        .withPropertiesFile(RESOURCES_DIR + "application.properties")
        .withCustomPredicate(myAppFilter)
        .build();

This example permanently alters the property list and only keep properties whose key starts with "myApp".

Note: It is possible to use withCustomPredicate multiple times.

Retrieving subsets of properties from the final list

It is possible to get subsets of properties that match custom predicates. One use case for this is having different sets of properties that have to be passed on to application plugins.

Predicate<? super Map.Entry<String, String>> filterXProperties =
    (Predicate<Map.Entry<String, String>>) entry ->
        entry.getKey().startsWith("X");

Properties properties =
        propertyAggregator.getPropertiesWithCustomPredicate(filterXProperties);

This example would return properties that have keys starting with the letter "X".

Setting default values

Setting default values can be beneficial if certain properties must exist and can optionally be overwritten.

Map<String, String> defaults =
    Map.of("property1", "default1");

PropertyAggregator propertyAggregator =
    new PropertyAggregator.Builder(true)
    .withDefaultValues(defaults)
    .withPropertiesFile("path/to/application.properties")
    .build();

Here, the key "property1" is set with a default value of "default1". If any of the property sources (in this example a properties file) does not include "property1", it is added to the final list of properties with the default value. If, however, "property1" is specified in a property source, the default value is replaced by the actual value.

Note: If you use defaults and filters together, properties with default values are added to the final set regardless of filters!

Logging the final properties

If you want to check the properties after all applied operations, you can log all properties like this:

propertyAggregator.logFinalProperties();

Note: These logs are always shown regardless of the log settings of the builder!

Checking the size of the final properties

In order to get the size of processed properties including properties that are only specified via default values, use

propertyAggregator.getPropertiesCount()

Retrieving all properties

This method returns all processed property keys and values that are set by property sources or defaults and are not filtered out:

propertyAggregator.getAllProperties()

Appendix

Building

Property Aggregator requires Java >= 11 and Maven >= 3.3.9.

It is available in Maven central.

License

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.