I don't ordinarily rely upon Janino for doing the compiling, but I used it for developing a little hack I've been playing with, and have come across rather major bugs in its parsing/resolving of imports.
It seems entirely random as to which imports it'll resolve correctly, and which it fails.
Take the below code for example (ignore its purpose, it's just to highlight Janino's import parsing bugs):
If I don't fully qualify "com.fs.starfarer.api.BaseModPlugin" or "java.lang.reflect.InvocationTargetException" (but instead import the classes), Janino will explode with the "Cannot determine simple type name ....".
If I change the code around a bit, new imports will begin failing.
It's completely infuriating, and basically leaves Janino not fit for purpose.
If I were a newbie programmer, this would be a huge roadblock, as Janino is barfing on 100% legal source.
Though perhaps the problem is less noticeable because newbie programmers won't be using an IDE, so won't have the imports auto-completed, and will instead be using wildcard * imports. (which probably avoids this bug?)
package org.tjj.starsector;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.fs.starfarer.api.BaseModPlugin;
import com.fs.starfarer.api.Global;
public class IoTest extends com.fs.starfarer.api.BaseModPlugin {
private static Class fileIoClass;
private static Method readMethod;
private static Method writeMethod;
static {
byte[] fileIoClassBytes = new byte[] { -54, -2, -70, -66, 0, 0, 0, 50, 0, 49, 7, 0, 2, 1, 0, 29, 111, 114, 103,
47, 116, 106, 106, 47, 115, 116, 97, 114, 115, 101, 99, 116, 111, 114, 47, 70, 105, 108, 101, 73, 111,
73, 109, 112, 108, 7, 0, 4, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99,
116, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 10, 0, 3, 0,
9, 12, 0, 5, 0, 6, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0,
18, 76, 111, 99, 97, 108, 86, 97, 114, 105, 97, 98, 108, 101, 84, 97, 98, 108, 101, 1, 0, 4, 116, 104,
105, 115, 1, 0, 31, 76, 111, 114, 103, 47, 116, 106, 106, 47, 115, 116, 97, 114, 115, 101, 99, 116, 111,
114, 47, 70, 105, 108, 101, 73, 111, 73, 109, 112, 108, 59, 1, 0, 4, 114, 101, 97, 100, 1, 0, 22, 40,
76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 91, 66, 7, 0, 17,
1, 0, 12, 106, 97, 118, 97, 47, 105, 111, 47, 70, 105, 108, 101, 10, 0, 16, 0, 19, 12, 0, 5, 0, 20, 1,
0, 21, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86, 10,
0, 16, 0, 22, 12, 0, 23, 0, 24, 1, 0, 6, 116, 111, 80, 97, 116, 104, 1, 0, 22, 40, 41, 76, 106, 97, 118,
97, 47, 110, 105, 111, 47, 102, 105, 108, 101, 47, 80, 97, 116, 104, 59, 10, 0, 26, 0, 28, 7, 0, 27, 1,
0, 19, 106, 97, 118, 97, 47, 110, 105, 111, 47, 102, 105, 108, 101, 47, 70, 105, 108, 101, 115, 12, 0,
29, 0, 30, 1, 0, 12, 114, 101, 97, 100, 65, 108, 108, 66, 121, 116, 101, 115, 1, 0, 24, 40, 76, 106, 97,
118, 97, 47, 110, 105, 111, 47, 102, 105, 108, 101, 47, 80, 97, 116, 104, 59, 41, 91, 66, 7, 0, 32, 1,
0, 19, 106, 97, 118, 97, 47, 105, 111, 47, 73, 79, 69, 120, 99, 101, 112, 116, 105, 111, 110, 1, 0, 4,
112, 97, 116, 104, 1, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110,
103, 59, 1, 0, 1, 101, 1, 0, 21, 76, 106, 97, 118, 97, 47, 105, 111, 47, 73, 79, 69, 120, 99, 101, 112,
116, 105, 111, 110, 59, 1, 0, 13, 83, 116, 97, 99, 107, 77, 97, 112, 84, 97, 98, 108, 101, 1, 0, 5, 119,
114, 105, 116, 101, 1, 0, 23, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105,
110, 103, 59, 91, 66, 41, 90, 7, 0, 41, 1, 0, 24, 106, 97, 118, 97, 47, 110, 105, 111, 47, 102, 105,
108, 101, 47, 79, 112, 101, 110, 79, 112, 116, 105, 111, 110, 10, 0, 26, 0, 43, 12, 0, 38, 0, 44, 1, 0,
71, 40, 76, 106, 97, 118, 97, 47, 110, 105, 111, 47, 102, 105, 108, 101, 47, 80, 97, 116, 104, 59, 91,
66, 91, 76, 106, 97, 118, 97, 47, 110, 105, 111, 47, 102, 105, 108, 101, 47, 79, 112, 101, 110, 79, 112,
116, 105, 111, 110, 59, 41, 76, 106, 97, 118, 97, 47, 110, 105, 111, 47, 102, 105, 108, 101, 47, 80, 97,
116, 104, 59, 1, 0, 1, 98, 1, 0, 2, 91, 66, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1,
0, 15, 70, 105, 108, 101, 73, 111, 73, 109, 112, 108, 46, 106, 97, 118, 97, 0, 33, 0, 1, 0, 3, 0, 0, 0,
0, 0, 3, 0, 1, 0, 5, 0, 6, 0, 1, 0, 7, 0, 0, 0, 47, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 8, -79, 0, 0, 0,
2, 0, 10, 0, 0, 0, 6, 0, 1, 0, 0, 0, 7, 0, 11, 0, 0, 0, 12, 0, 1, 0, 0, 0, 5, 0, 12, 0, 13, 0, 0, 0, 9,
0, 14, 0, 15, 0, 1, 0, 7, 0, 0, 0, 98, 0, 3, 0, 2, 0, 0, 0, 18, -69, 0, 16, 89, 42, -73, 0, 18, -74, 0,
21, -72, 0, 25, -80, 76, 1, -80, 0, 1, 0, 0, 0, 14, 0, 15, 0, 31, 0, 3, 0, 10, 0, 0, 0, 14, 0, 3, 0, 0,
0, 11, 0, 15, 0, 12, 0, 16, 0, 13, 0, 11, 0, 0, 0, 22, 0, 2, 0, 0, 0, 18, 0, 33, 0, 34, 0, 0, 0, 16, 0,
2, 0, 35, 0, 36, 0, 1, 0, 37, 0, 0, 0, 6, 0, 1, 79, 7, 0, 31, 0, 9, 0, 38, 0, 39, 0, 1, 0, 7, 0, 0, 0,
119, 0, 3, 0, 3, 0, 0, 0, 25, -69, 0, 16, 89, 42, -73, 0, 18, -74, 0, 21, 43, 3, -67, 0, 40, -72, 0, 42,
87, 4, -84, 77, 3, -84, 0, 1, 0, 0, 0, 20, 0, 22, 0, 31, 0, 3, 0, 10, 0, 0, 0, 18, 0, 4, 0, 0, 0, 19, 0,
20, 0, 20, 0, 22, 0, 21, 0, 23, 0, 22, 0, 11, 0, 0, 0, 32, 0, 3, 0, 0, 0, 25, 0, 33, 0, 34, 0, 0, 0, 0,
0, 25, 0, 45, 0, 46, 0, 1, 0, 23, 0, 2, 0, 35, 0, 36, 0, 2, 0, 37, 0, 0, 0, 6, 0, 1, 86, 7, 0, 31, 0, 1,
0, 47, 0, 0, 0, 2, 0, 48 };
ClassLoader cl = IoTest.class.getClassLoader();
Class clc = ClassLoader.class;
java.lang.reflect.Method defineClass;
try {
defineClass = clc.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Failed finding defineClass", e);
} catch (SecurityException e) {
throw new RuntimeException("Failed finding defineClass", e);
}
defineClass.setAccessible(true);
try {
fileIoClass = (Class) defineClass.invoke(cl.getParent().getParent(), "org.tjj.starsector.FileIoImpl",
fileIoClassBytes, 0, fileIoClassBytes.length);
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed definingClass", e);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Failed definingClass", e);
} catch (java.lang.reflect.InvocationTargetException e) {
throw new RuntimeException("Failed definingClass", e);
}
try {
readMethod = fileIoClass.getDeclaredMethod("read", String.class);
writeMethod = fileIoClass.getDeclaredMethod("write", String.class, byte[].class);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Failed finding io methods", e);
} catch (SecurityException e) {
throw new RuntimeException("Failed finding io methods", e);
}
}
public static byte[] read(String path) {
try {
return (byte[]) readMethod.invoke(null, path);
} catch (IllegalAccessException e) {
} catch (IllegalArgumentException e) {
} catch (InvocationTargetException e) {
}
return null;
}
public static boolean write(String path, byte[] b) {
try {
return (Boolean) writeMethod.invoke(null, path, b);
} catch (IllegalAccessException e) {
} catch (IllegalArgumentException e) {
} catch (InvocationTargetException e) {
}
return false;
}
public IoTest() {
if (write("Test.txt", "Yep, Sandbox bypassed".getBytes())) {
Global.getLogger(IoTest.class).info("Successfully written file");
}
}
}