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
jobject
types 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
boolean
or the boxedBoolean
.integer / number to any of
boolean
char
byte
short
int
long
float
double
or their boxed alternative. (Double
is preferred.)Trying to convert a number into an
Object
will always yield a boxedDouble
. So pay attention when you useObject::equals
for 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#createProxy
withparty.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#createProxy
withparty.iroiro.luajava.Lua.Conversion#SEMI
.Any type can get wrapped into a
LuaValue
.If all the above is not applicable, the result is
null
on 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