2

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?

Community
  • 1
  • 1
user3525774
  • 172
  • 7

3 Answers3

6

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

Cloudy Zheng
  • 61
  • 1
  • 1
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!

user3525774
  • 172
  • 7
1

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")
Gelldur
  • 11,187
  • 7
  • 57
  • 68