1

I am attempting to use LuaJ with Scala. Most things work (actually all things work if you do them correctly!) but the simple task of setting object values has become incredibly complicated thanks to Scala's setter implementation.

Scala:

class TestObject {
  var x: Int = 0
}

Lua:

function myTestFunction(testObject) 
  testObject.x = 3
end

If I execute the script or line containing this Lua function and pass a coerced instance of TestObject to myTestFunction this causes an error in LuaJ. LuaJ is trying to direct-write the value, and Scala requires you to go through the implicitly-defined setter (with the horrible name x_=, which is not valid Lua so even attempting to call that as a function makes your Lua not parse).

As I said, there are workarounds for this, such as defining your own setter or using the @BeanProperty markup. They just make code that should be easy to write much more complicated:

Lua:

function myTestFunction(testObject) 
  testObject.setX(testObject, 3)
end

Does anybody know of a way to get luaj to implicitly call the setter for such assignments? Or where I might look in the luaj source code to perhaps implement such a thing?

Thanks!

2 Answers2

1

I must admit that I'm not too familiar with LuaJ, but the first thing that comes to my mind regarding your issue is to wrap the objects within proxy tables to ease interaction with the API. Depending upon what sort of needs you have, this solution may or may not be the best, but it could be a good temporary fix.

local mt = {}

function mt:__index(k)
    return self.o[k] -- Define how your getters work here.
end

function mt:__newindex(k, v)
    return self.o[k .. '_='](v) -- "object.k_=(v)"
end

local function proxy(o)
    return setmetatable({o = o}, mt)
end

-- ...

function myTestFunction(testObject) 
    testObject = proxy(testObject)
    testObject.x = 3
end

I believe this may be the least invasive way to solve your problem. As for modifying LuaJ's source code to better suit your needs, I had a quick look through the documentation and source code and found this, this, and this. My best guess says that line 71 of JavaInstance.java is where you'll find what you need to change, if Scala requires a different way of setting values.

    f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
Ryan Stein
  • 7,930
  • 3
  • 24
  • 38
0

Perhaps you should use the method syntax:

testObject:setX(3)

Note the colon ':' instead of the dot '.' which can be hard to distinguish in some editors.

This has the same effect as the function call:

testObject.setX(testObject, 3)

but is more readable.

It can also be used to call static methods on classes:

luajava.bindClass("java.net.InetAddress"):getLocalHost():getHostName()

The part to the left of the ':' is evaluated once, so a statement such as

x = abc[d+e+f]:foo()

will be evaluated as if it were

local tmp = abc[d+e+f]
x = tmp.foo(tmp)
Jim Roseborough
  • 201
  • 1
  • 4