Sunday, April 14, 2013

Environment configuration property injection using Java CDI

In Spring Framework, injecting environment properties is made simple using the context:property-placeholder to configure property file locations and the @Value("#{propKey}") annotation to specify the key of the property.

Java CDI does not have an equivalent out-of-the-box, but it's flexible and rolling your own is easy using a single qualifier and a producer method.

As shown in the code listing above, the Configuration qualifier takes a single parameter, the key of the property that we are trying to inject.

The ConfigurationFactory class is more elaborate. In the @PostConstruct method, we initialize the environment specific property files. How this is done is up to you. In my case, I check for a system property environment.name to identify the deployment environment (assuming that this property is set in all environments). Then I use this value to load the correct environment properties file in the classpath. By default, the bundled environments.properties file is loaded from the classpath.

By example, if the application is deployed to the production environment, then the environment.name will return something like "production", so we will expect to find an "environment_production.properties" in the classpath.

The solution is flexible, and can be set up in many ways.

The limitation of the example above is that there is no automatic reloading of property files. This and many other improvements can be made if we instead leverage the Apache Commons Configuration in our producer method.

4 comments:

  1. What would be the best way to handle different property types, String, Integer, Long, Date etc.

    ReplyDelete
    Replies
    1. The simplest solution is to have a producer method per property type that would convert the property to the appropriate type.

      Alternatively, the producer method would have to convert to the appropriate type based on injectionPoint.getType() property. This will require changing the signature of the producer method to return Object, though I'm not sure this will work.

      Delete
  2. I made a very similar capability as a CDI extension named Pinject (https://github.com/soulwing/pinject). In addition to injecting strings, it has an extensible converter mechanism that supports many common value types. It also supports many different kinds of property resolution.

    ReplyDelete