Hiển thị các bài đăng có nhãn properties. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn properties. Hiển thị tất cả bài đăng

Thứ Ba, 27 tháng 1, 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.

Thứ Sáu, 11 tháng 4, 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.