The Final Take On Java System Properties
November 26th, 2009 by Stefan Fußenegger | Published in Java | 14 Comments
In this post, I’m looking for active collaboration of my readers (as I really hope that I have some). I’ve thought about a simpler way to handle Java system properties as I tend to forget them all the time. Additionally, I don’t like to see them as string constants – neither within the code nor somewhere else. I’ve come up with a single enum class, that aims to simplify handling of system properties. Actually, you won’t ever think of possible best practices – hence “The Final Take on Java System Properties” ![]()
Note: the impatient may skip down to the list of requirements – but please let me give some background first
Yesterday, I was trying to make all our JUnit tests independent of the current content of a system’s temporary directory (“java.io.tmpdir”). It’s pretty simple to add “-Djava.io.tmpdir=`mktemp -d /tmp/junit.XXXX`” as a JVM parameter – at least as long as you don’t have to do it more than a few times. As I didn’t like the idea of adding this parameter to each and every invocation of our Maven build, I’ve abandoned this idea rather quickly. Instead, I was looking to set java.io.tmpdir within Maven. To do this, all it takes is adding the appropriate configuration to the maven-surefire-plugin:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<systemProperties>
<property>
<name>java.io.tmpdir</name>
<value>${java.io.tmpdir}${file.separator}surefire-${user.name}-${project.artifactId}</value>
</property>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build> |
In my case, the resulting value of java.io.tmpdir was “/tmp/surefire-build-molindo-util-r4711″ (btw, “build.vcs.number” is set by TeamCity). Having this done, I’ve found out another thing: while the JVM does not guarantee that java.io.tmpdir exists quite a bunch of our tests assumed that java.io.tmpdir points to an existing directory. So the next step was refactoring some code:
// existing File tmp = new File(System.getProperty("java.io.tmpdir"), "output.txt"); // new File tmpDir = new File(System.getProperty("java.io.tmpdir")); tmpDir.mkdirs(); File tmp = new File(tmpDir, "output.txt"); |
As I don’t like to repeat myself – who does? – I thought about creating a new utility method:
public static File getTmpDir() { File tmpDir = new File(System.getProperty("java.io.tmpdir")); tmpDir.mkdirs(); return tmpDir; } |
Well, nothing spectacular here, most likely I wouldn’t be the first one to write this method. As a second though, I remembered that I had to lookup the property names for my Maven configuration: “java.io.tmpdir”, “file.separator”, “user.name”. Some of you might be able to name all of them instantly, but I’m admittedly not very good in remembering such things. As a result, I decided to create a simple utility that should provide four things:
Requirements:
- simple and consistent access to Java system properties
- full documentation of available properties and their possible values – within my IDE (i.e. auto-completion, inline Javadoc)
- fix inconsistencies in returned values and/or naming
- make sure that java.io.tmpdir exists – acutally that’s the main reason why I’m doing all this
That’s why I came up with the following class: SystemProperty.java
It’s not complete yet, especially the documentation. Yet, I’ve only tested it with Sun Java 1.6 on Linux and Mac. To get full documentation of available properties and values, I’d like to ask you to run the included main method and send me the output (simply paste it to your favourite pastebin and post the link in the comments) along with your environment (OS, JVM version). In return, I’ll promise to update the class with all the gathered input and keep it available at the above URL.
Some highlights:
// Use toString() to get values: // "/tmp/output.txt" System.out.println(new File(SystemProperty.JAVA_IO_TMPDIR + "output.txt")); // "You are running Linux, version 2.6.24-25-generic" System.out.println(String.format("You are running %s, version %s", SystemProperty.OS_NAME, SystemProperty.OS_VERSION)); // get and set values SystemProperty.JAVA_IO_TMPDIR.set("/dev/null"); // avoid setting of properties that shouldn't be changed // throws UnsupportedOperationException SystemProperty.JAVA_CLASS_PATH.set(newClassPath); |
Additionally, access to properties is wrapped into a PrivilegedAction which is suggested as a best practice. If you know of any derived properties that would be cool to include, please let me now (e.g. Maven is providing non-standard os.family which I might include). Next, if you know of any properties that shouldn’t be read-only, let me know. Finally, if you know of any inconsistencies across different environments (e.g. like java.io.tmpdir that might or might not endswith a file seperator) – make a guess – let me know!
EDIT: I’ve also asked the people on Stack Overflow for collaboration. You may also add your output there.
EDIT2: This class is part of the molindo-utils project at GitHub
November 28th, 2009 at 8:11 am (#)
### PLEASE POST THIS AT http://j.mp/props0 or http://j.mp/props1
/**
* Windows XP only: known values:
*/
USER_VARIANT(“user.variant”),
November 28th, 2009 at 12:33 pm (#)
Here is a list of settable properties (some have to be set very early to have an effect):
“sun.awt.disableMixing” (for Sun VM on Java 6u14+)
“sun.awt.noerasebackground”
“sun.awt.xembedserver”
By-the-way, I love this idea of an enum for all properties, and I will probably create a similar enum for my application-specific properties!
Keep up the good work.
-Christopher
November 28th, 2009 at 9:54 pm (#)
I have added the following method:
public String get(String defaultValue);
It allows to specify the default value to return when the value of the property is null. It calls:
System.getProperty(getName(), defaultValue);
-Christopher
December 1st, 2009 at 12:53 pm (#)
You might also be interested in objectify-led : http://www.objectify.be/objectify-led/
It handles assignment of properties using, amoung other things, system properties, properties files or arbitrary data sources. Type conversion is also handled.
public class Foo
{
@Property(“blah.value”);
private static String BLAH = “default-value”;
@Property(“mystring.value”);
private String myString;
@Property(“myint.value”);
private int myInt = -1;
public static void main(String[] args)
{
Foo foo = new Foo();
new PropertySetter().process(foo);
}
…
}
December 1st, 2009 at 7:54 pm (#)
Hi Christopher,
thanks for your input. I’ve added the get(String) method. Additionally, I’ve added some convenience methods that convert the String: getInteger(String), getLong(String), getBoolean(String), getFloat(String), getDouble(String), getFile(String) (all with a no-argument alternative and a corresponding setter).
I’m also thinking about uploading the result as a Maven artifact as soon as my work is done. This way, it can easily be included in any project.
December 2nd, 2009 at 9:08 am (#)
Hi Steve,
First, sorry that I’ve forgotten to approve your comment yesterday. Personally, I’m not interested as I’m normally using Spring for what you describe. And if not, compared to
@Property(“user.country”);
private String country = “US”;
using
private String country = SystemProperty.USER_COUNTRY.get(“US”);
looks far less … frightening
How do you process the annotations? I couldn’t find that information on your site.
December 11th, 2009 at 12:01 pm (#)
Hi Stefan,
take a look at http://objectify-led.googlecode.com/svn/trunk/src/main/java/be/objectify/led/PropertySetter.java and you’ll see how the annotations are processed.
I like your approach for well-known properties, but for arbitrary properties it would require either the developer to update the class manually and then have to merge in your future updates, or for you to add properties from potentially proprietary projects to the enum.
Personally, I would (and will) use your SystemProperty enum for well-known props (don’t re-invent the wheel!) and objectify-led for project-specific properties.
December 11th, 2009 at 12:13 pm (#)
Hi Steve,
there’s nothing too spectacular in this class. But when and how is PropertySetter#process(..) invoked? But don’t get me wrong. Your project looks nice. However, it’s mostly a subset of Spring’s functionality – and Spring is what I’m already using on a daily basis.
I know that my enum isn’t suited for project-specific properties. That never was it’s intention. I’m not even sure about using an enum. But the “how” is not important anyway. My main objective was documentation on the one hand and getting rid of string constants on the other hand. Both in order to leverage IDE capabilities such as autocompletion and inline Javadoc.
December 11th, 2009 at 12:24 pm (#)
Hi Stefan,
PropertySetter#process(..) is the entry point to traverse the variables of an object/class – see my original post for an example.
Most of my projects involve Spring, but a few small ones don’t and I don’t want to have to a) use Spring or b) set the properties and do the type conversion by hand – that’s where objectify-led (need to find a shorter name…) comes in handy.
One other advantage (which I haven’t written yet) is automatic help generation on the command line. Since all properties which can be set are annotated, they can automatically be discovered and printed out. Hope to get around to implementing this at the weekend.
December 11th, 2009 at 12:29 pm (#)
Okay, so now it all comes together. Actually, it sound nice. I could have used it for some groovy scripts
December 11th, 2009 at 12:32 pm (#)
I think I need to collate what I’ve written here and update the project site. Thanks for the discussion
February 18th, 2011 at 2:02 pm (#)
### PLEASE POST THIS AT http://j.mp/props0 or http://j.mp/props1
/**
* Windows 7 only; known values:
*/
USER_VARIANT(“user.variant”),
name mismatch: SUN_AWT_DISABLEMIXING: sun.awt.disableMixing=null (expected SUN_AWT_DISABLE_MIXING)
April 26th, 2013 at 9:13 am (#)
Hi Stefan,
I don’t know if you still maintaining that code, but finally i discovered what is the mystery
/**
* Windows only: known values: “” (empty string)
*/
USER_VARIANT(“user.variant”),
the user.variant property is part of the triplet
user.language
user.country
user.variant
needed to define a Locale instance. Could you please update your source code?
April 26th, 2013 at 5:59 pm (#)
Stathis,
what do you want me to update? Remove the “Windows ONLY” comment only?
Note that I’ve updated the post with a link to our GitHub project.
Cheers