Search code examples
javalualuaj

LuaJ - Calling a Java method


I have a Java Class with a method called test:

public class MyClass() {
    public String test() {
        //Do Something
    }
}

Then, I want to call the test method in my Lua script. In order to do it, I did:

Globals globals = JsePlatform.standartGlobals();

LuaValue test = CoerceJavaToLua.coerce(new MyClass());
globals.set("obj", test);
LuaValue chunk = globals.load("obj.test()");
chunk.call();

When the Lua script is called, I got a bad argument error.

It only works when I use "obj:test()".

It's like I should pass the object in the first parameter.

Is there a way to do "obj.test()" work?


Solution

  • I can't find any examples of binding a static function of a class and calling it without an instance of the class. All examples everywhere, even when using static functions, pass an instance of the object. Thus I can not be 100% sure this is not possible to do (without editing luaj).

    Any static functions in libraries and examples are actually made with creating a dummy class for example see here http://luaj.cvs.sourceforge.net/viewvc/luaj/luaj-vm/examples/jse/hyperbolic.java?view=markup

    A closer look at the luaj source shows that luaj does not distinct between static and nonstatic functions in a class which means all are handled as nonstatic. See JavaClass.java getMethod function for more.

    Here is a rather simple example how you can accomplish what you wanted, but sadly it requires to not have a static method.

    package luaj;
    
    import org.luaj.vm2.*;
    import org.luaj.vm2.lib.*;
    import org.luaj.vm2.lib.jse.*;
    
    public class luaj {
    
        static final public class MyClass {
    
            public static int asd = 5;
    
            static public class Test extends ZeroArgFunction {
    
                @Override
                public LuaValue call() {
                    System.out.println("Worked");
                    return NIL;
                }
            }
        }
    
        public static void main(String[] args) {
            Globals globals = JsePlatform.standardGlobals();
            LuaValue test = CoerceJavaToLua.coerce(new MyClass());
            globals.set("obj", test);
            LuaTable t = new LuaTable();
            t.set("test", new MyClass.Test());
            t.set("__index", t);
            test.setmetatable(t);
            LuaValue chunk = globals.load("print('Testing', obj.asd) obj.test()");
            chunk.call();
        }
    }
    

    A similar approach can probably be done with using a static method by setting obj.test to a function that wraps the real obj.test and passes a new instance of MyClass to it thus "hiding" the passing of an instance.