System.getProperty("java.version") Returns Null

I am trying to compile a class which uses the Processing 3.4 source code. I am getting an StringIndexOutOfBoundsException when trying to compile the class which extends PApplet.

The PApplet class has the following code which I think is the issue

public class PApplet implements PConstants {
  /** Full name of the Java version (i.e. 1.5.0_11). */
  static public final String javaVersionName =
    System.getProperty("java.version");

  static public final int javaPlatform;
  static {
    String version = javaVersionName;
    if (javaVersionName.startsWith("1.")) {
      version = version.substring(2);
      javaPlatform = parseInt(version.substring(0, version.indexOf('.')));
    } else {
      // Remove -xxx and .yyy from java.version (@see JEP-223)
      javaPlatform = parseInt(version.replaceAll("-.*","").replaceAll("\\..*",""));
    }
  }

I think that the string javaVersionName is being set to null or some other weird value which is causing version.indexOf('.') to return -1.

The stack trace:

    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:567)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run (ExecJavaMojo.java:293)
    at java.lang.Thread.run (Thread.java:830)
Caused by: java.lang.StringIndexOutOfBoundsException: begin 0, end -1, length 2
    at java.lang.String.checkBoundsBeginEnd (String.java:3720)
    at java.lang.String.substring (String.java:1909)
    at processing.core.PApplet.<clinit> (PApplet.java:123)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:567)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run (ExecJavaMojo.java:293)
    at java.lang.Thread.run (Thread.java:830)

Somewhere in there it says at processing.core.PApplet.<clinit> (PApplet.java:123). Line 123 in PApplet.java is the first line (public class PApplet ...) that I posted above.

I suspect it might have something to do with my path and JAVA_HOME system variables. I am using JDK 13 which is added to my path as C:\Program Files\Java\jdk-13\bin and the JAVA_HOME variable is set to C:\Program Files\Java\jdk-13\

EDIT: The main function within my class looks like this

static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "Demo" };

    if (passedArgs != null) {
        PApplet.main(concat(appletArgs, passedArgs));
    } else {
        PApplet.main(appletArgs);
    }
}

EDIT: I should also mention that the PApplet snippet I posted above is not the actual source that I am using, just something I found online. The actual source I that have is in a core.jar folder. I cannot change the source without great difficulty.

It looks like you are cheating a little bit ;)

The code you have shown is already after the fix for proper handling of Java version since release 9 - this is where you have slightly different version for major release and patched versions.

It looks like your core.jar is pre-commit:

https://github.com/processing/processing/commit/b0b2d89228c8bf178f5113a4af25779a14f242e1#diff-29e1de29464981394819a89e38e87288

where handling of java.version property was fixed.

So, your sample code should read

public class PApplet {
  static public final String javaVersionName =
    System.getProperty("java.version");

  static public final int javaPlatform =
     PApplet.parseInt(PApplet.split(javaVersionName, '.')[1]);


  static public String[] split(String value, char delim) {
    // do this so that the exception occurs inside the user's
    // program, rather than appearing to be a bug inside split()
    if (value == null) return null;
    //return split(what, String.valueOf(delim));  // huh

    char chars[] = value.toCharArray();
    int splitCount = 0; //1;
    for (int i = 0; i < chars.length; i++) {
      if (chars[i] == delim) splitCount++;
    }
    // make sure that there is something in the input string
    //if (chars.length > 0) {
      // if the last char is a delimeter, get rid of it..
      //if (chars[chars.length-1] == delim) splitCount--;
      // on second thought, i don't agree with this, will disable
    //}
    if (splitCount == 0) {
      String splits[] = new String[1];
      splits[0] = value;
      return splits;
    }
    //int pieceCount = splitCount + 1;
    String splits[] = new String[splitCount + 1];
    int splitIndex = 0;
    int startIndex = 0;
    for (int i = 0; i < chars.length; i++) {
      if (chars[i] == delim) {
        splits[splitIndex++] =
          new String(chars, startIndex, i-startIndex);
        startIndex = i + 1;
      }
    }
    //if (startIndex != chars.length) {
      splits[splitIndex] =
        new String(chars, startIndex, chars.length-startIndex);
    //}
    return splits;
  }

  static final public int parseInt(String what) {
    return parseInt(what, 0);
  }

  static final public int parseInt(String what, int otherwise) {
    try {
      int offset = what.indexOf('.');
      if (offset == -1) {
        return Integer.parseInt(what);
      } else {
        return Integer.parseInt(what.substring(0, offset));
      }
    } catch (NumberFormatException e) { }
    return otherwise;
  }

  public static void main(String [] args) {
    System.out.println("Java version: " + javaPlatform);
  }
}

and for main

public class Main {
  static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "Demo" };

    PApplet.main(appletArgs);
  }
}

where you will get your Exception

> javac PApplet.java
> javac Main.java
> java -cp . Main
Exception in thread "main" java.lang.ExceptionInInitializerError
    at Main.main(Main.java:7)
Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
    at PApplet.<clinit>(PApplet.java:6)
    ... 1 more

if you use the tick suggested in comment, you can get it "fixed"

public class Main {
  static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "Demo" };

    System.setProperty("java.version", "1.1.1");

    PApplet.main(appletArgs);
  }
}

and you will get your code running

> javac PApplet.java
> javac Main.java
> java -cp . Main
Java version: 1

So, concluding, why not building it from most recent sources? :)

Alternative approach - little bit hacky

Let's say you can't alter neither Main.java nor core.jar. What you can do here is to cheat Java where to look for PApplet.class. You can create a dir - let's call it fix. Inside fix you can compile just one class: PApplet.java. And then, you can run the code like this:

> java -cp fix:. Main

where fix contains your specially crafted version

public class PApplet {
  static public final String javaVersionName =
    System.getProperty("java.version");

  static public final int javaPlatform = 1;

  public static void main(String [] args) {
    System.out.println("Java version: " + javaPlatform);
  }
}

Java System.getProperty vs System.getenv, getProperty(String key) : java.lang.System.getProperty(String key) method returns a string containing the value of the property. If the property does not exist, this  Description The java.lang.System.getProperties () method determines the current system properties. The current set of system properties for use by the getProperty (String) method is returned as a Properties object. If there is no current set of system properties, a set of system properties is first created and initialized.

getproperty() and getproperties() methods of System Class in Java , System.getProperty(String key) method gets the system property indicated by the specified key. Declaration. Following is the declaration for java.lang.System  Properties p = new Properties (System.getProperties ()); This statement initializes the new properties object, p, with the current set of system properties, which in the case of this small application, is the set of properties initialized by the runtime system.

The problem is here:

 //supposing Java version 18.9
 version = version.substring(2);
 //now version is equal to "9"
 javaPlatform = parseInt(version.substring(0, version.indexOf('.')));//error! because indexOf('.') return -1 since '.' is not found in variable version

So, indexOf('.') return -1 and subString(0,-1) raise StringIndexOutOfBoundsException

Java.lang.System.getProperty() Method, The java.lang.System.getProperties() method determines the current system properties. The current set of system properties for use by the getProperty(String)​  We can use System.getProperty () method to find out the Operating System information, user home directory, Java runtime version, path separator, line separator, user working directory, Java home, Java classpath, and various other useful information. Java System getProperty Example

Java.lang.System.getProperties() Method, System.getProperty() gets a property as defined by the JVM (either the JVM itself or any -D options you may have passed at the command line). getProperties () : java.lang.System.getProperties () fetches the current properties that JVM on your System gets from your Operating System. The current System properties are returned as Properties object for use by the getProperties () method. If no such set of properties is present, a set of system is first created and then initialized.

What is the difference between System.getProperty and properties , We can use System.getProperty() method to find out the Operating System information, user home directory, Java runtime version, path separator, line separator,  Situations in which AmbiguousMatchException occurs include the following: A type contains two indexed properties that have the same name but different numbers of parameters. To resolve the ambiguity, use an overload of the GetProperty method that specifies parameter types.

Java System.getProperty(), getProperties() or you can also retrieve individual property via System.​getProperty(key) . Please note that Access to system properties can be restricted by the Java  The java.lang.System class is a final class, meaning that we cannot subclass it, therefore all methods are static. We are going to look at the differences between two System methods for reading system properties and environment variables. These methods are getProperty and getenv. 2.

Comments
  • please share a minimal version of your PApplet sublcass (would be good to see how you initialize the applet). Which version of Processing are you using ?
  • Take a look here: owsiak.org/java-9-10-and-macos-issues-with-java-version
  • @GeorgeProfenza I added the main function from my class. That code was added when I exported my application from Processing. The reason I wish to compile it myself is so that I can hopefully add it to a web app using Heroku. And the version of processing I am using is 3.4.
  • @Oo.oO I am using windows
  • It doesn’t matter whether it’s windows or any other system. Java introduced new version format.
  • I can't really debug it since the actual libraries I'm using are already compiled (I tried to recompile everything myself and I need sooooo many other dependencies). Your note on applets is appreciated though.
  • @AlexanderDingwall I'm not sure I understand your point about being unable to debug. Can you not just open a socket and set a breakpoint in the source? What does this have to do with the libraries in use and the fact that they are compiled?
  • The PApplet snippet I posted is not from my actual source that I am using, just something I found online. All I have pertaining to this library is a file called core.jar which I add to the classpath when I compile my .java file.
  • @AlexanderDingwall I see. Your IDE should be able to de-compile that and show you the source though, unless it's obfuscated (in which case it will show you the source, but not in a very useful way :). You should still be able to set a breakpoint where you want and debug this.
  • @AlexanderDingwall I cannot recommend using an IDE strongly enough. It will make a lot of your problems go away. Just trust me on that one: stop everything and set it up now - you may struggle a while at first, but you'll never look back, and that'll provide you invaluable help for all your current and future projects.
  • Yes, I mention that in my question. I am asking how to fix it.
  • @AlexanderDingwall I think is more easy to create in your main your own static method exact copy of PAppplet.javaPlatform() , and finally print on console what variable javaVersionName contains
  • I am a little confused about what you mean. javaPlatform is a static int variable
  • @AlexanderDingwall sorry I mean PApplet.main method