Showing posts with label properties. Show all posts
Showing posts with label properties. Show all posts

Tuesday, January 27, 2009

Java Properties in XML

Java properties have been a staple of Java development for many years. Even today, Java properties are used in popular frameworks and tools such as the Spring Framework and Ant. Most of the Java properties that I have seen used frequently follow the tried-and-true name=value paradigm. However, since J2SE 5, it has been easy to load (and save) properties in XML format.

In my experience, the typical properties file looks something like that shown next.

examples.properties


url.blog.dustin=http://marxsoftware.blogspot.com/
url.javaworld=http://www.javaworld.com/
url.coloradosoftwaresummit=http://www.softwaresummit.com/
url.otn=http://www.oracle.com/technology/index.html
url.rmoug=http://www.rmoug.org/


J2SE 5 made it easy to load properties from XML (and store properties to XML). The Javadoc-based API documentation for the Properties class discusses both formats. This documentation shows the DTD used to define the Properties XML grammar:


<?xml version="1.0" encoding="UTF-8"?>
<!-- DTD for properties -->
<!ELEMENT properties ( comment?, entry* ) >
<!ATTLIST properties version CDATA #FIXED "1.0">
<!ELEMENT comment (#PCDATA) >
<!ELEMENT entry (#PCDATA) >
<!ATTLIST entry key CDATA #REQUIRED>


The DTD shows us that properties stored in XML must have <properties> as the root element required of well-formed XML and can have zero or one <comment> elements nested in this root tag. We also learn from this DTD that zero to many elements name <entry> are allowed and that an entry element may contain a data body and a single attribute named key. Based on this DTD, we could write a compatible XML-based properties file by hand, but an even easier way to see one is to read in a traditional properties file of name/value pairs and store it back out in XML format. This is exactly what the next Java class, PropertiesExamples, does.

PropertiesExamples.java


package dustin.properties;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;

public class PropertiesExamples
{
/** No-arguments constructor. */
public PropertiesExamples() {}

/**
* Get traditional properties in name=value format.
*
* @param filePathAndName Path and name of properties file (without the
* .properties extension).
* @return Properties read in from provided file.
*/
public Properties loadTraditionalProperties(
final String filePathAndName)
{
final Properties properties = new Properties();
try
{
final FileInputStream in = new FileInputStream(filePathAndName);
properties.load(in);
in.close();
}
catch (FileNotFoundException fnfEx)
{
System.err.println("Could not read properties from file " + filePathAndName);
}
catch (IOException ioEx)
{
System.err.println(
"IOException encountered while reading from " + filePathAndName);
}
return properties;
}

/**
* Store provided properties in XML format.
*
* @param sourceProperties Properties to be stored in XML format.
* @param out OutputStream to which to write XML formatted properties.
*/
public void storeXmlProperties(
final Properties sourceProperties,
final OutputStream out)
{
try
{
sourceProperties.storeToXML(out, "This is easy!");
}
catch (IOException ioEx)
{
System.err.println("ERROR trying to store properties in XML!");
}
}

/**
* Store provided properties in XML format to provided file.
*
* @param sourceProperties Properties to be stored in XML format.
* @param pathAndFileName Path and name of file to which XML-formatted
* properties will be written.
*/
public void storeXmlPropertiesToFile(
final Properties sourceProperties,
final String pathAndFileName)
{
try
{
FileOutputStream fos = new FileOutputStream(pathAndFileName);
storeXmlProperties(sourceProperties, fos);
fos.close();
}
catch (FileNotFoundException fnfEx)
{
System.err.println("ERROR writing to " + pathAndFileName);
}
catch (IOException ioEx)
{
System.err.println(
"ERROR trying to write XML properties to file " + pathAndFileName);
}
}

/**
* Runs main examples.
*
* @param arguments Command-line arguments; none anticipated.
*/
public static void main(final String[] arguments)
{
final PropertiesExamples me = new PropertiesExamples();
final Properties inputProperties =
me.loadTraditionalProperties("examples.properties");
me.storeXmlPropertiesToFile(inputProperties, "examples-xml.properties");
}
}


The class shown above reads in the properties file listed earlier and then writes it back out in XML format. The actual lines of code doing most of the work are small in number, but the many checked exceptions associated with file input/output make the code base much larger.

When this code is run, the following output is generated:

examples-xml.properties


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>This is easy!</comment>
<entry key="url.coloradosoftwaresummit">http://www.softwaresummit.com/</entry>
<entry key="url.rmoug">http://www.rmoug.org/</entry>
<entry key="url.blog.dustin">http://marxsoftware.blogspot.com/</entry>
<entry key="url.javaworld">http://www.javaworld.com/</entry>
<entry key="url.otn">http://www.oracle.com/technology/index.html</entry>
</properties>


This generated XML file contains the same name/value pairs as the traditional properties file shown earlier, can be read in like the traditional version using the Properties.loadFromXML, and includes the comment that was passed to the Properties.storeToXML method.

Conclusion

It is fairly straightforward to load properties from XML and to store them as XML. However, the XML is essentially limited to the same paradigm of name/value pairs as traditional properties files. Therefore, we are unable to take advantage of XML's hierarchical nature to use relationships more complex than one key (name) to one value. The primary reason one might use Java's support for XML-based properties is if XML was being used for other tools or frameworks and the properties in XML were more accessible to the other tool or framework.

Friday, April 11, 2008

Properties in Spring: PropertyPlaceholderConfigurer and PropertyOverrideConfigurer

The Spring Framework's PropertyPlaceholderConfigurer and PropertyOverrideConfigurer make using Java .properties files with Spring easy. In this blog entry, I'll use a simple example to demonstrate these two classes that enable configuration of Spring via .properties files.

The first code listing is a simple Java class that will be exposed by Spring and will have its attributes set based on Java properties files.


package dustin;

/**
* Simple Java class that will be exposed as a Spring bean and configured via
* properties files.
*/
public class SpringPropertiesHandlingExample implements SpringPropertiesHandlingIf
{
private String valueFromConfigurer;
private String valueFromOverrider;

public SpringPropertiesHandlingExample()
{
}

public String getValueFromConfigurer()
{
return this.valueFromConfigurer;
}

public void setValueFromConfigurer(final String valueFromConfigurer)
{
this.valueFromConfigurer = valueFromConfigurer;
}

public String getValueFromOverrider()
{
return this.valueFromOverrider;
}

public void setValueFromOverrider(final String valueFromOverrider)
{
this.valueFromOverrider = valueFromOverrider;
}
}


The interface for the above class is simple and shown next.


package dustin;

/**
* Interface for simple Java class configured in Spring via properties files.
*/
public interface SpringPropertiesHandlingIf
{
String getValueFromConfigurer();

String getValueFromOverrider();

void setValueFromConfigurer(final String valueFromConfigurer);

void setValueFromOverrider(final String valueFromOverrider);
}


The next code listing is the executable Java class that bootstraps the Spring container used in this example.


package dustin;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* Main executable starting Spring Container.
*/
public class SpringPropertiesMain
{
/**
* Main executable starting Spring Container.
*
* @param arguments Command-line arguments; none anticipated.
*/
public static void main(final String arguments[])
{
final ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext("/spring-properties-example.xml");
final SpringPropertiesHandlingIf propertiesExample =
(SpringPropertiesHandlingExample)
context.getBean("SpringPropertiesHandlingBean");
System.err.println( "Configurer Value: "
+ propertiesExample.getValueFromConfigurer());
System.err.println( "Overrider Value: "
+ propertiesExample.getValueFromOverrider());
}
}


This simple main class instantiates the Spring container. It then displays its attributes as set in the XML configuration file (called spring-properties-example.xml and shown next).


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:locations="classpath:/spring-properties-configure.properties" />

<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer"
p:locations="classpath:/spring-properties-override.properties" />

<bean id="SpringPropertiesHandlingBean"
class="dustin.SpringPropertiesHandlingExample"
p:valueFromConfigurer="${value.configurer}"
p:valueFromOverrider="yadayadayada" />
</beans>


In the Spring XML configuration shown above, the highlighted portion contains use of the PropertyPlaceholderConfigurer and the PropertyOverrideConfigurer.

The Spring XML above points at two properties files. They are simple in this example and are shown next.

spring-properties-configure.properties

value.configurer=Hello, World!
value.overrider=Hello, Spring!


spring-properties-override.properties

SpringPropertiesHandlingBean.valueFromOverrider=Overridden!


The first properties file is used to set the two values of the simple Java class and the second properties files overrides the value of the second of the two values of that Java class.

The output from running this looks like this:


Configurer Value: Hello, World!
Overrider Value: Overridden!


If I comment out the single line in the spring-properties-override.properties file so that it doesn't do any overriding, the output from running this now looks like this:


Configurer Value: Hello, World!
Overrider Value: yadayadayada


These two pieces of output show that the PropertyPlaceholderConfigurer configures the values in the Spring application based on properties files and the PropertyOverrideConfigurer allows these values to be overridden. Of course, you could override hard-coded values in the XML as well, but I thought it was interesting to see both the original values set with PropertyPlaceholderConfigurer and then see them overridden with PropertyOverrideConfigurer.

Wednesday, November 7, 2007

Ant <echoproperties /> Task

I have always found it useful when writing Ant build.xml files to have a task that prints out the properties that I use in that script. This helps me to determine if any of the properties are undefined or defined incorrectly. I have typically used the <echo> tag with the message attribute for each property. However, I realized recently when reading The Elements of Ant Style that this can be much easier using the echoproperties tag.

When used directly without any attributes or nested tags, all properties (general Java and Ant properties as well as locally defined project-specific properties) are listed. Because this can sometimes be a little too much information, it is useful that the echoproperties tag has the prefix attribute to narrow down the returned properties to those starting with the specified prefix. One limitation to using the prefix tag is that only one such prefix can be declared in an XML attribute. To declare multiple prefixes for which properties should be displayed, you can use the propertyset nested tag.

The following code listing shows an example of a build.xml file that uses the echoproperties tag and shows off a few of its features.

<?xml version="1.0" encoding="UTF-8"?>

<project name="EchoPropertiesExample" default="echoAll" basedir=".">
  
  <property environment="env" />

  <target name="echoAll"
          description="Echo all properties I access.">
    <echoproperties />
  </target>
  <target name="echoJava"
          description="Echo my properties that begin with java.">
    <echoproperties prefix="java" />
  </target>
  <target name="echoAnt"
          description="Echo my properties that begin with ant.">
    <echoproperties prefix="ant" />
  </target>

  <target name="echoAntAndJava"
          description="Echo Ant and Java properties">
    <echoproperties>
      <propertyset>
        <propertyref prefix="java" />
        <propertyref prefix="ant" />
      </propertyset>
    </echoproperties>
  </target>

  <target name="echoAllXml"
          description="Echo all properties in XML format">
    <echoproperties format="xml" />
  </target>

</project>

The last target example in the above build.xml file demonstrates how to use the format attribute set to xml to have the properties output to XML rather than the default text format. This is usually most useful when used in conjunction with the destfile attribute to specify a file to which the XML output is written.

Displaying the properties available to a particular Ant build.xml file is useful in ensuring that build are configured and working properly and the <echoproperties /> task makes this trivial.

In a previous blog entry, I discussed using Ant to reveal Java and Ant properties that are available in a given environment, but using <echoproperties /> is a more convenient method for doing this than explicitly creating individual <echo .../> tasks for each property.

Thursday, October 11, 2007

Java and Ant Properties Refresher

I occasionally need a certain built-in Java property for use in code or in an Apache Ant script and this blog entry is intended to make an easy-to-remember location for me to find a list of some of the properties that I use most often.

Some of the Java properties available from the call to System.getProperties() are listed in the Java Tutorial on System Properties. This resource lists only a small subset of the available properties, but the listed properties are among the most significant and more frequently used of the properties. These significant properties include file.separator, line.separator, path.separator, user.dir, and user.home.

The Javadoc API documentation for the System class has even more properties listed than the Java Tutorial, but not all of the available properties are listed (such as user.country, user.language, and user.timezone).

One of the best ways to view all of the available properties is to call System.getProperties() and iterate over the returned properties to see what is available. The code below shows how this is done and takes advantage of some Java SE 6 features in the process.

Java Code Listing for One Way to Display Available Properties

package properties;

import java.util.Enumeration;
import java.util.Properties;
import java.util.Set;

/**
 * Lists all Java system properties.  Uses
 * Properties.stringPropertyNames for convenience,
 * but this is a Java SE 6 feature and it shows only
 * properties in which both the key and the value
 * are String types.
 */
public class SystemPropertiesExample
{
  public static void main(final String[] aArgs)
  {
     System.out.println(
        "Welcome!  Here are your Java System properties:");
     Properties systemProperties = System.getProperties();
     Set propertyNames =
        systemProperties.stringPropertyNames();
     for ( final String propertyName : propertyNames )
     {
        String propertyValue =
           systemProperties.getProperty(propertyName);
        if ( propertyValue.isEmpty() )
        {
           propertyValue =
              "<<<empty string>>>";
        }
        System.out.println(  propertyName
                           + " = "
                           + propertyValue );
     }
  }
}

Of course, Java developers have been iterating over available properties since the beginning days of Java using java.util.Enumeration (not related to the enum introduced in Java 5) with the Properties.propertyNames() method, but the above code example demonstrates the new-to-Java-SE-6 Properties.stringPropertyNames() method in action.

Ant also makes it easy to access the Java system properties in addition to Ant's own built-in properties. The build.xml excerpt below demonstrates how easy it is to use Ant to display custom properties (defined in a separate build.properties file in this case), Ant’s built-in properties, Java-related properties, and even Java implementation-specific properties.

An Ant build.xml File that Displays Available Properties

<project name="SystemPropertiesExample"
default="buildJar"
basedir=".">

<property file="build.properties" />

<tstamp />

<target name="init">
<mkdir dir="${classes.dir}" />
</target>

<target name="clean">
<delete dir="${classes.dir}" />
</target>

<target name="compile"
description="Compile Java class for Java System.properties example"
depends="init">
<javac srcdir="${src.dir}"
destdir="${classes.dir}"
includes="properties/SystemPropertiesExample.java"
debug="${javac.debug}"
deprecation="${javac.deprecation}"
verbose="${javac.verbose}" />
</target>

<target name="buildJar"
description="Build executable JAR to display Java System.properties"
depends="compile">
<jar destfile="${dist.dir}/${jar.system.properties}"
basedir="${classes.dir}"
includes="properties/SystemPropertiesExample.class">
<manifest>
<attribute name="Main-Class"
value="properties.SystemPropertiesExample" />
</manifest>
</jar>
</target>

<target name="echo"
description="Display custom and standard available properties">
<antcall target="echoCustomProperties" />
<antcall target="echoAntBuiltInProperties" />
<antcall target="echoJavaSystemProperties" />
<antcall target="echoSunSpecificProperties" />
</target>

<!-- Properties created specifically for use in this build file (see the
associated build.properties file. -->
<target name="echoCustomProperties"
description="Display properties custom to this build file">
<echo message="------------- CUSTOM PROPERTIES ---------------" />
<echo message="jar.system.properties = ${jar.system.properties}" />
<echo message="javac.debug = ${javac.debug}" />
<echo message="javac.deprecation = ${javac.deprecation}" />
<echo message="javac.verbose = ${javac.verbose}" />
<echo message="classes.dir = ${classes.dir}" />
<echo message="dist.dir = ${dist.dir}" />
<echo message="src.dir = ${src.dir}" />
</target>

<!-- Ant's built-in properties as described in Ant manual at
http://ant.apache.org/manual/using.html#built-in-props. -->
<target name="echoAntBuiltInProperties"
description="Display Ant's built-in properties">
<echo message="------------- ANT PROPERTIES ---------------" />
<echo message="ant.file = ${ant.file}" />
<echo message="ant.home = ${ant.home}" />
<echo message="ant.java.version = ${ant.java.version}" />
<echo message="ant.project.name = ${ant.project.name}" />
<echo message="ant.version = ${ant.version}" />
<echo message="basedir = ${basedir}" />
</target>

<!-- Ant's peek at select Java's properties. Ant actually can see many more
properties than shown here, including Sun-specific properties when using
that particular JVM, but only a sample is shown here. -->
<target name="echoJavaSystemProperties"
description="Display Java properties">
<echo message="------------- (SELECT SAMPLE OF) JAVA PROPERTIES ---------------" />
<echo message="java.class.path = ${java.class.path}" />
<echo message="java.class.version = ${java.class.version}" />
<echo message="java.home = ${java.home}" />
<echo message="java.library.path = ${java.library.path}" />
<echo message="java.runtime.name = ${java.runtime.name}" />
<echo message="java.runtime.version = ${java.runtime.version}" />
<echo message="java.vendor.url = ${java.vendor.url}" />
<echo message="java.vendor.url.bug = ${java.vendor.url.bug}" />
<echo message="java.version = ${java.version}" />
<echo message="java.vm.info = ${java.vm.info}" />
<echo message="java.vm.name = ${java.vm.name}" />
<echo message="java.vm.specification.vendor = ${java.vm.specification.vendor}" />
<echo message="java.vm.vendor = ${java.vm.vendor}" />
<echo message="java.vm.version = ${java.vm.version}" />
<echo message="os.arch = ${os.arch}" />
<echo message="os.name = ${os.name}" />
<echo message="os.version = ${os.version}" />
<echo message="user.country = ${user.country}" />
<echo message="user.home = ${user.home}" />
<echo message="user.language = ${user.language}" />
<echo message="user.name = ${user.name}" />
<echo message="user.timezone = ${user.timezone}" />
</target>

<!-- Display Ant's peek at select Sun-specific properties. -->
<target name="echoSunSpecificProperties" if="sun.management.compiler">
<echo message="--------------- (SELECT) SUN-SPECIFIC PROPERTIES ---------------" />
<echo message="sun.boot.library.path = ${sun.boot.library.path}" />
<echo message="sun.cpu.isalist = ${sun.cpu.isalist}" />
<echo message="sun.java.launcher = ${sun.java.launcher}" />
<echo message="sun.management.compiler = ${sun.management.compiler}" />
</target>

</project>

The build.properties file used by the build.xml file above


# Directories
classes.dir = classes
dist.dir = dist
src.dir = src

# Generated Files
jar.system.properties = displayJavaProperties.jar

# Java Compiler (javac) Attributes
javac.debug = off
javac.deprecation = off
javac.verbose = no

UPDATE (6 November 2007): This <echoproperties /> task is an even easier way to display properties available to an Ant build.xml file. I cover this useful Ant task in more detail in this blog entry.

There are some differences between the properties returned from the Java System.getProperties() call and the Java-related properties accessed in Ant. For example, the property java.class.path has a value shown only of the executable JAR file that was executed with "java –jar displayJavaProperties.jar" to print out the properties while the Ant java.class.path display shows a very long classpath value with paths pointing to various Java and Ant JAR and ZIP files.

Fred Swartz has a nice discussion of using Java's System.getProperties with Swing in his Java: Systems Properties page.