As developers we do not want to hard code values in our source code.

int iterations = 42;

Static analyzers, like Checkstyle tell us that we should not use magic numbers.

'42' is a magic number.

And defining these values as constants does help to appease the static analyzer, but the value is still hard coded.

public static final int DEFAULT_ITERATIONS = 42; 
public void method() {
  int iterations = DEFAULT_ITERATIONS;
  ...
}

For a Java developer, any change to the value requires to recompile the sources. And not only the source code with the declaration of the constant, but every source file that references this constant. Changing the value of a public constant is usually a bad idea. So the constant is not a property, since it should not be changed at development time and cannot be changed during runtime.

Happy Hacking with Properties

To work around this, a Java developer may use Properties. So here is the quickhack:

public void method() throws IOException, NumberFormatException {
  final Properties properties = loadProperties();
  final int iterations = readAsInt(properties, "defaultIterations");
  ...
}
 
public Properties loadProperties() throws IOException {
  final Properties properties = new Properties();
  final InputStream input = 
       getClass().getResourceAsStream("app.properties");
  if (input != null) {
    try (final BufferedInputStream bin = 
                       new BufferedInputStream(input)) {
      properties.load(bin);
    }
  }
  return properties;
}
 
private int readAsInt(final Properties properties, final String key)
  throws NumberFormatException {
  final String stringValue = properties.getProperty(key);
  if (stringValue != null) {
    final int intValue = Integer.parseInt(stringValue);
    return intValue;
  }
  return 0;
}

Additionally a properties file named app.properties is supplied within the classpath of the project to make this code work.

So why is this a quickhack?

  1. The properties file is part of the classpath. Therefore the code does not have to be recompiled, but repackaged. The problem is that in this example the configuration is shipped with your code. You can easily work around this, if you provide your configuration in its own JAR. This is easily overlooked, since many Java Standards demand that the configuration is packaged with the code (e.g. te web.xml in a WAR file).
  2. The properties are easily managed by the developer, who edits the value and saves it to the source code management system. This is a pretty good idea, since this way the property value changes can be tracked and different versions of configuration can be compared. But configuration values are not so easily edited by the operations team that has to open the properties file from within JAR file with their text editors. It depends on your use case, if this is a problem.
  3. The property may be changed during runtime in the in-memory representation of the properties, but it may be challenge to persist such a change.
  4. You find no error handling in this code. What if the property or the whole properties file is missing? Is it ok to return 0 as default?
  5. Bad traceability: in case the property value is not an integer, an exception is raised. Further work should be invested to tell which property has a wrong type of value. What is missing is a proper value conversion. And in the code above there is just the conversion to integer. What about the other primitive types? What about URIs or even more complex types?
  6. But even if the value can be parsed as an integer, there may be constraints on the value. Is a negative value for an iteration count really allowed? What is missing is a proper validation of the value.
  7. Where is the validation code put? Crafting it manually requires some form of integration pattern, maybe boilder plate code. If you are implementing a business function, you surely do not want to bother with such basic tasks.
  8. This code has to be tested. On the bottom line code and configuration is the same. A configuration is an externalized, configurable piece of code.
  9. A configuration file is part of the public interface. We mentioned above, that values passed in have to be converted and validated. What is still missing is a documentation that tells users of the system which values are allowed and what default values are provided. It should also tell which properties are mandatory and which optional. Which are read only and which can be changed at runtime. And there is even more metadata. This documentation has to be kept in sync with the implementation. The number of iterations may be limited to a maximum number in future.
  10. And in the end we added another magic value: The name of the property. This has to be added as a constant as we cannot add the key to a properties file. So again it needs to be decided where these property keys should be defined.
  11. A developer should not bother with the administration of properties. Neither where to put them, nor how to load them. Handling properties is an architectural decision. There should be a documented way on how to deal with properties in a given project. Everyone will happily adhere to these rules instead of inventing the wheel over and over again. Not only within a project, but also from project to project.

The Properties class is basically a hashtable with load and store functions. There are certainly use cases for Properties, but for many more use cases this Java class provides too basic support for application developers.

Some Elaboration with Preferences

The Properties class is well known. Less known is the Preferences package. The Preferences class within this package provides some interesting features.

  1. The user of this class does not bother where to pick the property values from. This is handled by an implementation that usually extends AbstractPreferences and is registered via a PreferencesFactory. Java also provides a default implementation (that may or may not suit your needs).
  2. If you need it, there is support for user and system properties.
  3. There is even an event mechanism that allows to register code to be notified of value changes.
  4. Value changes are stored transparently by the implementation.
  5. There is a conversion support for all basic types.


So this class cures some of the problems above, but not all. The developer still has to care for:

  1. Validation
  2. Basic Testing
  3. Key Handling
  4. Documentation
  5. Handling complex types

smartics-properties

If you do not want to invest in providing a technical basis for handling properties in your application, you may have a look at a configuration library. There are many open source versions on the internet. smartics Properties is one of them. Please note that this library is currently in an early version.


Link

Link

Posts

Tagcloud

Loading tagcloud ...