The Final Take On Java System Properties

November 26th, 2009 by  |  Published in Java  |  17 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

Responses

  1. john says:

    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”),

  2. Christopher Deckers says:

    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

  3. Christopher Deckers says:

    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

  4. Steve Chaloner says:

    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);
    }

    }

  5. Stefan Fußenegger says:

    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.

  6. Stefan Fußenegger says:

    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.

  7. Steve Chaloner says:

    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.

  8. Stefan Fußenegger says:

    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.

  9. Steve Chaloner says:

    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.

  10. Stefan Fußenegger says:

    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 :)

  11. Steve Chaloner says:

    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 :)

  12. Iain says:

    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)

  13. Stathis Alexopoulos says:

    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?

  14. Stefan Fußenegger says:

    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

  15. Writing Java Code that Writes Java Code | Java Articles says:

    August 27th, 2013 at 12:05 pm (#)

    […] to Molindo and the article, The Final Take On Java System Properties, for the list of Java System properties found on various operating […]

  16. jd evora says:

    October 3rd, 2013 at 11:11 am (#)

    He,

    Looking for a way to force java to active the TCP “keep alive” I came across http://docs.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html

    And then came across your post looking for something similar

    I think that you should add those to your class

    JD

  17. joe says:

    April 23rd, 2014 at 7:27 pm (#)

    Hi,
    thanks for that programm.

    Would be helpful, to know witch jar your logger needs:

    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:/D:/ncset/workspace623/SystemProps/lib/slf4j-1.7.7/slf4j-simple-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/D:/ncset/workspace623/SystemProps/lib/slf4j-1.7.7/slf4j-log4j12-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/D:/ncset/workspace623/SystemProps/lib/slf4j-1.7.7/slf4j-jdk14-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/D:/ncset/workspace623/SystemProps/lib/slf4j-1.7.7/slf4j-android-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/D:/ncset/workspace623/SystemProps/lib/slf4j-1.7.7/slf4j-jcl-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/D:/ncset/workspace623/SystemProps/lib/slf4j-1.7.7/slf4j-nop-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
    SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]

    Bye Joe

Leave a Response