简体   繁体   中英

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.

There are two aspects to this:

  • the very fact that a StringIndexOutOfBoundsException is being thrown within context implies that the javaVersionName string is not null , otherwise, you'd get a NullPointerException when startsWith is invoked
  • The issue here is the assumption that the part of the string after 1. will have another dot

There are various Java major versions and vendors and the versions change depending on that.

You should simply debug your code and infer what exactly is the value returned there.

As a probably unrelated note, you also want to be cautious if (as the class name suggests), your application is an applet:

Security consideration: Access to system properties can be restricted by the Security Manager. This is most often an issue in applets, which are prevented from reading some system properties, and from writing any system properties. For more on accessing system properties in applets, refer to System Properties in the Doing More With Java Rich Internet Applications lesson.

Sourcehere .

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM