Dakusan Dakusan - 1 year ago 102
Java Question

LuaJ array/list type safety

So using LuaJ.

If I pass, from Java to Lua, a userdata

with type
, Luaj still allows insertion into that array of any type of object via the
function. For example:

Java code:

import java.util.ArrayList;
import org.luaj.vm2.Globals;
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.LuaValue;

ArrayList<Integer>ExampleList=new ArrayList<>();
LuaValue[] LuaParams=new LuaValue[] {

Globals globals=JsePlatform.standardGlobals();
try { globals.get("TestFunc").invoke(LuaValue.varargsOf(LuaParams)); }
catch(Exception e) {}


function TestFunc(arr)

Result of ExampleList:

new Integer(1),
new String("str"), //This should not be allowed!
new Integer(2)

That string should not have been allowed since
is a

Question: Is there any way to maintain type safety?

If it helps for testing, here is the code to add the lua script into lua memory (just before the

"function TestFunc(arr)\n"+
" arr:add(\"str\")\n"+
" arr:add(2);\n"+

Answer Source

After doing the research, I've found that it is not possible to find out what generic type an array is declared as. Java does not store that information within the object. During runtime, it just uses the type the array is declared as for the current variable reference.

All you can do is look at the objects inside of it to determine what it is supposed to be, but this is not foolproof.

If the array is defined within another object, then you can look at the parent object's fields to get the component/template/generic type of the array.

ArrayList reflection

[edit on 2016-07-06] Another suggested method that I was aware of was extending all list classes with an interface which actually stores the type of class. This wouldn't really be practical though for the project. After having given it thought, it makes sense why Java does not store the generic class type for a list.

The solution I ended up using was editing org.luaj.vm2.lib.jse.JavaMethod.invokeMethod(Object instance, Varargs args) with the following (after the Object[] a = convertArgs(args); line:

//If this is adding/setting to a list, make sure the object type matches the list's 0th object type
java.util.List TheInstanceList;
    instance instanceof java.util.List && //Object is a list
    java.util.Arrays.asList("add", "set").contains(method.getName()) && //Adding/setting to list
    (TheInstanceList=(java.util.List)instance).size()>0 && //List already has at least 1 item
    !a[a.length>1 ? 1 : 0].getClass().isInstance(TheInstanceList.get(0)) //New item does not match type of item #0
    return LuaValue.error(String.format(
            "list coercion error: %s is not instanceof %s",
            a[a.length>1 ? 1 : 0].getClass().getName(),

While this could be extended to account for matching parent classes by traversing up both object's extended-parent-type-list (everything before java.lang.Object) that would be less safe type-safety-wise than what we need for the project.

The solution I used from above is there specifically to weed out errors in LUA scripts before they are committed to production.

We may also end up needing to make a hack in which certain classes are considered one of their ancestor or inheritance classes when comparing.