| /* |
| * $Id: JavaModule.java 121 2012-01-22 01:40:14Z andre@naef.com $ |
| * See LICENSE.txt for license terms. |
| */ |
| |
| package com.naef.jnlua; |
| |
| import java.lang.reflect.Array; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.NavigableMap; |
| |
| import com.naef.jnlua.JavaReflector.Metamethod; |
| |
| /** |
| * Provides the Java module for Lua. The Java module contains Java functions for |
| * using Java in Lua. |
| */ |
| public class JavaModule { |
| // -- Static |
| private static final JavaModule INSTANCE = new JavaModule(); |
| private static final Map<String, Class<?>> PRIMITIVE_TYPES = new HashMap<String, Class<?>>(); |
| static { |
| PRIMITIVE_TYPES.put("boolean", Boolean.TYPE); |
| PRIMITIVE_TYPES.put("byte", Byte.TYPE); |
| PRIMITIVE_TYPES.put("char", Character.TYPE); |
| PRIMITIVE_TYPES.put("double", Double.TYPE); |
| PRIMITIVE_TYPES.put("float", Float.TYPE); |
| PRIMITIVE_TYPES.put("int", Integer.TYPE); |
| PRIMITIVE_TYPES.put("long", Long.TYPE); |
| PRIMITIVE_TYPES.put("short", Short.TYPE); |
| PRIMITIVE_TYPES.put("void", Void.TYPE); |
| } |
| private static final NamedJavaFunction[] EMPTY_MODULE = new NamedJavaFunction[0]; |
| |
| // -- State |
| private final NamedJavaFunction[] functions = { new Require(), new New(), |
| new InstanceOf(), new Cast(), new Proxy(), new Pairs(), |
| new IPairs(), new ToTable(), new Elements(), new Fields(), |
| new Methods(), new Properties() }; |
| |
| // -- Static methods |
| /** |
| * Returns the instance of the Java module. |
| * |
| * @return the instance |
| */ |
| public static JavaModule getInstance() { |
| return INSTANCE; |
| } |
| |
| // -- Construction |
| /** |
| * Singleton. |
| */ |
| private JavaModule() { |
| } |
| |
| // -- Operations |
| /** |
| * Opens this module in a Lua state. The method is invoked by |
| * {@link LuaState#openLibs()} or by |
| * {@link LuaState#openLib(com.naef.jnlua.LuaState.Library)} if |
| * {@link LuaState.Library#JAVA} is passed. |
| * |
| * @param luaState |
| * the Lua state to open in |
| */ |
| public void open(LuaState luaState) { |
| synchronized (luaState) { |
| luaState.register("java", functions); |
| luaState.pop(1); |
| } |
| } |
| |
| /** |
| * Returns a table-like Lua value for the specified map. The returned value |
| * corresponds to the return value of the <code>totable()</code> function |
| * provided by this Java module. |
| * |
| * @param map |
| * the map |
| * @return the table-like Lua value |
| */ |
| public TypedJavaObject toTable(Map<?, ?> map) { |
| return ToTable.toTable(map); |
| } |
| |
| /** |
| * Returns a table-like Lua value for the specified list. The returned value |
| * corresponds to the return value of the <code>totable()</code> function |
| * provided by this Java module. |
| * |
| * @param list |
| * the list |
| * @return the table-like Lua value |
| */ |
| public TypedJavaObject toTable(List<?> list) { |
| return ToTable.toTable(list); |
| } |
| |
| // -- Private methods |
| /** |
| * Loads a type. The named type is a primitive type or a class. |
| */ |
| private static Class<?> loadType(LuaState luaState, String typeName) { |
| Class<?> clazz; |
| if ((clazz = PRIMITIVE_TYPES.get(typeName)) != null) { |
| return clazz; |
| } |
| try { |
| clazz = luaState.getClassLoader().loadClass(typeName); |
| return clazz; |
| } catch (ClassNotFoundException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| // -- Nested types |
| /** |
| * Imports a Java class into the Lua namespace. Returns the class and a |
| * status code. The status code indicates if the class was stored in the Lua |
| * namespace. Primitive types and classes without a package are not stored |
| * in the Lua namespace. |
| */ |
| private static class Require implements NamedJavaFunction { |
| // -- JavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| // Check arguments |
| String className = luaState.checkString(1); |
| boolean doImport = luaState.checkBoolean(2, false); |
| |
| // Load |
| Class<?> clazz = loadType(luaState, className); |
| luaState.pushJavaObject(clazz); |
| |
| // Import |
| if (doImport) { |
| className = clazz.getName(); |
| int lastDotIndex = className.lastIndexOf('.'); |
| if (lastDotIndex >= 0) { |
| String packageName = className.substring(0, lastDotIndex); |
| className = className.substring(lastDotIndex + 1); |
| luaState.register(packageName, EMPTY_MODULE); |
| luaState.pushJavaObject(clazz); |
| luaState.setField(-2, className); |
| luaState.pop(1); |
| } else { |
| luaState.pushJavaObject(clazz); |
| luaState.setGlobal(className); |
| } |
| } |
| luaState.pushBoolean(doImport); |
| |
| // Return |
| return 2; |
| } |
| |
| @Override |
| public String getName() { |
| return "require"; |
| } |
| } |
| |
| /** |
| * Creates and returns a new Java object or array thereof. The first |
| * argument designates the type to instantiate, either as a class or a |
| * string. The remaining arguments are the dimensions. |
| */ |
| private static class New implements NamedJavaFunction { |
| // -- JavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| // Find class |
| Class<?> clazz; |
| if (luaState.isJavaObject(1, Class.class)) { |
| clazz = luaState.checkJavaObject(1, Class.class); |
| } else { |
| String className = luaState.checkString(1); |
| clazz = loadType(luaState, className); |
| } |
| |
| // Instantiate |
| Object object; |
| int dimensionCount = luaState.getTop() - 1; |
| switch (dimensionCount) { |
| case 0: |
| try { |
| object = clazz.newInstance(); |
| } catch (InstantiationException e) { |
| throw new RuntimeException(e); |
| } catch (IllegalAccessException e) { |
| throw new RuntimeException(e); |
| } |
| break; |
| case 1: |
| object = Array.newInstance(clazz, luaState.checkInteger(2)); |
| break; |
| default: |
| int[] dimensions = new int[dimensionCount]; |
| for (int i = 0; i < dimensionCount; i++) { |
| dimensions[i] = luaState.checkInteger(i + 2); |
| } |
| object = Array.newInstance(clazz, dimensions); |
| } |
| |
| // Return |
| luaState.pushJavaObject(object); |
| return 1; |
| } |
| |
| @Override |
| public String getName() { |
| return "new"; |
| } |
| } |
| |
| /** |
| * Returns whether an object is an instance of a type. The object is given |
| * as the first argument. the type is given as the second argument, either |
| * as a class or as a type name. |
| */ |
| private static class InstanceOf implements NamedJavaFunction { |
| // -- JavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| // Get the object |
| Object object = luaState.checkJavaObject(1, Object.class); |
| |
| // Find class |
| Class<?> clazz; |
| if (luaState.isJavaObject(2, Class.class)) { |
| clazz = luaState.checkJavaObject(2, Class.class); |
| } else { |
| String className = luaState.checkString(2); |
| clazz = loadType(luaState, className); |
| } |
| |
| // Type check |
| luaState.pushBoolean(clazz.isInstance(object)); |
| return 1; |
| } |
| |
| @Override |
| public String getName() { |
| return "instanceof"; |
| } |
| } |
| |
| /** |
| * Creates a typed Java object. |
| */ |
| private static class Cast implements NamedJavaFunction { |
| // -- NamedJavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| // Find class |
| final Class<?> clazz; |
| if (luaState.isJavaObject(2, Class.class)) { |
| clazz = luaState.checkJavaObject(2, Class.class); |
| } else { |
| String className = luaState.checkString(2); |
| clazz = loadType(luaState, className); |
| } |
| |
| // Get the object |
| final Object object = luaState.checkJavaObject(1, clazz); |
| |
| // Push result |
| luaState.pushJavaObject(new TypedJavaObject() { |
| @Override |
| public Object getObject() { |
| return object; |
| } |
| |
| @Override |
| public Class<?> getType() { |
| return clazz; |
| } |
| |
| @Override |
| public boolean isStrong() { |
| return false; |
| } |
| }); |
| return 1; |
| } |
| |
| @Override |
| public String getName() { |
| return "cast"; |
| } |
| } |
| |
| /** |
| * Creates a dynamic proxy object the implements a set of Java interfaces in |
| * Lua. |
| */ |
| private static class Proxy implements NamedJavaFunction { |
| // -- JavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| // Check table |
| luaState.checkType(1, LuaType.TABLE); |
| |
| // Get interfaces |
| int interfaceCount = luaState.getTop() - 1; |
| luaState.checkArg(2, interfaceCount > 0, "no interface specified"); |
| Class<?>[] interfaces = new Class<?>[interfaceCount]; |
| for (int i = 0; i < interfaceCount; i++) { |
| if (luaState.isJavaObject(i + 2, Class.class)) { |
| interfaces[i] = luaState |
| .checkJavaObject(i + 2, Class.class); |
| } else { |
| String interfaceName = luaState.checkString(i + 2); |
| interfaces[i] = loadType(luaState, interfaceName); |
| } |
| } |
| |
| // Create proxy |
| luaState.pushJavaObjectRaw(luaState.getProxy(1, interfaces)); |
| return 1; |
| } |
| |
| @Override |
| public String getName() { |
| return "proxy"; |
| } |
| } |
| |
| /** |
| * Provides an iterator for maps. For <code>NavigableMap</code> objects, the |
| * function returns a stateless iterator which allows concurrent |
| * modifications to the map. For other maps, the function returns an |
| * iterator based on <code>Iterator</code> which does not support concurrent |
| * modifications. |
| */ |
| private static class Pairs implements NamedJavaFunction { |
| // -- Static |
| private final JavaFunction navigableMapNext = new NavigableMapNext(); |
| |
| // -- JavaFunction methods |
| @SuppressWarnings("unchecked") |
| @Override |
| public int invoke(LuaState luaState) { |
| Map<Object, Object> map = luaState.checkJavaObject(1, Map.class); |
| luaState.checkArg(1, map != null, String.format( |
| "expected map, got %s", luaState.typeName(1))); |
| if (map instanceof NavigableMap) { |
| luaState.pushJavaFunction(navigableMapNext); |
| } else { |
| luaState |
| .pushJavaFunction(new MapNext(map.entrySet().iterator())); |
| } |
| luaState.pushJavaObject(map); |
| luaState.pushNil(); |
| return 3; |
| } |
| |
| @Override |
| public String getName() { |
| return "pairs"; |
| } |
| |
| /** |
| * Provides a stateful iterator function for maps. |
| */ |
| private static class MapNext implements JavaFunction { |
| // -- State |
| private Iterator<Map.Entry<Object, Object>> iterator; |
| |
| // -- Construction |
| /** |
| * Creates a new instance. |
| */ |
| public MapNext(Iterator<Map.Entry<Object, Object>> iterator) { |
| this.iterator = iterator; |
| } |
| |
| // -- JavaFunction methods |
| public int invoke(LuaState luaState) { |
| if (iterator.hasNext()) { |
| Map.Entry<Object, Object> entry = iterator.next(); |
| luaState.pushJavaObject(entry.getKey()); |
| luaState.pushJavaObject(entry.getValue()); |
| return 2; |
| } else { |
| luaState.pushNil(); |
| return 1; |
| } |
| } |
| } |
| |
| /** |
| * Provides a stateless iterator function for navigable maps. |
| */ |
| private static class NavigableMapNext implements JavaFunction { |
| // -- JavaFunction methods |
| @SuppressWarnings("unchecked") |
| public int invoke(LuaState luaState) { |
| NavigableMap<Object, Object> navigableMap = luaState |
| .checkJavaObject(1, NavigableMap.class); |
| Object key = luaState.checkJavaObject(2, Object.class); |
| Map.Entry<Object, Object> entry; |
| if (key != null) { |
| entry = navigableMap.higherEntry(key); |
| } else { |
| entry = navigableMap.firstEntry(); |
| } |
| if (entry != null) { |
| luaState.pushJavaObject(entry.getKey()); |
| luaState.pushJavaObject(entry.getValue()); |
| return 2; |
| } else { |
| luaState.pushNil(); |
| return 1; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Provides an iterator for lists and arrays. |
| */ |
| private static class IPairs implements NamedJavaFunction { |
| // -- Static |
| private final JavaFunction listNext = new ListNext(); |
| private final JavaFunction arrayNext = new ArrayNext(); |
| |
| // -- JavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| Object object; |
| if (luaState.isJavaObject(1, List.class)) { |
| object = luaState.toJavaObject(1, List.class); |
| luaState.pushJavaFunction(listNext); |
| } else { |
| object = luaState.checkJavaObject(1, Object.class); |
| luaState.checkArg(1, object.getClass().isArray(), String |
| .format("expected list or array, got %s", luaState |
| .typeName(1))); |
| luaState.pushJavaFunction(arrayNext); |
| } |
| luaState.pushJavaObject(object); |
| luaState.pushInteger(0); |
| return 3; |
| } |
| |
| @Override |
| public String getName() { |
| return "ipairs"; |
| } |
| |
| /** |
| * Provides a stateless iterator function for lists. |
| */ |
| private static class ListNext implements JavaFunction { |
| public int invoke(LuaState luaState) { |
| List<?> list = luaState.checkJavaObject(1, List.class); |
| int size = list.size(); |
| int index = luaState.checkInteger(2); |
| index++; |
| if (index >= 1 && index <= size) { |
| luaState.pushInteger(index); |
| luaState.pushJavaObject(list.get(index - 1)); |
| return 2; |
| } else { |
| luaState.pushNil(); |
| return 1; |
| } |
| } |
| } |
| |
| /** |
| * Provides a stateless iterator function for arrays. |
| */ |
| private static class ArrayNext implements JavaFunction { |
| public int invoke(LuaState luaState) { |
| Object array = luaState.checkJavaObject(1, Object.class); |
| int length = java.lang.reflect.Array.getLength(array); |
| int index = luaState.checkInteger(2); |
| index++; |
| if (index >= 1 && index <= length) { |
| luaState.pushInteger(index); |
| luaState.pushJavaObject(Array.get(array, index - 1)); |
| return 2; |
| } else { |
| luaState.pushNil(); |
| return 1; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Provides a wrapper object for table-like map and list access from Lua. |
| */ |
| private static class ToTable implements NamedJavaFunction { |
| // -- Static methods |
| /** |
| * Returns a table-like Lua value for the specified map. |
| */ |
| @SuppressWarnings("unchecked") |
| public static TypedJavaObject toTable(Map<?, ?> map) { |
| return new LuaMap((Map<Object, Object>) map); |
| } |
| |
| /** |
| * Returns a table-list Lua value for the specified list. |
| */ |
| @SuppressWarnings("unchecked") |
| public static TypedJavaObject toTable(List<?> list) { |
| return new LuaList((List<Object>) list); |
| } |
| |
| // -- JavaFunction methods |
| @SuppressWarnings("unchecked") |
| @Override |
| public int invoke(LuaState luaState) { |
| if (luaState.isJavaObject(1, Map.class)) { |
| Map<Object, Object> map = luaState.toJavaObject(1, Map.class); |
| luaState.pushJavaObject(new LuaMap(map)); |
| } else if (luaState.isJavaObject(1, List.class)) { |
| List<Object> list = luaState.toJavaObject(1, List.class); |
| luaState.pushJavaObject(new LuaList(list)); |
| } else { |
| luaState.checkArg(1, false, String.format( |
| "expected map or list, got %s", luaState.typeName(1))); |
| } |
| return 1; |
| } |
| |
| @Override |
| public String getName() { |
| return "totable"; |
| } |
| |
| // -- Member types |
| /** |
| * Provides table-like access in Lua to a Java map. |
| */ |
| private static class LuaMap implements JavaReflector, TypedJavaObject { |
| // -- Static |
| private static final JavaFunction INDEX = new Index(); |
| private static final JavaFunction NEW_INDEX = new NewIndex(); |
| |
| // -- State |
| private Map<Object, Object> map; |
| |
| // -- Construction |
| /** |
| * Creates a new instance. |
| */ |
| public LuaMap(Map<Object, Object> map) { |
| this.map = map; |
| } |
| |
| // -- Properties |
| /** |
| * Returns the map. |
| */ |
| public Map<Object, Object> getMap() { |
| return map; |
| } |
| |
| // -- JavaReflector methods |
| @Override |
| public JavaFunction getMetamethod(Metamethod metamethod) { |
| switch (metamethod) { |
| case INDEX: |
| return INDEX; |
| case NEWINDEX: |
| return NEW_INDEX; |
| default: |
| return null; |
| } |
| } |
| |
| // -- TypedJavaObject methods |
| @Override |
| public Object getObject() { |
| return map; |
| } |
| |
| @Override |
| public Class<?> getType() { |
| return Map.class; |
| } |
| |
| @Override |
| public boolean isStrong() { |
| return true; |
| } |
| |
| // -- Member types |
| /** |
| * __index implementation for maps. |
| */ |
| private static class Index implements JavaFunction { |
| // -- JavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| LuaMap luaMap = (LuaMap) luaState.toJavaObjectRaw(1); |
| Object key = luaState.toJavaObject(2, Object.class); |
| if (key == null) { |
| throw new LuaRuntimeException(String.format( |
| "attempt to read map with %s accessor", |
| luaState.typeName(2))); |
| } |
| luaState.pushJavaObject(luaMap.getMap().get(key)); |
| return 1; |
| } |
| } |
| |
| /** |
| * __newindex implementation for maps. |
| */ |
| private static class NewIndex implements JavaFunction { |
| // -- JavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| LuaMap luaMap = (LuaMap) luaState.toJavaObjectRaw(1); |
| Object key = luaState.toJavaObject(2, Object.class); |
| if (key == null) { |
| throw new LuaRuntimeException(String.format( |
| "attempt to write map with %s accessor", |
| luaState.typeName(2))); |
| } |
| Object value = luaState.toJavaObject(3, Object.class); |
| if (value != null) { |
| luaMap.getMap().put(key, value); |
| } else { |
| luaMap.getMap().remove(key); |
| } |
| return 0; |
| } |
| } |
| } |
| |
| /** |
| * Provides table-like access in Lua to a Java list. |
| */ |
| private static class LuaList implements JavaReflector, TypedJavaObject { |
| // -- Static |
| private static final JavaFunction INDEX = new Index(); |
| private static final JavaFunction NEW_INDEX = new NewIndex(); |
| private static final JavaFunction LENGTH = new Length(); |
| |
| // -- State |
| private List<Object> list; |
| |
| // -- Construction |
| /** |
| * Creates a new instance. |
| */ |
| public LuaList(List<Object> list) { |
| this.list = list; |
| } |
| |
| // -- Properties |
| /** |
| * Returns the map. |
| */ |
| public List<Object> getList() { |
| return list; |
| } |
| |
| // -- JavaReflector methods |
| @Override |
| public JavaFunction getMetamethod(Metamethod metamethod) { |
| switch (metamethod) { |
| case INDEX: |
| return INDEX; |
| case NEWINDEX: |
| return NEW_INDEX; |
| case LEN: |
| return LENGTH; |
| default: |
| return null; |
| } |
| } |
| |
| // -- TypedJavaObject methods |
| @Override |
| public Object getObject() { |
| return list; |
| } |
| |
| @Override |
| public Class<?> getType() { |
| return List.class; |
| } |
| |
| @Override |
| public boolean isStrong() { |
| return true; |
| } |
| |
| // -- Member types |
| /** |
| * __index implementation for lists. |
| */ |
| private static class Index implements JavaFunction { |
| // -- JavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| LuaList luaList = (LuaList) luaState.toJavaObjectRaw(1); |
| if (!luaState.isNumber(2)) { |
| throw new LuaRuntimeException(String.format( |
| "attempt to read list with %s accessor", |
| luaState.typeName(2))); |
| } |
| int index = luaState.toInteger(2); |
| luaState.pushJavaObject(luaList.getList().get(index - 1)); |
| return 1; |
| } |
| } |
| |
| /** |
| * __newindex implementation for lists. |
| */ |
| private static class NewIndex implements JavaFunction { |
| // -- JavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| LuaList luaList = (LuaList) luaState.toJavaObjectRaw(1); |
| if (!luaState.isNumber(2)) { |
| throw new LuaRuntimeException(String.format( |
| "attempt to write list with %s accessor", |
| luaState.typeName(2))); |
| } |
| int index = luaState.toInteger(2); |
| Object value = luaState.toJavaObject(3, Object.class); |
| if (value != null) { |
| int size = luaList.getList().size(); |
| if (index - 1 != size) { |
| luaList.getList().set(index - 1, value); |
| } else { |
| luaList.getList().add(value); |
| } |
| } else { |
| luaList.getList().remove(index - 1); |
| } |
| return 0; |
| } |
| } |
| |
| /** |
| * __len implementation for lists. |
| */ |
| private static class Length implements JavaFunction { |
| // -- JavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| LuaList luaList = (LuaList) luaState.toJavaObjectRaw(1); |
| luaState.pushInteger(luaList.getList().size()); |
| return 1; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Provides an iterator for Iterable objects. |
| */ |
| private static class Elements implements NamedJavaFunction { |
| // -- NamedJavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| Iterable<?> iterable = luaState.checkJavaObject(1, Iterable.class); |
| luaState.pushJavaObject(new ElementIterator(iterable.iterator())); |
| luaState.pushJavaObject(iterable); |
| luaState.pushNil(); |
| return 3; |
| } |
| |
| @Override |
| public String getName() { |
| return "elements"; |
| } |
| |
| // -- Member types |
| private static class ElementIterator implements JavaFunction { |
| // -- State |
| private Iterator<?> iterator; |
| |
| // -- Construction |
| /** |
| * Creates a new instance. |
| */ |
| public ElementIterator(Iterator<?> iterator) { |
| this.iterator = iterator; |
| } |
| |
| // -- JavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| if (iterator.hasNext()) { |
| luaState.pushJavaObject(iterator.next()); |
| } else { |
| luaState.pushNil(); |
| } |
| return 1; |
| } |
| } |
| } |
| |
| /** |
| * Provides an iterator for Java object fields. |
| */ |
| private static class Fields implements NamedJavaFunction { |
| // -- NamedJavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| luaState.checkArg(1, luaState.isJavaObjectRaw(1), String.format( |
| "expected Java object, got %s", luaState.typeName(1))); |
| JavaFunction metamethod = luaState.getMetamethod(luaState |
| .toJavaObjectRaw(1), Metamethod.JAVAFIELDS); |
| return metamethod.invoke(luaState); |
| } |
| |
| @Override |
| public String getName() { |
| return "fields"; |
| } |
| } |
| |
| /** |
| * Provides an iterator for Java methods. |
| */ |
| private static class Methods implements NamedJavaFunction { |
| // -- NamedJavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| luaState.checkArg(1, luaState.isJavaObjectRaw(1), String.format( |
| "expected Java object, got %s", luaState.typeName(1))); |
| JavaFunction metamethod = luaState.getMetamethod(luaState |
| .toJavaObjectRaw(1), Metamethod.JAVAMETHODS); |
| return metamethod.invoke(luaState); |
| } |
| |
| @Override |
| public String getName() { |
| return "methods"; |
| } |
| } |
| |
| /** |
| * Provides an iterator for Java object properties. |
| */ |
| private static class Properties implements NamedJavaFunction { |
| // -- NamedJavaFunction methods |
| @Override |
| public int invoke(LuaState luaState) { |
| luaState.checkArg(1, luaState.isJavaObjectRaw(1), String.format( |
| "expected Java object, got %s", luaState.typeName(1))); |
| JavaFunction metamethod = luaState.getMetamethod(luaState |
| .toJavaObjectRaw(1), Metamethod.JAVAPROPERTIES); |
| return metamethod.invoke(luaState); |
| } |
| |
| @Override |
| public String getName() { |
| return "properties"; |
| } |
| } |
| } |