Sometimes you have to be evil!
Many times the most innocuous aspects of programming create lot of trouble. Take the innocent Properties file. These avatars of Hashtable are collections of key-value pairs, frequently used by applications for their need for external resources and configuration settings. Now pointers such as these tell you that reading the Properties file using java I/O is evil, owing to the fact that it warrants absolute file names and that in turn hinders application portability. So we have the recommended ways to use the ResourceBundle class or classpath resources. Nothing wrong with this!
Or so I thought, till I had to work on a web-interface to create, modify and delete Properties files. I realized that when loading a Properties file using the Classloader and ResourceBundle and after I modify my files and store() the values, the changes though successfully saved to the file in question won’t reflect to the user. The old properties were displayed despite the fact that some of them had been changed. The reason it seems was the fact that the Classloader somehow cached the properties. While this would be termed most efficient and desirable when reading the properties, this perhaps wouldn’t be so in an Property File Editor application like mine.
In a nutshell what I ultimately had to do was to take the evil route and use java.io to load the files, as below:
[code lang=”java”]
//Do not load the properties file as Resource
//stream or ResourceBundle
//if caching is not acceptable
//InputStream in = loader.getResourceAsStream(name);
//Load it using direct I/O, obviously we need the
//file "path" here, which can be
//retrieved using the ServletContext
in = new FileInputStream(path);
//rest is usual stuff
if (in != null) {
Properties objProps = new Properties();
objProps.load(in);
}
[/code]
Since this is a web-application I am fetching the relative file-path of the Properties file (situated along with other classes in a package structure) using the ServletContext (getRealPath()), this works well in Tomcat, I am not sure if this approach works for all containers, especially on Websphere.
Update (Jan.01, 2004):
I must apologise for not updating this post after I implemented Anthony’s suggestion based on the original post (see comments on this post). The getResourceAsStream() approach is indeed cool to load the file without using Classloader while avoiding risk of unpredictability associated with getRealPath() on various containers. This also avoided the caching that the Classloader was doing. So the code above may be revised as follows:
[code lang=”java”]
//Load using direct I/O, we need the file "path"
//here retrievable using the ServletContext
String path = "/WEB-INF/properties/" + name + ".properties";
//getResourceAsStream() does not use Classloader
<strong>in = sContext.getResourceAsStream(path);</strong>
if (in != null) {
Properties objProps = new Properties();
objProps.load(in);
}
[/code]
Did you update the original file?
Did you re-load file?
Did you flush()?
Try using Dynamic properties:
http://www.javaworld.com/javaworld/javatips/jw-javatip125.html?
Any use of getRealPath() will most likely not work if you use unpacked WARs. Perhaps you should try using ServletContext.getResourceAsStream() instead of the class loader method.