Module org.refcodes.properties
Package org.refcodes.properties
What is this package for?
This artifact provides means to read configuration data from various different locations such as properties from JAR files, file system files or remote HTTP addresses or GIT repositories.Jump start
import static org.refcodes.properties.PropertiesSugar.*; // ... public class Foo { public void bar() throws IOException, ParseException { // ... PropertiesBuilder theProperties = fromProperties( toProperty( "message", "Hello world!" ), toProperty( "foo", "bar" ) ); fileToTomlProperties( theProperties, "application.toml" ); // ... Properties thePrecedence = toPrecedence( fromSystemProperties(), fromEnvironmentVariables(), seekFromTomlProperties( "application.toml" ) ); FooConfig theConfig = thePrecedence.toType( FooConfig.class ); // ... } // ... public static class FooConfig { String message; int frequency; TemperatureUnit unit; int port; } // ... }See also the blog post Dead simple Java application configuration.
How do I get set up?
To get up and running, include the following dependency (without the three dots "...") in yourpom.xml
:
<dependencies>
...
<dependency>
<artifactId>refcodes-properties</artifactId>
<groupId>org.refcodes</groupId>
<version>1.1.9</version>
</dependency>
...
</dependencies>
The artifact is hosted directly at
Maven Central. Jump
straight to the source codes at Bitbucket. Read the
artifact's javadoc at javadoc.io.
If you also want to observe your properties (e.g. listen for
create
, update
or delete
operations),
you may instead add the following dependency to your pom.xml
:
<dependencies>
...
<dependency>
<artifactId>refcodes-properties-ext-observer</artifactId>
<groupId>org.refcodes</groupId>
<version>1.1.9</version>
</dependency>
...
</dependencies>
The artifact is hosted directly at
Maven Central. Jump
straight to the source codes at Bitbucket. Read
the artifact's javadoc at javadoc.io.
How do I get started?
Use the *static import* syntactic sugar to easily harness therefcoces-configuration
features.
import static org.refcodes.properties.PropertiesSugar.*; // ...Create some
properties
and play around with them:
// ... PropertiesBuilder theProperties = fromProperties( toProperty( "/user/firstName", "Nolan" ), toProperty( "/user/lastName", "Bushnell" ), toProperty( "/commodore/user/firstName", "Jack" ), toProperty( "/commodore/user/lastName", "Tramiel" ) ); // ...The content of your
properties
looks as follows:
/user/firstName=Nolan /user/lastName=Bushnell /commodore/user/lastName=Tramiel /commodore/user/firstName=JackThe
Properties.PropertiesBuilder
inherits
from the Map
interface, it is fully compatible with the
Java collections framework
.
You may have noted that the keys
in your properties
look like path
declarations. This is no coincidence, you can now
manipulate your properties
using (sub-)paths
. See
more in the article The
canonical model, an ace upon your sleeve. E.g. you may now retrieve the
commodore
specific properties (the properties
below
the /commodore
path):
// ... Properties theCommodoreProperties = theProperties.retrieveFrom( "/commodore" ); // ...This results in your
commodore
specific properties
to look as such:
/user/lastName=Tramiel /user/firstName=JackThere are many more features hidden in the
Properties
type, just browse the Javadoc. The
Properties
type is the read-only
super-type of the
Properties.PropertiesBuilder
type. Common
functionality produces Properties
instances
which easily can be converted into a mutable
Properties.PropertiesBuilder
instance as
follows:
// ... PropertiesBuilder theBuilder = toPropertiesBuilder( theCommodoreProperties ); // ...
Storing properties
Considering the example from above, storingproperties
is as easy as this:
// ... ResourcePropertiesBuilder theResourceProperties = saveToTomlProperties( theProperties, "/some/path/to/my/properties.toml" ); // ...You can make the
library
choose a suitable place for you where
to save your properties
to; being near the launcher
(JAR
) of your application:
// ... ResourcePropertiesBuilder theResourceProperties = fileToTomlProperties( theProperties, "properties.toml" ); // ...See the
RuntimeUtility
on how a suitable
location is determines by the library
.
Loading properties
Considering the example from above, loadingproperties
back again is as easy as this:
// ... ResourcePropertiesBuilder theResourceProperties = loadFromTomlProperties( "/some/path/to/my/properties.toml" ): // ...You can make the
library
seek for a suitable
properties
for you to load; being near the launcher
(JAR
) of your application:
// ... ResourcePropertiesBuilder theResourceProperties = seekFromTomlProperties( "properties.toml" ); // ...See the
RuntimeUtility
on how a suitable
location is determines by the library
.
Properties parsers
There are some notations being supported by therefcodes-properties
artifact:
Java
based propertiesTOML
based propertiesXML
based propertiesYAML
based propertiesJSON
based properties
Profiles from properties
Aprofile
is identified by the
first level path hierarchy in your originating properties
. In
the example above, commodore
represents a profile specific
configuration which we can use to get our profile
view:
// ... Properties theProfile = fromProfile( theProperties, "commodore" ); // ...We can also specify a
property
in our properties
for the path /runtime/profiles
identifying the
profiles
to be considered (comma separated). See also the
ProfilePropertiesProjection
type as well as
the ProfilePropertiesDecorator
type on more
usages.
Schedule reloading of properties
Using theResourceProperties.ResourcePropertiesBuilder
form above which we attached to a file, we now can schedule a *reload* of the
properties
:
// ... ResourceProperties theScheduled = schedule( theResourceProperties, 5000, ReloadMode.ORPHAN_REMOVAL ); // ...We actually encapsulate the
properties
with a *schedule*
decorator
which reloads the encapsulated properties
accordingly: Reload
them each 5000
milliseconds and remove any
properties
not found in the attached resource (e.g.
File
) from your properties
instance.
Observe properties
You may also listen to anycreate
,
update
or delete
changes applied to your
properties. To do so, you must encapsulate your
ResourceProperties.ResourcePropertiesBuilder
instance with an observable
decorator
of type ObservableResourcePropertiesBuilder
This observable
fires a sub-type of the PropertyEvent
upon updates applied to the properties
to each subscriber of
those events
:
import static org.refcodes.properties.ext.observer.ObservablePropertiesSugar.*;
// ...
PropertiesBuilder theProperties = toPropertiesBuilder();
ObservablePropertiesBuilder theObservable = observe( theProperties );
theObservable.subscribeObserver( aEvent -> {
if ( aEvent.getAction() == PropertyAction.PROPERTY_UPDATED ) {
System.out.println( aEvent.getClass().getSimpleName() + " (" + aEvent.getAction() + ") --> " + aEvent.getKey() + " := " + aEvent.getValue() );
}
} );
theObservable.put( "/user/firstName", "Nolan" );
theObservable.put( "/user/lastName", "Bushnell" );
theObservable.put( "/user/firstName", "Jack" );
theObservable.put( "/user/lastName", "Tramiel" );
theObservable.remove( "/user/firstName" );
theObservable.remove( "/user/lastName" );
// ...
For the example above to work, make sure to include the
refcodes-properties-ext-observer
dependency (see at the beginning of this article) in your project's
pom.xml
. The lambda
being subscribed acts as a
listener
which is a FunctionalInterface
of
type PropertiesObserver
with which you explicitly may listen to the three event types PropertyCreatedEvent
,
PropertyUpdatedEvent
and PropertyDeletedEvent
as well as to the super-type [PropertyEvent
].
Observing just the PropertyEvent
type *catches* all of its sub-types (as we did in the example above).
Multiple properties precedence
We can combine multipleProperties
instances behind a
composite behaving just
like a Properties
type:
// ... Properties theProperties = toPrecedence( fromSystemProperties(), fromEnvironmentVariables(), seekFromJavaProperties( "application.config" ) ); // ...Above we created a composite containing various various
properties
instances, the first one overrules
the second one and the second one overrules the third one when accessing the
resulting Properties
composite. Take a look
at the SystemProperties
as well as at the
EnvironmentProperties
instances we added:
They provide means to access Java
's system properties
or the operating system
's environment variables
within your properties
..
Under the hood
Thecanonical model
pattern is an ace up your sleeve in order to open your libraries for
functionality otherwise to be implemented in a tiresome, error prone and
redundant way. As you settle upon a canonical model
within your library, your library's will be able to interact with any
existing and yet to be implemented functionality on top of your
canonical model
,
making your bits and pieces work together magically. The
CanonicalMap
is the super-type of the
Properties
related types. Read more in the
blog post The
canonical model, an ace upon your sleeve.
Examples
For examples and usage, please take a look at the accordingUnit-Tests
.
For examples and usage on the observable extensions, please take a look at
the according Unit-Tests
.-
Interface Summary Interface Description ProfileProperties TheProfileProperties
extend theProperties
with Runtime-Profiles support.ProfileProperties.MutableProfileProperties The Interface MutableProfileProperties.ProfileProperties.ProfilePropertiesBuilder The Interface ProfilePropertiesBuilder.Properties TheProperties
are a specialization of theDictionary
.Properties.MutableProperties The interfaceProperties.MutableProperties
defines "dirty" methods allowing to modify ("mutate") the properties.Properties.PropertiesBuilder The interfaceProperties.PropertiesBuilder
defines builder functionality on top of the properties .PropertiesAccessor Provides an accessor for aProperties
property.PropertiesAccessor.PropertiesBuilder<B extends PropertiesAccessor.PropertiesBuilder<B>> Provides a builder method for aProperties
property returning the builder for applying multiple build operations.PropertiesAccessor.PropertiesMutator Provides a mutator for aProperties
property.PropertiesAccessor.PropertiesProperty Provides aProperties
property.PropertiesNotationAccessor Provides an accessor for aPropertiesNotation
property.PropertiesNotationAccessor.PropertiesNotationBuilder<B extends PropertiesNotationAccessor.PropertiesNotationBuilder<B>> Provides a builder method for aPropertiesNotation
property returning the builder for applying multiple build operations.PropertiesNotationAccessor.PropertiesNotationMutator Provides a mutator for aPropertiesNotation
property.PropertiesNotationAccessor.PropertiesNotationProperty Provides aPropertiesNotation
property.PropertiesPrecedence Defines a meta-interface in order to retrieve properties from various different properties sources (Properties
instances) by querying all the herein containedProperties
instances in the order of them being added.PropertiesPrecedence.MutablePropertiesPrecedence The interfacePropertiesPrecedence.MutablePropertiesPrecedence
defines "dirty" methods allowing to modify ("mutate") thePropertiesPrecedence
: Add or removeProperties
inside aPropertiesPrecedence
instance.PropertiesPrecedence.PropertiesPrecedenceBuilder The interfacePropertiesPrecedence.MutablePropertiesPrecedence
defines builder functionality on top of the properties .ResourceLoaderMixin<B extends ResourceLoaderMixin<B>> This interface provides builder additions (as of the builder pattern for chained configuring method calls) for "dynamic"ResourceProperties
: AsResourceProperties
are immutable from an interface's point of view, there are no mutating methods provided.ResourceProperties TheResourceProperties
are a specialization of theDictionary
.ResourceProperties.MutableResoureProperties The interfaceResourceProperties.MutableResoureProperties
defines "dirty" methods allowing to modify ("mutate") theResourceProperties
.ResourceProperties.ResourcePropertiesBuilder The interfaceResourceProperties.ResourcePropertiesBuilder
defines builder functionality on top of theResourceProperties.MutableResoureProperties
.ResourcePropertiesFactory Factory interface for creatingResourceProperties
instances.ResourcePropertiesFactory.ResourcePropertiesBuilderFactory Factory interface for creatingResourceProperties.ResourcePropertiesBuilder
instances.ScheduledResourceProperties TheScheduledResourceProperties
enrichResourceProperties
with scheduling functionality whereby the properties are being automatically reloaded periodically viaResourceProperties.reload(ReloadMode)
.ScheduledResourceProperties.ScheduledMuableResourceProperties The interfaceScheduledResourceProperties.ScheduledMuableResourceProperties
defines "dirty" methods allowing to modify ("mutate") theScheduledResourceProperties
.ScheduledResourceProperties.ScheduledResourcePropertiesBuilder The interfaceScheduledResourceProperties.ScheduledResourcePropertiesBuilder
defines builder functionality on top of theScheduledResourceProperties.ScheduledMuableResourceProperties
.StrictProperties TheStrictProperties
extends theProperties
with all the getters to throw aKeyNotFoundRuntimeException
instead of returning null in case the key was not found.StrictProperties.MutableStrictProperties The Interface MutableStrictProperties.StrictProperties.StrictPropertiesBuilder The Interface StrictPropertiesBuilder. -
Enum Summary Enum Description PropertiesNotation The currently known notations forResourceProperties
implementations.PropertiesPath Enumeration representing defined path values.ReloadMode Mode of operation regarding theResourceProperties.reload(ReloadMode)
method. -
Exception Summary Exception Description ConfigurationRuntimeException Base exception for the configuration artifact.