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:
StringIndexOutOfBoundsException
is being thrown within context implies that the javaVersionName
string is not null
, otherwise, you'd get a NullPointerException
when startsWith
is invoked1.
will have another dotThere 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:
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.