Search code examples
javajvmcross-platformplatform

How can I find complete list of platform-dependent traps in JDK like timezone, encoding, line endings etc.?


We always want our dev/test environment to be production like, but often we can be caught in the trap of using JDK functions that are not exposing environment dependency very explicit (like required method parameter) or can be subtle to detect and be aware. For example:

  • public String(byte bytes[]) uses default encoding
  • new Date()/Instant.now() uses sytem timezone
  • System.out.printf("%n") uses platform line endings

Some of them can be driven by JVM parameters like -Dfile.encoding=UTF-8.

But how to find all of such gotchas?


Solution

  • The type of gotchas depends on the type of your application.

    For an almost complete list you can run this check, which lists both your operating system environment variables and the java system properties:

    import java.awt.GraphicsEnvironment;
    import java.util.Map;
    import java.util.Properties;
    
    public class Sof39189179 {
    
        public static void main(String[] args) {
    
            Map<String, String> sysenv = System.getenv();
    
            for(String key: sysenv.keySet())
                System.out.println( key +  ": " + sysenv.get(key));
    
            Properties properties = System.getProperties();
    
            for(Object key: properties.keySet())
                System.out.println(key + ": " + properties.get(key));
    
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
            System.out.println("headless: " + ge.isHeadless());
        }
    }
    

    On my computer, I get the following output (I have left out some lines):

    M2: $M2_HOME/bin
    JAVA_HOME: /opt/local/jdk-1.8.0_51
    LANG: en_US.UTF-8
    CATALINA_HOME: /opt/local/tomcat-8.0.24
    
    ...
    
    ---------------------
    java.runtime.name: Java(TM) SE Runtime Environment
    sun.boot.library.path: /opt/local/jdk-1.8.0_51/jre/lib/amd64
    java.vm.version: 25.51-b03
    java.vm.vendor: Oracle Corporation
    java.vendor.url: http://java.oracle.com/
    path.separator: :
    java.vm.name: Java HotSpot(TM) 64-Bit Server VM
    file.encoding.pkg: sun.io
    user.country: US
    sun.java.launcher: SUN_STANDARD
    sun.os.patch.level: unknown
    java.vm.specification.name: Java Virtual Machine Specification
    user.dir: /home/rudolf/workspace/neon/sof39189179
    java.runtime.version: 1.8.0_51-b16
    java.awt.graphicsenv: sun.awt.X11GraphicsEnvironment
    java.endorsed.dirs: /opt/local/jdk-1.8.0_51/jre/lib/endorsed
    os.arch: amd64
    java.io.tmpdir: /tmp
    line.separator: 
    
    java.vm.specification.vendor: Oracle Corporation
    os.name: Linux
    ...
    
    java.awt.printerjob: sun.print.PSPrinterJob
    file.encoding: UTF-8
    java.specification.version: 1.8
    java.class.path: /home/rudolf/workspace/neon/sof39189179/bin
    user.name: rudolf
    java.vm.specification.version: 1.8
    java.home: /opt/local/jdk-1.8.0_51/jre
    sun.arch.data.model: 64
    user.language: en
    java.specification.vendor: Oracle Corporation
    awt.toolkit: sun.awt.X11.XToolkit
    java.vm.info: mixed mode
    java.version: 1.8.0_51
    java.ext.dirs: /opt/local/jdk-1.8.0_51/jre/lib/ext:/usr/java/packages/lib/ext
    sun.boot.class.path: /opt/local/jdk-1.8.0_51/jre/lib/resources.jar:/opt/local/jdk-1.8.0_51/jre/lib/rt.jar:/opt/local/jdk-1.8.0_51/jre/lib/sunrsasign.jar:/opt/local/jdk-1.8.0_51/jre/lib/jsse.jar:/opt/local/jdk-1.8.0_51/jre/lib/jce.jar:/opt/local/jdk-1.8.0_51/jre/lib/charsets.jar:/opt/local/jdk-1.8.0_51/jre/lib/jfr.jar:/opt/local/jdk-1.8.0_51/jre/classes
    java.vendor: Oracle Corporation
    file.separator: /
    java.vendor.url.bug: http://bugreport.sun.com/bugreport/
    sun.io.unicode.encoding: UnicodeLittle
    sun.cpu.endian: little
    sun.cpu.isalist: 
    headless: false
    

    You can determine from this list what properties are relevant in your case and check your code for it. Or, better, code with those properties in mind.

    System.out.printf("%n") uses platform line endings

    I prefer using the properties listed above, i.e. for printing out a newline, I use something like:

    String newline = (String) System.getProperties().get("line.separator");
    System.out.println("newline: " +  newline);