Type Conversions
Exchanging values between Java and Lua, we allow users to control how values are converted back and forth. You might want to read #Extra Lua Types first.
Java to Lua
When pushing a Java value onto the Lua stack, you can choose from doing a FULL conversion, a SEMI conversion or NONE of the conversions by supplying a second parameter of type Lua.Conversion.
| Java Types | NONE | SEMI | FULL | Conversion (if ever) |
|---|---|---|---|---|
null | ✅ | ✅ | ✅ | Lua nil |
LuaValue | 🟧 | 🟧 | 🟧 | Converted if sharing main state |
Boolean | ✅ | ✅ | Lua booleans | |
Character | ✅ | ✅ | lua_Integer or lua_Number | |
Boxed numerics (Integer...) | ✅ | ✅ | lua_Integer or lua_Number | |
String | ✅ | ✅ | Lua strings | |
JFunction | ✅ | ✅ | A Lua closure | |
| Java arrays | ✅ | Lua tables (index starting from 1) | ||
Collections<?> | ✅ | Lua tables (index starting from 1) | ||
Map<?, ?> | ✅ | Lua tables | ||
Class<?> | ✅ | jclass | ||
| Others | Proxied to the Java side | |||
Example: BigInteger | Proxied to the Java side | |||
Example: AtomicInteger | Proxied to the Java side |
TIP
For a SEMI-conversion, roughly speaking, immutable types are converted, while mutable types, as well as those types not having Lua counterparts, are not.
For a FULL-conversion, all values are recursively converted if possible. Note that we ignore entries in Map<?> with a null key or a null value.
When calling Java methods from Lua, we SEMI-convert the return value. Currently, there is no way to specify how you want the return value converted.
Examples
NONE:You cannot add
jobjecttypes up, even if their underlying class isInteger.javatry (Lua L = new Lua51()) { L.push(1, Lua.Conversion.NONE); L.setGlobal("i"); L.run("print(i:hashCode())"); assertThrows(LuaException.class, () -> L.run("print(i + 1)")); L.run("print(java.luaify(i) + 1)"); }1
2
3
4
5
6
7FULL:Changes in converted Lua objects are not propagated back to the original Java object.
javatry (Lua L = new Lua51()) { int[] array = new int[]{100}; L.push(array, Lua.Conversion.FULL); L.setGlobal("array"); L.run("array[1] = 1024"); assert 100 == array[0]; }1
2
3
4
5
6
7
Lua to Java
nil is converted to
null.boolean converted to
booleanor the boxedBoolean.integer / number to any of
booleancharbyteshortintlongfloatdoubleor their boxed alternative. (Doubleis preferred.)Trying to convert a number into an
Objectwill always yield a boxedDouble. So pay attention when you useObject::equalsfor example.string to
String.table to
Map<Object, Object>,List<Object>,Object[], (converted recursively withMap<Object, Object>preferred) or any interfaces.To convert tables into any interface, we call
party.iroiro.luajava.Lua#createProxywithparty.iroiro.luajava.Lua.Conversion#SEMI.jclass to
Class<?>.jobject to the underlying Java object.
function to a functional interface.
Actually, if the abstract methods in the target interfaces are all of the same name, the library also does the wrapping for you.
The wrapping is done by creating an intermediate Lua table and then calling
party.iroiro.luajava.Lua#createProxywithparty.iroiro.luajava.Lua.Conversion#SEMI.Any type can get wrapped into a
LuaValue.If all the above is not applicable, the result is
nullon the Java side.
WARNING
Currently, you cannot convert a C closure back to a JFunction, even if the closure simply wraps around JFunction.
64-Bit Integers
To ensure compatibility across Lua versions, this library uses double for most numbers. However, Lua 5.3 introduced an integer subtype for numbers, which allows usage of 64-bit integers in Lua (on 64-bit machines mostly). This library ensures that no truncation ever happens when casting between long and double (which can happen on 32-bit machines where long values get truncated to 32-bit Lua integers). To retrieve or push integer values that exceed the safe integer range of double numbers, you will need to use party.iroiro.luajava.Lua#push(long) and party.iroiro.luajava.Lua#toInteger.
Also, when passing values via proxies or Java calls on the Lua side, the values will get auto converted to ensure maximal precision. For example, the following Lua snippet passes 2^60 + 1 around correctly (which cannot fit into a double) when running with 64-bit Lua 5.3:
POW_2_60 = 1152921504606846976
Long = java.import('java.lang.Long')
l = Long(POW_2_60 + 1)
assert(l:toString() == "1152921504606846977")
assert(l:longValue() == 1152921504606846977)2
3
4
5