问题
I am currently writing a game engine in Java using the LibGDX framework. For several months now, I have successfully used LuaJ 3.0 with my engine. I have had no problems getting scripts to run on Android (tested on two devices) or Desktop (in and out of Eclipse).
However, when I tried to deploy to Android today, I got the following error:
org.luaj.vm2.LuaError: script:2 vm error: java.lang.ClassNotFoundException: com.javamon.console.ScriptPlayerCreate
The line of the script causing this error is:
Result = luajava.bindClass("com.javamon.console.ScriptPlayerCreate")
This is typographically identical to the class supposedly "not found" on Android.
If I try to bind a regular java class, such as java.lang.ClassNotFoundException
, I don't get any error. However, this error does not occur on the Desktop version, whether run from within Eclipse or via a runnable *.jar.
Here is the stack trace, retrieved from LogCat:
org.luaj.vm2.LuaError: script:2 vm error: java.lang.ClassNotFoundException: com.javamon.console.ScriptPlayerCreate
at org.luaj.vm2.lib.jse.LuajavaLib.invoke(Unknown Source)
at org.luaj.vm2.lib.VarArgFunction.call(Unknown Source)
at org.luaj.vm2.LuaClosure.execute(Unknown Source)
at org.luaj.vm2.LuaClosure.call(Unknown Source)
at com.javamon.console.Script.runFunction(Script.java:91)
at com.javamon.console.Script.runFunction(Script.java:96)
at com.javamon.console.ScriptPlayerCreate.run(ScriptPlayerCreate.java:39)
What bothers me is the very last line. ScriptPlayerCreate
certainly exists -- it's running the very script that produces the error!
Things I have tried:
- Trying different versions of LuaJ
- Binding a different class within the
com.javamon
package (same problem) - Updating my ADT/SDK plugins
- Cleaning/rebuilding the project within Eclipse
- "Starting Over" (creating a new LibGDX project using the GUI tool, and manually importing my source files)
- Checking
classes.dex
--ScriptPlayerCreate
is certainly there - Testing on separate Android devices (Moto X and Incredible 2)
I would like to reiterate that I have successfully used LuaJ with Android for several months without incident. Additionally, I have not changed my scripting engine since my last (successful) Android deployment.
UPDATE
After trying to revert to backup versions of my app and Eclipse, the problem persists -- even on another computer. I am beginning to suspect that luajava.bindClass()
does not know how to interpret the contents of classes.dex
, and is instead searching for actual class files.
When I attempted to recompile some backup versions, I noticed that the recompiled version almost always has a smaller classes.dex
file than the backup. Perhaps something is wrong or has changed with Eclipse's/Android's compiler?
I tried manually inserting class files into the com/javamon/console/ folder within the APK, but of course that messes up the file integrity, and even after re-signing the app will not load. Any ideas?
回答1:
I got a similar problem,and I'd fix it
LuaJavaLib.java:202
original return Class.forName(name, true, ClassLoader.getSystemClassLoader());
change to return Class.forName(name, true, Thread.currentThread().getContextClassLoader());
回答2:
Reverting to LuaJ 2.0.1 solved the issue.
It appears that all versions of LuaJ above 2.0.1 have a different implementation of LuajavaLib.class
. In the new implementation, only Java system libraries can be accessed through luajava.bindClass()
, whereas in the older versions, bindClass()
permits access to local application classes as well. All other script functions behave normally; only luajava.bindClass()
is affected.
In the newer versions, if a class is not found in the Java system libraries, LuaJ apparently checks the local application directory. Because the Desktop project is a runnable *.jar and contains actual class
files, the Desktop version of the game would have worked properly in any version of LuaJ. Contrastingly, Android bundles everything in a classes.dex
file, which is not "searchable" in the file-path sense. Hence the ClassNotFoundException
.
Lastly: I have been using LuaJ successfully for months, so what changed? Apparently, when I upgraded to 3.0 several months ago, Eclipse never actually recognized the file change. It was only when I refreshed and cleaned the project that Eclipse realized a new version of LuaJ was present. Because the main project in LibGDX is source-files only (assets are in -android
), you almost never click "refresh". Thus, the LuaJ problem has been a time-bomb of sorts.
I plan on submitting a support ticket to the author so he can address this issue. Until he does, I advise Android developers to stay with LuaJ 2.0.1!
回答3:
Also you can fix it with your class Helper.
Create package: org.luaj.vm2.lib.jse
In this package create following class:
package org.luaj.vm2.lib.jse;
public class Helper {
public static JavaClass forClass(Class c) {
return JavaClass.forClass(c);
}
public Class<JavaClass> huskClass() {
return JavaClass.class;
}
}
Then create something like bridge class:
public class LuaBridge {
public Varargs getClass(String clazzName) {
try {
Class clazz = Class.forName(clazzName);
return Helper.forClass(clazz);
} catch (Exception e) {
e.printStackTrace();
Crashlytics.logException(e);
}
return null;
}
}
And now when you run your script you can pass instance to your lua script:
_globals = JsePlatform.standardGlobals();
_bridge = new LuaBridge();
//...
_globals.loadfile(scriptName)
.call(CoerceJavaToLua.coerce(_bridge));
Inside your LUA script:
First line:
local luaBridge = ...
-- some code here...
UserManager = luaBridge:getClass("com.dexode.cree.ScriptPlayerCreate")
-- used like luajava.bindClass("com.dexode.cree.ScriptPlayerCreate")
来源:https://stackoverflow.com/questions/23025835/luaj-and-android-cannot-bind-class