diegocmaia
diegocmaia

Reputation: 79

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?

Upvotes: 4

Views: 7836

Answers (3)

Jim Roseborough
Jim Roseborough

Reputation: 201

You can also use the equivalent syntax:

obj.test(obj)

It's the same as

obj:test()

You should be able to get at any filed or method of a Java class or instance, but in certain cases the extra argument is required, and the colon syntax is a convenient shortcut.

To illustrate, construct a class with various static and instance fields and methods such as this:

public static class MyClass {
    public static String variable = "variable-value";
    public String field = "field-value";
    public static String func() {
        return "function-result";
    }
    public String method() {
        return "method-result";
    }

If you coerce an instance of that class as in your example, here is syntax to access each:

Globals globals = JsePlatform.standardGlobals();

// Load an instance into globals
LuaValue instance = CoerceJavaToLua.coerce(new MyClass());
globals.set("obj", instance);
LuaValue chunk = globals.load(
        "print( obj );" +
        "print( obj.variable );" +
        "print( obj.field );" +
        "print( obj.func );" +
        "print( obj.method );" +
        "print( obj:method() );" + // same as 'obj.method(obj)'
        "print( obj.method(obj) );");
chunk.call();   

which for me produced

Example$MyClass@4554617c
variable-value
field-value
function: JavaMethod
function: JavaMethod
method-result
method-result

You may also want to just coerce the class instead. Everything can still be accessed except the field, which doesn't exist for a class:

// Load a class into globals, 'field' cannot be accessed
LuaValue cls = CoerceJavaToLua.coerce(MyClass.class);
globals.set("cls", cls);
chunk = globals.load(
        "print( cls );" +
        "print( cls.variable );" +
        "print( cls.func );" +
        "print( cls:func() );" + // same as 'cls.method(cls)'
        "print( cls.func(cls) );" +
        "print( cls.method );" +
        "print( cls.method(obj) );"); 
chunk.call();   

The output is:

class Example$MyClass
variable-value
function: JavaMethod
function-result
function-result
function: JavaMethod
method-result

Within lua, an instance can be constructed from a Java class via 'new', then it behaves like other Java instances:

// Construct an instance from a class using 'new'
chunk = globals.load(
        "print( cls.new );" +   
        "print( cls.new() );" +
        "print( cls.new().field );"); // etc.
chunk.call();   

and the output is

function: JavaConstructor
Example$MyClass@4b67cf4d
field-value

Upvotes: 3

Rochet2
Rochet2

Reputation: 1156

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.

Upvotes: 3

SevenDeLeven
SevenDeLeven

Reputation: 33

I dont do lua that much, but what you said you have to do is what works

LuaValue chunk = globals.load("obj:test()");

notice the colon, thats how the method should be called.

Like I said, I don't do much, but it looks like the way you have to do it is in that way

Upvotes: 0

Related Questions