Skip to main content

Configuration Objects: using JAXB instead of java.util.Properties

Posted by felipegaucho on October 26, 2007 at 3:11 AM PDT

Configurable features is a common requisite of computer systems,
and the Java API provides the utility class java.util.Properties
to facilitate our lives. It is very simple to use, and it is suitable
for the most part of applications, but it also has some limitations -
more precisely when we consider the configuration data:

  1. How to check if all key/values are really present in the
    properties file?
  2. How to check if the type of the values are consistent with the
    types required by the application?
  3. How to represent complex types (nested properties)? For
    example: I have a property that is a set of properties.
  4. How to represent values that are not Java primitive types?

Special remind: properties loading using the java API just reads
the key/values pair in the memory , it doesn't check its consistency or
any data structure related to the configuration. And more: unfortunately
the Properties class is locked in the old Properties DTD and it doesn't
support nested structures or complex types. It also provides a XML
validation mechanism, but it is really too simple to be useful in more
complex scenarios - like the one I present below.

A real world example where java.util.Properties
seems not to be enough

My need for a better Properties loading mechanism started when I
coded the Footprint
project
- Footprint is a signed PDF generator that requires three
distinct set of Properties:

  1. The JDBC Driver Properties: required by href='http://java.sun.com/j2se/1.4.2/docs/api/java/sql/DriverManager.html#getConnection(java.lang.String,%20java.util.Properties)'>java.sql.DriverManager#getConnection
  2. A mapping between the name of the fields in the PDF template
    and the name of the column names in the database.
  3. The general properties used to configure the system (number of
    threads, resources directories, etc.).

My prime code was based on three different files, and I also
thought of creating a unique properties file referring the other ones or
adopting some pre-defined prefixes/sufixes in order to identify the
different set of properties - like jdbc.prop1=value. After
some analysis it became clear my system required a more sophisticated
configuration mechanism than a collection of key/value pairs of strings.
It requires nested structures and better yet if it can have validation
of its configuration data. Natural conclusion: these requirements can be
easily achieved with an XML file. After deciding to use XML, I evaluated
some options, including different XML frameworks and also the usage of
XML with the Java API. I also checked the new features of JAXB 2.0, and
the fact it is already distributed with the JRE 1.6 convinced me that
JAXB is a first class configuration binder. The figure below summarizes
my observations about property files versus XML:

Option #1: several Properties Option #2: XML file converted in Configuration
Object
through JAXB
footprop.jpg footjaxb.jpg
  • Good:
    1. Plain text file
    2. Easy visualization of key/values pairs
    3. Simple code for reading the properties
    4. Default Java API - required classes are distributed as part
      of JRE (since 1.2)
  • Bad:
    1. Several files to manage
    2. Weak validation of files structure and contents
    3. Text editors or IDEs don't help to identify problems
    4. String + primitive types representation only
    5. Error prone - it is very hard to visualize missing data
    6. Custom binder - it requires a custom code to convert String
      values in Java Objects
    7. Inclusion of new key/pair on demand - hard to control the
      mess in big teams
  • Good:
    1. Plain text file
    2. Only 1 file to manage
    3. Configuration data defined in a model
    4. Validation support by default using the XML Schema
    5. Configuration versioning
    6. Data types and values range configurable in the model
    7. Any Java type supported
    8. Default Java API - required classes are distributed as part
      of JRE (since 1.6)
    9. Full support from IDEs in editing time (highlight,
      validation and auto-complete)
    10. Missing data never happens
    11. Automatic binding between the configuration values in Java
      Objects
    12. Inclusion of new properties depends on model changing -
      more easy to control the mess in big teams - just keep the model
      locked ;)
  • Bad:
    1. Difficulty in visualizing the information
    2. Any new configuration value impacts in a model changing

Implemented solution: binding XML properties to Configuration
Object
through JAXB 2.0

The full source code I used to implement my JAXB based properties
mechanism is available at the href='https://footprint.dev.java.net/source/browse/footprint/trunk/footprint-core/src/net/java/dev/footprint/xml/'>Footprint
SVN repository - including the href='https://footprint.dev.java.net/source/browse/*checkout*/footprint/tags/footprint-07.10.23/footprint-core/build.xml?rev=259'>ANT
task required to create the XML<->Object binder using XJC. I strongly
recommend you to download the footprint source code and try it a bit
before checking my conclusions at the end of this blog. Inspecting the
code you will start seeing how clean is the application regarding to its
configuration properties. I don't have hard-coded String representing
the configuration acronyms, and I don't need to verify if the values in
the properties are consistent with the values required by the code, it
is implicit since we are calling the methods of the Configuration
Object
that are homonymous to the properties names. Other comfortable
feature: if I modify the XML schema or try to change the code in a way
both sides become inconsistent, the IDE will notify the problem,
avoiding me to crash my own code - the code will not compile before the
classes and the properties model become consistent to each other, even
under that stressful deadline :)

First step: you first need to create a href='https://footprint.dev.java.net/files/documents/7027/68644/footprint.xsd'>XML
Schema, and then use an ANT task to generate the XML<->Object
binder classes, like the one below:

	<taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
<classpath refid="classpath.base" />
</taskdef>

<target name="compileschema">
<echo message="Compiling the Curriculum XML Schema..." />
<mkdir dir="${jaxb.classes.dir}" />
<xjc schema="${schema}" extension="true"
classpath="${build.dir.classes}" target="${generated.dir}"
package="${jaxb.bindingclasses.package}">
<produces dir="${jaxb.classes.dir}" includes="**/*.java" />
</xjc>
<javac srcdir="${generated.dir}" destdir="${generated.dir}"
debug="off" source="1.5" />
<jar destfile="lib/footprint-config.jar" basedir="${generated.dir}"
excludes="**/*.java" />
<delete dir="${generated.dir}" />
</target>

Before discussing the pros and cons of the JAXB adoption, let me
show some code fragments. What we need to do is to load and to use the
configuration properties, what is quite easy with the newest version of
JAXB. The validation of the XML against its schema is automatic, but I
can also implement a finer verification of the properties data using the
Event Callbacks mechanism provided by JAXB.

  1. A code for reading the XML properties file:
    	@SuppressWarnings("unchecked")
    public JAXBElement read(InputStreamReader inputStream)
    throws Exception {
    JAXBContext jc = JAXBContext.newInstance(
    AbstractJaxbFootprintStream.FOOTPRINT_CONTEXT, this.getClass()
    .getClassLoader());

    Unmarshaller unmarshaller = jc.createUnmarshaller();
    unmarshaller.setEventHandler(new FootprintConfigValidationHandler());
    unmarshaller.setListener(listener);
    SchemaFactory sf = SchemaFactory
    .newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Schema schema = sf.newSchema(getClass().getClassLoader().getResource(
    AbstractJaxbFootprintStream.SCHEMA_FILE));
    unmarshaller.setSchema(schema);

    JAXBElement footprintProperties = (JAXBElement) unmarshaller
    .unmarshal(inputStream);
    return footprintProperties;
    // That's it! From this point I have a Java Object I use to retrieve the configuration values
    }
  2. After binding the properties to Java Object, I can manipulate
    its attributes as any other class:
    	private void DemoMethod(FootprintProperties properties) {
    ConfigEmail email = config.getEmail();
    setMsgFrom(email.getMsgFrom()); // GOODBYE hard-coded strings like prop.get(" color='red'>msg.from");
    }
  3. An optional href='http://java.sun.com/webservices/docs/2.0/api/javax/xml/bind/Unmarshaller.html#unmarshalEventCallback'>Unmarshal
    Event Callbacks, to check what is being read. Observe in the code below
    that I can inspect every element of my configuration, which means I can
    stop the application loading if I detect something inconsistent. I am
    using this listener also to log what is being loaded. And since I have
    a model, I know what any fragment of my configuration file is
    about and I can do extra verification on the config values. Eventually
    I can also modify the created Object based on custom requirements.
    	@Override
    public void afterUnmarshal(Object target, Object parent) {
    if (target instanceof ConfigEmail) {
    validateEmailData((ConfigEmail) target);
    }
    ...
    }

    // Observe I don't need to check if the [prettify]msgTo
    attribute is present or not // in my property file, the model guarantee that. private void validateEmailData(ConfigEmail email) { String msgFrom = email.getMsgFrom(); Pattern p = Pattern.compile(".+@.+\\.[a-z]+"); Matcher m = p.matcher(msgFrom); boolean matchFound = m.matches(); if (!matchFound) { severe(FootprintConfigUnmarshallerListener.I18N_KEY_EMAIL_MALLFORMED, new String[] { msgFrom }); } }[/prettify]

Conclusions

The implemented code works fine, and despite I didn't stressed
too much the tests, I have some observations:

  1. The loading performance is good, since a regular configuration
    file is never more than hundreds of values.
  2. Memory impact: large sets of configuration can cause an
    explosion of Objects in the memory, and that is a good thing to keep in
    mind: each element of the XML will instantiate a different Object.
  3. The complexity of the reading/writing algorithm is similar do
    the one required by the java.util.Properties, and after
    creating it once you can reuse it later.
  4. The validation and verification of the configuration data are
    sound and robust processes - much more elegant and safe than using
    properties files.
  5. Open the configuration example XML in your preferred IDE, and
    you will notice the helpful support available there, including
    highlight and auto-complete features.
  6. Think about the natural match between the XML structure and
    the beans editors code out there. It is quite easy to create a GUI that
    presents to the user a tree with all configuration elements and its
    respective editors. I started a href='https://footprint.dev.java.net/source/browse/footprint/trunk/footprint-demo/'>Swing
    prototype here, but it is still a pending task. Eventually I will use
    the NetBeans platform, that gives me a wonderful beans editor support,
    or even try JavaFX to produce the configuration editor GUI.

A polemic topic is about the large amount of Objects loaded in
memory, what is controversial if you consider what happens when you load
values using java.util.Properties. The properties are
loaded as Strings, what in the worst case means one String object to
each value. Even considering Strings are lightweight objects compared to
complex types, all Strings will be used to instantiate an Object at some
part of your code. One can suggest JAXB is much heavier since it loads
all objects at once, while properties being used by demand will rarely
cause all objects being loaded together. I agree in terms, but I think
JAXB provides a better productivity - reducing the chances of mistakes
and facilitating the verification of the configuration and the code.
Imagine a developer using auto-complete for loading the properties,
instead of checking constants somewhere or including weird hard-coded
String all over the code. It is up to you to think about that.

My overall feeling about using JAXB instead of Properties is very
good, I am feeling much more confident to code based on Objects than
based on collection of Strings. At the end, both approaches are quite
similar in terms of logic, but since I am an Object Oriented developer,
I prefer to manipulate objects than lists of values - the old fashion
procedural approach.


Related Topics >>