AndHow Properties
90% of using AndHow is creating and using Properties
AndHow Properties are immutable constants in your code, except their value is loaded when your application starts up. They are always static final
and created with a builder() method:
Properties may be private
or public
, but they must be static final
and the compiler will enforce that. Getting the value of a Property is simple:
Properties are strongly typed (so IntProp
returns an Integer
) and there are Property types for most primitive types - see the next section.
Properties can...
be declared anywhere in code that a
static final
variable can be declared. They do not need to be centralized into a configuration class. Best pactice is to declare them where you use them.have constraints such as
greaterThan(5)
(for a numeric type) ormatches("regex expression")
(for a String), etc.have configuration values loaded into them during application startup from a number of configuration sources - see the Loaders.
be null if no value if found for the property at startup, or may have a default value
Property Types
AndHow has Properties to represent most common value types:
StrProp - String Property
BolProp - Boolean Property
IntProp - Integer Property
LngProp - Long Property
DblProp - Double Property
BigDecProp - BigDecimal Property
LocalDateTimeProp - LocalDateTime Property
FlagProp - boolean Property (never null) that acts as a command line switch
All Property types basically behave the same way:
They parse the configured values they receive during application startup into the appropriate type.
If no configuration value is found, their value is null unless a default is specified.
If the value cannot be parsed to the appropriate type or does not meet the validation requirements defined in the Property declaration, the application startup is stopped with a runtime exception.
One exception to this general behavior is the FlagProp
. The FlagProp behaves similar to an on/off switch, thus it is never null and always returns true
or false
from getValue()
. Additionally, the FlagProp behaves like a 'nix flag when used on the command line - see the example in the StdMainStringArgsLoader.
Property value access and security
Property.getValue()
is the only way to get a Property's value (other than exports), so the visibility of the Property controls access:
If code can see/access a Property, it can read its value
If code cannot see/access a Property, it cannot read its value
Reflection can bypass visibility (except non-open modules in JDK 9+) and code can read environment vars and other sources, but many other configuration solutions result in all configuration being effectively public. AndHow Properties let you scope configuration to the classes that need it.
Properties and their values are immutable
During initialization, AndHow will automatically load Property values from multiple configuration sources. Once complete, Property values will not change for the run-life of the application.
Property Names
Properties always have a unique canonical name based on their logical path. A Property named MY_PROP
declared in the com.bigcorp.MyClass
has the canonical name com.bigcorp.MyClass.MY_PROP
. The same pattern continues with nested inner classes or interfaces.
Property names are case-insensitive, so com.bigcorp.MyClass.MY_PROP
is the same as COM.BiGcOrP.MyClaSS.my_prOP
.
Best Practice: Don't worry about Property names unless you have to
Canonical Properties names are often good enough and will implicitly update when refactoring.
Properties may have In and Out aliases. In aliases are recognized when loading values, in addition to canonical names. Out aliases are alternate names that can be used when exporting. Properties may have multiple In and Out aliases:
When AndHow loads values, CODE
's canonical name, pin and secret_pin will be recognized. If values are exported (such as to a Map to configure another framework), the canonical name, secret and secret_pin will all be names that could be used.
In aliases are useful for Properties that need to be specified from command line, or to match an already existing set of configuration files / sources. Out aliases are useful for exporting to other frameworks or legacy applications that expect specific key names.
Default Values
All Properties can have default values:
...But be careful! Its easy for a default value to end up in production. Some Properties have good defaults: report margin, retry counts or log level. Others do not: DB connection string, user name or password. If a Property has no value that is acceptable in all environments, its better to not specify a default and rely on configuration to supply the value.
Best Practice: Use a default value when there is a good business-related default
Don't use a default value for local workstation or test environment configuration values.
As you will see in the testing section, its easy to use separate test configurations. Its also easy to provide local and tier specific configuration (TDB: Write this section).
Properties have lots of configuration options
Properties can have validation, description, defaults, and more. Rather than attempt to describe them all, see the examples below.
Properties behave like static finals except...
AndHow Properties work like static final variables whose value is assigned at startup. This is true in amost all situations except one: A Property's getValue()
method cannot be called inside a static initializer block. Doing so will cause a startup error that AndHow will tell you about.
Groups
A Group is just the AndHow term for the class or interface containing Properties. Some AndHow operations and annotations apply to Groups, as you will see in the examples below.
Property Example 1
Properties and Groups can have description to help make code self-documenting. AndHow uses all the Property metadata to generate rich configuration templates for your Properties, as in the 2nd tab. The template serves as both documentation and an initial configuration file, and is created when startup fails due to validation error, or it can be run manually by setting the built-in org.yarnandtail.andhow.Options.CREATE_SAMPLES
to true, e.g.:
-D
sets a Java system property and AHForceCreateSamples
is an In alias for CREATE_SAMPLES
, as you can see at the bottom of the configuration template. It is also a 'flag' property (FlagProp
), so just being present is enough to set it true, similar to other command line switches.
The 3rd tab shows example error messages for invalid configuration values. These informative messages would be part of a RuntimeException
, thrown to prevent startup with invalid configuration.
Property Example 2
Just like constants, Properties can (and should) be declared where they are be used to create natural scope: If a secret is only needed by one class, don't make it visible to the entire application. Avoid placing Properties in a central 'Config' class.
Best Practice: Declare properties in the class or interface where they are used
Place related sets of Properties in nested interfaces.
The Properties in the example above configure a Report class, and related Properties have been nested into interfaces. This creates logical, canonical names for Properties: The purpose of ZIP is easy to understand when it's inside Report.Filter.
Nesting into interfaces also takes advantage of the Java language to save some typing: Variables declared in an interface are implicitly static final
. (Note: Java 11+ is required to use a private interface as in the example)
Last updated
Was this helpful?