There is a common requirement in most of the Java/JavaEE projects related to how to differentiate environment configurations like development, test, QA, production, etc. for that reason there are a lot of frameworks or libraries to resolve that:
- DeltaSpike Configuration
- Apache Commons Configuration
- Sabot
- Apache Tamaya
- Dropwizard Configuration
- Jackson Dataformat YAML
Even there is a Java Specification Request (JSR) Proposal:
How those libraries resolve the problem
Most of those libraries require to have an injection point(s) for the configurations and also the source of the configuration(s), something like this:
dev.properties:
host=localhost port=5432 schema=public prod.properties:
host=production.com port=5432 schema=public ConfigurationResolver.java:
class ConfigurationResolver implements SomeLibraryInterface { @Override public String resolvePropertyFilename() { // probably do some trick to load a global/base configuration // if is not provided for the library return String.format("%s.properties", System.getProperty("MY_ENV", "dev")); } } MyType.java:
class MyType { @Configuration(key = "host") String host; @Configuration(key = "port") int port; @Configuration(key = "schema", defaultValue = "public") String schema; } Notice that all the granularity is only needed because of lack of support for custom types
Besides that, with the new Java 8 capabilities, specifically with default methods and some utility classes are easy to get this behavior.
With Java 8 default methods
DefaultConfiguration.java:
interface DefaultConfiguration { default DataSource datasource { // create the DS with host, port and schema return new MyDataSource("localhost", 5432, "public"); } } DevConfiguration.java:
class DevConfiguration implements DefaultConfiguration { // No need to override methods if they are the same } ProdConfiguration:
class ProdConfiguration implements DefaultConfiguration { default DataSource datasource { return new MyDataSource("production.com", 5432, "public"); } } ConfigurationFactory.java:
abstract class ConfigurationFactory { private static final Map<String, DefaultConfiguration> configurations = new HashMap<>(); static { configurations.put("development", new DevConfiguration()); configurations.put("production", new ProdConfiguration()); } public static DefaultConfiguration configuration() { return configurations.getOrDefault(System.getProperty("MY_ENV"), new DevConfiguration()); } } Notice that you can use an enumeration instead of a map as a configuration factory.
Pros
- Typesafe configurations
- Support for all kinds of types not only
String,Dateor primitives. you can specify or exampleDataSource,TimeUnits,JedisPool, etc. - No conversion/mapping from strings to types
- No more
.properties,.xmlor.ymlfiles - Possibility to use other sources to fill the properties like properties files, database, rest API's, etc.
- No library/framework/dependency required in your app
Cons
- Changes in the configuration require to compile/deploy (this shouldn’t be a problem in the 99% of the cases)
Top comments (0)