Major refactor of luajava type coercion logic, and method selection logic.

This commit is contained in:
James Roseborough
2011-03-03 16:52:12 +00:00
parent f335a25e6b
commit a88789517d
14 changed files with 1240 additions and 595 deletions

View File

@@ -21,12 +21,15 @@
******************************************************************************/
package org.luaj.vm2.lib.jse;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Map;
import org.luaj.vm2.LuaDouble;
import org.luaj.vm2.LuaInteger;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaUserdata;
import org.luaj.vm2.LuaValue;
/**
@@ -103,6 +106,7 @@ public class CoerceJavaToLua {
COERCIONS.put( Character.class, charCoercion );
COERCIONS.put( Short.class, intCoercion );
COERCIONS.put( Integer.class, intCoercion );
COERCIONS.put( Long.class, doubleCoercion );
COERCIONS.put( Float.class, doubleCoercion );
COERCIONS.put( Double.class, doubleCoercion );
COERCIONS.put( String.class, stringCoercion );
@@ -129,9 +133,25 @@ public class CoerceJavaToLua {
return LuaValue.NIL;
Class clazz = o.getClass();
Coercion c = (Coercion) COERCIONS.get( clazz );
if ( c != null )
return c.coerce( o );
return LuajavaLib.toUserdata( o, clazz );
if ( c == null ) {
c = o instanceof Class? JavaClass.forClass((Class)o):
clazz.isArray()? arrayCoercion:
instanceCoercion;
COERCIONS.put( clazz, c );
}
return c.coerce(o);
}
static final Coercion instanceCoercion = new Coercion() {
public LuaValue coerce(Object javaValue) {
return new JavaInstance(javaValue);
}
};
// should be userdata?
static final Coercion arrayCoercion = new Coercion() {
public LuaValue coerce(Object javaValue) {
return new JavaArray(javaValue);
}
};
}

View File

@@ -22,10 +22,16 @@
package org.luaj.vm2.lib.jse;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
@@ -58,187 +64,272 @@ import org.luaj.vm2.Varargs;
*/
public class CoerceLuaToJava {
static int SCORE_NULL_VALUE = 0x10;
static int SCORE_WRONG_TYPE = 0x100;
static int SCORE_UNCOERCIBLE = 0x10000;
static interface Coercion {
public int score( LuaValue value );
public Object coerce( LuaValue value );
public int score( int paramType );
};
/**
* Coerce a LuaValue value to a specified java class
* @param value LuaValue to coerce
* @param clazz Class to coerce into
* @return Object of type clazz (or a subclass) with the corresponding value.
*/
public static Object coerce(LuaValue value, Class clazz) {
return getCoercion(clazz).coerce(value);
}
static final Map COERCIONS = new HashMap();
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
static {
Coercion boolCoercion = new Coercion() {
public Object coerce(LuaValue value) {
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
}
public int score(int paramType) {
switch ( paramType ) {
case LuaValue.TNIL:
case LuaValue.TBOOLEAN:
return 0;
case LuaValue.TINT:
case LuaValue.TNUMBER:
return 1;
default:
return 4;
static final class BoolCoercion implements Coercion {
public String toString() {
return "BoolCoercion()";
}
public int score( LuaValue value ) {
switch ( value.type() ) {
case LuaValue.TBOOLEAN:
return 0;
}
return 1;
}
public Object coerce(LuaValue value) {
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
}
}
static final class NumericCoercion implements Coercion {
static final int TARGET_TYPE_BYTE = 0;
static final int TARGET_TYPE_CHAR = 1;
static final int TARGET_TYPE_SHORT = 2;
static final int TARGET_TYPE_INT = 3;
static final int TARGET_TYPE_LONG = 4;
static final int TARGET_TYPE_FLOAT = 5;
static final int TARGET_TYPE_DOUBLE = 6;
static final String[] TYPE_NAMES = { "byte", "char", "short", "int", "long", "float", "double" };
final int targetType;
public String toString() {
return "NumericCoercion("+TYPE_NAMES[targetType]+")";
}
NumericCoercion(int targetType) {
this.targetType = targetType;
}
public int score( LuaValue value ) {
if ( value.isint() ) {
switch ( targetType ) {
case TARGET_TYPE_BYTE: {
int i = value.toint();
return (i==(byte)i)? 0: SCORE_WRONG_TYPE;
}
}
};
Coercion byteCoercion = new Coercion() {
public Object coerce(LuaValue value) {
return new Byte( (byte) value.toint() );
}
public int score(int paramType) {
switch ( paramType ) {
case LuaValue.TINT:
return 1;
case LuaValue.TNUMBER:
return 2;
default:
return 4;
case TARGET_TYPE_CHAR: {
int i = value.toint();
return (i==(byte)i)? 1: (i==(char)i)? 0: SCORE_WRONG_TYPE;
}
}
};
Coercion charCoercion = new Coercion() {
public Object coerce(LuaValue value) {
return new Character( (char) value.toint() );
}
public int score(int paramType) {
switch ( paramType ) {
case LuaValue.TINT:
return 1;
case LuaValue.TNUMBER:
return 2;
default:
return 4;
case TARGET_TYPE_SHORT: {
int i = value.toint();
return (i==(byte)i)? 1: (i==(short)i)? 0: SCORE_WRONG_TYPE;
}
}
};
Coercion shortCoercion = new Coercion() {
public Object coerce(LuaValue value) {
return new Short( (short) value.toint() );
}
public int score(int paramType) {
switch ( paramType ) {
case LuaValue.TINT:
return 1;
case LuaValue.TNUMBER:
return 2;
default:
return 4;
case TARGET_TYPE_INT: {
int i = value.toint();
return (i==(byte)i)? 2: ((i==(char)i) || (i==(short)i))? 1: 0;
}
}
};
Coercion intCoercion = new Coercion() {
public Object coerce(LuaValue value) {
return new Integer( value.toint() );
}
public int score(int paramType) {
switch ( paramType ) {
case LuaValue.TINT:
return 0;
case LuaValue.TNUMBER:
return 1;
case LuaValue.TBOOLEAN:
case LuaValue.TNIL:
return 2;
default:
return 4;
case TARGET_TYPE_FLOAT: return 1;
case TARGET_TYPE_LONG: return 1;
case TARGET_TYPE_DOUBLE: return 2;
default: return SCORE_WRONG_TYPE;
}
}
};
Coercion longCoercion = new Coercion() {
public Object coerce(LuaValue value) {
return new Long( value.tolong() );
}
public int score(int paramType) {
switch ( paramType ) {
case LuaValue.TINT:
return 1;
case LuaValue.TNUMBER:
return 2;
default:
return 4;
} else if ( value.isnumber() ) {
switch ( targetType ) {
case TARGET_TYPE_BYTE: return SCORE_WRONG_TYPE;
case TARGET_TYPE_CHAR: return SCORE_WRONG_TYPE;
case TARGET_TYPE_SHORT: return SCORE_WRONG_TYPE;
case TARGET_TYPE_INT: return SCORE_WRONG_TYPE;
case TARGET_TYPE_LONG: {
double d = value.todouble();
return (d==(long)d)? 0: SCORE_WRONG_TYPE;
}
}
};
Coercion floatCoercion = new Coercion() {
public Object coerce(LuaValue value) {
return new Float( value.tofloat() );
}
public int score( int paramType ) {
switch ( paramType ) {
case LuaValue.TINT:
case LuaValue.TNUMBER:
return 1;
case LuaValue.TBOOLEAN:
return 2;
default:
return 4;
case TARGET_TYPE_FLOAT: {
double d = value.todouble();
return (d==(float)d)? 0: SCORE_WRONG_TYPE;
}
}
};
Coercion doubleCoercion = new Coercion() {
public Object coerce(LuaValue value) {
return new Double( value.todouble() );
}
public int score(int paramType) {
switch ( paramType ) {
case LuaValue.TINT:
return 1;
case LuaValue.TNUMBER:
return 0;
case LuaValue.TBOOLEAN:
return 2;
default:
return 4;
case TARGET_TYPE_DOUBLE: {
double d = value.todouble();
return ((d==(long)d) || (d==(float)d))? 1: 0;
}
default: return SCORE_WRONG_TYPE;
}
} else {
return SCORE_UNCOERCIBLE;
}
};
Coercion stringCoercion = new Coercion() {
public Object coerce(LuaValue value) {
}
public Object coerce(LuaValue value) {
switch ( targetType ) {
case TARGET_TYPE_BYTE: return new Byte( (byte) value.toint() );
case TARGET_TYPE_CHAR: return new Character( (char) value.toint() );
case TARGET_TYPE_SHORT: return new Short( (short) value.toint() );
case TARGET_TYPE_INT: return new Integer( (int) value.toint() );
case TARGET_TYPE_LONG: return new Long( (long) value.todouble() );
case TARGET_TYPE_FLOAT: return new Float( (float) value.todouble() );
case TARGET_TYPE_DOUBLE: return new Double( (double) value.todouble() );
default: return null;
}
}
}
static final class StringCoercion implements Coercion {
public static final int TARGET_TYPE_STRING = 0;
public static final int TARGET_TYPE_BYTES = 1;
final int targetType;
public StringCoercion(int targetType) {
this.targetType = targetType;
}
public String toString() {
return "StringCoercion("+(targetType==TARGET_TYPE_STRING? "String": "byte[]")+")";
}
public int score(LuaValue value) {
switch ( value.type() ) {
case LuaValue.TSTRING:
return value.checkstring().isValidUtf8()?
(targetType==TARGET_TYPE_STRING? 0: 1):
(targetType==TARGET_TYPE_BYTES? 0: SCORE_WRONG_TYPE);
case LuaValue.TNIL:
return SCORE_NULL_VALUE;
default:
return targetType == TARGET_TYPE_STRING? SCORE_WRONG_TYPE: SCORE_UNCOERCIBLE;
}
}
public Object coerce(LuaValue value) {
if ( value.isnil() )
return null;
if ( targetType == TARGET_TYPE_STRING )
return value.tojstring();
}
public int score(int paramType) {
switch ( paramType ) {
case LuaValue.TSTRING:
return 0;
case LuaValue.TUSERDATA:
return 1;
default:
return 2;
}
LuaString s = value.checkstring();
byte[] b = new byte[s.m_length];
s.copyInto(0, b, 0, b.length);
return b;
}
}
static final class ArrayCoercion implements Coercion {
final Class componentType;
final Coercion componentCoercion;
public ArrayCoercion(Class componentType) {
this.componentType = componentType;
this.componentCoercion = getCoercion(componentType);
}
public String toString() {
return "ArrayCoercion("+componentType.getName()+")";
}
public int score(LuaValue value) {
switch ( value.type() ) {
case LuaValue.TTABLE:
return value.length()==0? 0: componentCoercion.score( value.get(1) );
case LuaValue.TUSERDATA:
return inheritanceLevels( componentType, value.touserdata().getClass().getComponentType() );
case LuaValue.TNIL:
return SCORE_NULL_VALUE;
default:
return SCORE_UNCOERCIBLE;
}
};
Coercion objectCoercion = new Coercion() {
public Object coerce(LuaValue value) {
switch ( value.type() ) {
case LuaValue.TUSERDATA:
return value.optuserdata(Object.class, null);
case LuaValue.TSTRING:
return value.tojstring();
case LuaValue.TINT:
return new Integer(value.toint());
case LuaValue.TNUMBER:
return new Double(value.todouble());
case LuaValue.TBOOLEAN:
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
case LuaValue.TNIL:
return null;
default:
return value;
}
}
public int score(int paramType) {
switch ( paramType ) {
case LuaValue.TUSERDATA:
return 0;
case LuaValue.TSTRING:
return 1;
default:
return 0x10;
}
}
public Object coerce(LuaValue value) {
switch ( value.type() ) {
case LuaValue.TTABLE: {
int n = value.length();
Object a = Array.newInstance(componentType, n);
for ( int i=0; i<n; i++ )
Array.set(a, i, componentCoercion.coerce(value.get(i+1)));
return a;
}
};
case LuaValue.TUSERDATA:
return value.touserdata();
case LuaValue.TNIL:
return null;
default:
return null;
}
}
}
/**
* Determine levels of inheritance between a base class and a subclass
* @param baseclass base class to look for
* @param subclass class from which to start looking
* @return number of inheritance levels between subclass and baseclass,
* or SCORE_UNCOERCIBLE if not a subclass
*/
static final int inheritanceLevels( Class baseclass, Class subclass ) {
if ( subclass == null )
return SCORE_UNCOERCIBLE;
if ( baseclass == subclass )
return 0;
int min = Math.min( SCORE_UNCOERCIBLE, inheritanceLevels( baseclass, subclass.getSuperclass() ) + 1 );
Class[] ifaces = subclass.getInterfaces();
for ( int i=0; i<ifaces.length; i++ )
min = Math.min(min, inheritanceLevels(baseclass, ifaces[i]) + 1 );
return min;
}
static final class ObjectCoercion implements Coercion {
final Class targetType;
ObjectCoercion(Class targetType) {
this.targetType = targetType;
}
public String toString() {
return "ObjectCoercion("+targetType.getName()+")";
}
public int score(LuaValue value) {
switch ( value.type() ) {
case LuaValue.TNUMBER:
return inheritanceLevels( targetType, value.isint()? Integer.class: Double.class );
case LuaValue.TBOOLEAN:
return inheritanceLevels( targetType, Boolean.class );
case LuaValue.TSTRING:
return inheritanceLevels( targetType, String.class );
case LuaValue.TUSERDATA:
return inheritanceLevels( targetType, value.touserdata().getClass() );
case LuaValue.TNIL:
return SCORE_NULL_VALUE;
default:
return inheritanceLevels( targetType, value.getClass() );
}
}
public Object coerce(LuaValue value) {
switch ( value.type() ) {
case LuaValue.TNUMBER:
return value.isint()? (Object)new Integer(value.toint()): (Object)new Double(value.todouble());
case LuaValue.TBOOLEAN:
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
case LuaValue.TSTRING:
return value.tojstring();
case LuaValue.TUSERDATA:
return value.optuserdata(targetType, null);
case LuaValue.TNIL:
return null;
default:
return value;
}
}
}
static {
Coercion boolCoercion = new BoolCoercion();
Coercion byteCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_BYTE);
Coercion charCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_CHAR);
Coercion shortCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_SHORT);
Coercion intCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_INT);
Coercion longCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_LONG);
Coercion floatCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_FLOAT);
Coercion doubleCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_DOUBLE);
Coercion stringCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_STRING);
Coercion bytesCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_BYTES);
COERCIONS.put( Boolean.TYPE, boolCoercion );
COERCIONS.put( Boolean.class, boolCoercion );
COERCIONS.put( Byte.TYPE, byteCoercion );
@@ -256,95 +347,21 @@ public class CoerceLuaToJava {
COERCIONS.put( Double.TYPE, doubleCoercion );
COERCIONS.put( Double.class, doubleCoercion );
COERCIONS.put( String.class, stringCoercion );
COERCIONS.put( Object.class, objectCoercion );
COERCIONS.put( byte[].class, bytesCoercion );
}
/** Score a single parameter, including array handling */
static int scoreParam(int paramType, Class c) {
if ( paramType == LuaValue.TUSERDATA && !c.isArray() )
return 0;
static Coercion getCoercion(Class c) {
Coercion co = (Coercion) COERCIONS.get( c );
if ( co != null ) {
int b = LuajavaLib.paramBaseTypeFromParamType(paramType);
int d = LuajavaLib.paramDepthFromParamType(paramType);
int s = co.score(b);
return s * (d+1);
return co;
}
if ( c.isArray() ) {
Class typ = c.getComponentType();
int d = LuajavaLib.paramDepthFromParamType(paramType);
if ( d > 0 )
return scoreParam( LuajavaLib.paramComponentTypeOfParamType(paramType), typ );
else
return 0x10 + (scoreParam(paramType, typ) << 8);
co = new ArrayCoercion(c.getComponentType());
} else {
co = new ObjectCoercion(c);
}
return 0x1000;
}
/** Do a conversion */
static Object coerceArg(LuaValue a, Class c) {
if ( a.isuserdata(c) )
return a.touserdata(c);
Coercion co = (Coercion) COERCIONS.get( c );
if ( co != null ) {
return co.coerce( a );
}
if ( c.isArray() ) {
boolean istable = a.istable();
int n = istable? a.length(): 1;
Class typ = c.getComponentType();
Object arr = Array.newInstance(typ, n);
for ( int i=0; i<n; i++ ) {
LuaValue ele = (istable? a.checktable().get(i+1): a);
if ( ele != null )
Array.set(arr, i, coerceArg(ele, typ));
}
return arr;
}
if ( a.isnil() )
return null;
throw new LuaError("no coercion found for "+a.getClass()+" to "+c);
}
static Object[] coerceArgs(Varargs suppliedArgs, Class[] parameterTypes, boolean isvarargs) {
int nsupplied = suppliedArgs.narg();
int n = parameterTypes.length;
int nplain = Math.min(isvarargs? n-1: n, nsupplied);
Object[] args = new Object[n];
for ( int i=0; i<nplain; i++ )
args[i] = coerceArg( suppliedArgs.arg(i+1), parameterTypes[i] );
if ( isvarargs ) {
int nvar = Math.max(0, nsupplied - nplain);
Class typevar = parameterTypes[n-1].getComponentType();
Object array = Array.newInstance(typevar, nvar);
for ( int index=0; index<nvar; index++ ) {
Object value = coerceArg( suppliedArgs.arg(nplain+index+1), typevar );
Array.set(array, index, value);
}
args[n-1] = array;
}
return args;
}
/*
* Score parameter types for match with supplied parameter list
*
* 1) exact number of args
* 2) java has more args
* 3) java has less args
* 4) types coerce well
*/
static int scoreParamTypes(long paramssig, Class[] paramTypes) {
int nargs = LuajavaLib.paramsCountFromSig(paramssig);
int njava = paramTypes.length;
int score = (njava == nargs? 0: njava > nargs? 0x4000: 0x8000);
for ( int i=0; i<nargs && i<njava; i++ ) {
int paramType = LuajavaLib.paramTypeFromSig(paramssig, i);
Class c = paramTypes[i];
int s = scoreParam( paramType, c );
score += s;
}
return score;
COERCIONS.put( c, co );
return co;
}
}

View File

@@ -0,0 +1,65 @@
/*******************************************************************************
* Copyright (c) 2011 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lib.jse;
import java.lang.reflect.Array;
import org.luaj.vm2.LuaUserdata;
import org.luaj.vm2.LuaValue;
/**
* LuaValue that represents a Java instance of array type.
* <p>
* Can get elements by their integer key index, as well as the length.
*/
public class JavaArray extends LuaUserdata {
static final LuaValue LENGTH = valueOf("length");
JavaArray(Object instance) {
super(instance);
}
public LuaValue get(LuaValue key) {
if ( key.equals(LENGTH) )
return CoerceJavaToLua.coerce(Array.getLength(m_instance));
if ( key.isint() ) {
int i = key.toint() - 1;
return i>=0 && i<Array.getLength(m_instance)?
CoerceJavaToLua.coerce(Array.get(m_instance,key.toint()-1)):
NIL;
}
return super.get(key);
}
public void set(LuaValue key, LuaValue value) {
if ( key.isint() ) {
int i = key.toint() - 1;
if ( i>=0 && i<Array.getLength(m_instance) )
Array.set(m_instance,i,CoerceLuaToJava.coerce(value, m_instance.getClass().getComponentType()));
else if ( m_metatable==null || ! settable(this,key,value) )
error("array index out of bounds");
}
else
super.set(key, value);
}
}

View File

@@ -0,0 +1,124 @@
/*******************************************************************************
* Copyright (c) 2011 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lib.jse;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* LuaValue that represents a Java class.
* <p>
* Will respond to get() and set() by returning field values, or java methods.
*/
public class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
static final Map classes = Collections.synchronizedMap(new HashMap());
static final LuaValue NEW = valueOf("new");
Map fields;
Map methods;
static JavaClass forClass(Class c) {
JavaClass j = (JavaClass) classes.get(c);
if ( j == null )
classes.put( c, j = new JavaClass(c) );
return j;
}
JavaClass(Class c) {
super(c);
this.jclass = this;
}
public LuaValue coerce(Object javaValue) {
return this;
}
Field getField(LuaValue key) {
if ( fields == null ) {
Map m = new HashMap();
Field[] f = ((Class)m_instance).getFields();
for ( int i=0; i<f.length; i++ )
if ( Modifier.isPublic(f[i].getModifiers()) )
m.put( LuaValue.valueOf(f[i].getName()), f[i] );
fields = m;
}
return (Field) fields.get(key);
}
LuaValue getMethod(LuaValue key) {
if ( methods == null ) {
Map namedlists = new HashMap();
Method[] m = ((Class)m_instance).getMethods();
for ( int i=0; i<m.length; i++ ) {
Method mi = m[i];
if ( Modifier.isPublic( mi.getModifiers()) ) {
String name = mi.getName();
List list = (List) namedlists.get(name);
if ( list == null )
namedlists.put(name, list = new ArrayList());
list.add( JavaMethod.forMethod(mi) );
}
}
Map map = new HashMap();
Constructor[] c = ((Class)m_instance).getConstructors();
List list = new ArrayList();
for ( int i=0; i<c.length; i++ )
if ( Modifier.isPublic(c[i].getModifiers()) )
list.add( JavaConstructor.forConstructor(c[i]) );
switch ( list.size() ) {
case 0: break;
case 1: map.put(NEW, list.get(0)); break;
default: map.put(NEW, JavaConstructor.forConstructors( (JavaConstructor[])list.toArray(new JavaConstructor[list.size()]) ) ); break;
}
for ( Iterator it=namedlists.entrySet().iterator(); it.hasNext(); ) {
Entry e = (Entry) it.next();
String name = (String) e.getKey();
List methods = (List) e.getValue();
map.put( LuaValue.valueOf(name),
methods.size()==1?
methods.get(0):
JavaMethod.forMethods( (JavaMethod[])methods.toArray(new JavaMethod[methods.size()])) );
}
methods = map;
}
return (LuaValue) methods.get(key);
}
public LuaValue getConstructor() {
return getMethod(NEW);
}
}

View File

@@ -0,0 +1,101 @@
/*******************************************************************************
* Copyright (c) 2011 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lib.jse;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.VarArgFunction;
/**
* LuaValue that represents a particular public Java constructor.
* <p>
* May be called with arguments to return a JavaInstance
* created by calling the constructor.
*/
public class JavaConstructor extends JavaMember {
static final Map constructors = Collections.synchronizedMap(new HashMap());
static JavaConstructor forConstructor(Constructor c) {
JavaConstructor j = (JavaConstructor) constructors.get(c);
if ( j == null )
constructors.put( c, j = new JavaConstructor(c) );
return j;
}
public static LuaValue forConstructors(JavaConstructor[] array) {
return new Overload(array);
}
final Constructor constructor;
private JavaConstructor(Constructor c) {
super( c.getParameterTypes(), c.getModifiers() );
this.constructor = c;
}
public Varargs invoke(Varargs args) {
Object[] a = convertArgs(args);
try {
return CoerceJavaToLua.coerce( constructor.newInstance(a) );
} catch (InvocationTargetException e) {
throw new LuaError(e.getTargetException());
} catch (Exception e) {
return LuaValue.error("coercion error "+e);
}
}
static class Overload extends VarArgFunction {
final JavaConstructor[] constructors;
public Overload(JavaConstructor[] c) {
this.constructors = c;
}
public Varargs invoke(Varargs args) {
JavaConstructor best = null;
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
for ( int i=0; i<constructors.length; i++ ) {
int s = constructors[i].score(args);
if ( s < score ) {
score = s;
best = constructors[i];
if ( score == 0 )
break;
}
}
// any match?
if ( best == null )
LuaValue.error("no coercible public method");
// invoke it
return best.invoke(args);
}
}
}

View File

@@ -0,0 +1,73 @@
/*******************************************************************************
* Copyright (c) 2011 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lib.jse;
import java.lang.reflect.Field;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaUserdata;
import org.luaj.vm2.LuaValue;
/**
* LuaValue that represents a Java instance.
* <p>
* Will respond to get() and set() by returning field values or methods.
*/
public class JavaInstance extends LuaUserdata {
JavaClass jclass;
JavaInstance(Object instance) {
super(instance);
}
public LuaValue get(LuaValue key) {
if ( jclass == null )
jclass = JavaClass.forClass(m_instance.getClass());
Field f = jclass.getField(key);
if ( f != null )
try {
return CoerceJavaToLua.coerce(f.get(m_instance));
} catch (Exception e) {
throw new LuaError(e);
}
LuaValue m = jclass.getMethod(key);
if ( m != null )
return m;
return super.get(key);
}
public void set(LuaValue key, LuaValue value) {
if ( jclass == null )
jclass = JavaClass.forClass(m_instance.getClass());
Field f = jclass.getField(key);
if ( f != null )
try {
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
return;
} catch (Exception e) {
throw new LuaError(e);
}
super.set(key, value);
}
}

View File

@@ -0,0 +1,77 @@
/*******************************************************************************
* Copyright (c) 2011 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lib.jse;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.VarArgFunction;
import org.luaj.vm2.lib.jse.CoerceLuaToJava.Coercion;
/**
* Java method or constructor.
* <p>
* Primarily handles argument coercion for parameter lists including scoring of compatibility and
* java varargs handling.
*/
abstract
class JavaMember extends VarArgFunction {
static final int METHOD_MODIFIERS_VARARGS = 0x80;
final Coercion[] fixedargs;
final Coercion varargs;
protected JavaMember(Class[] params, int modifiers) {
boolean isvarargs = ((modifiers & METHOD_MODIFIERS_VARARGS) != 0);
fixedargs = new CoerceLuaToJava.Coercion[isvarargs? params.length-1: params.length];
for ( int i=0; i<fixedargs.length; i++ )
fixedargs[i] = CoerceLuaToJava.getCoercion( params[i] );
varargs = isvarargs? CoerceLuaToJava.getCoercion( params[params.length-1] ): null;
}
int score(Varargs args) {
int n = args.narg();
int s = n>fixedargs.length? CoerceLuaToJava.SCORE_WRONG_TYPE * (n-fixedargs.length): 0;
for ( int j=0; j<fixedargs.length; j++ )
s += fixedargs[j].score( args.arg(j+1) );
if ( varargs != null )
for ( int k=fixedargs.length; k<n; k++ )
s += varargs.score( args.arg(k+1) );
return s;
}
protected Object[] convertArgs(Varargs args) {
Object[] a;
if ( varargs == null ) {
a = new Object[fixedargs.length];
for ( int i=0; i<a.length; i++ )
a[i] = fixedargs[i].coerce( args.arg(i+1) );
} else {
int n = Math.max(fixedargs.length,args.narg());
a = new Object[n];
for ( int i=0; i<fixedargs.length; i++ )
a[i] = fixedargs[i].coerce( args.arg(i+1) );
for ( int i=fixedargs.length; i<n; i++ )
a[i] = varargs.coerce( args.arg(i+1) );
}
return a;
}
}

View File

@@ -0,0 +1,149 @@
/*******************************************************************************
* Copyright (c) 2011 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lib.jse;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.jse.CoerceLuaToJava.Coercion;
/**
* LuaValue that represents a Java method.
* <p>
* Can be invoked.
*/
public class JavaMethod extends JavaMember {
static final Map methods = Collections.synchronizedMap(new HashMap());
static JavaMethod forMethod(Method m) {
JavaMethod j = (JavaMethod) methods.get(m);
if ( j == null )
methods.put( m, j = new JavaMethod(m) );
return j;
}
static LuaFunction forMethods(JavaMethod[] m) {
return new Overload(m);
}
final Method method;
private JavaMethod(Method m) {
super( m.getParameterTypes(), m.getModifiers() );
this.method = m;
}
public LuaValue call() {
return error("method cannot be called without instance");
}
public LuaValue call(LuaValue arg) {
return invokeMethod(arg.checkuserdata(), LuaValue.NONE);
}
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return invokeMethod(arg1.checkuserdata(), arg2);
}
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return invokeMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
}
public Varargs invoke(Varargs args) {
return invokeMethod(args.checkuserdata(1), args.subargs(2));
}
LuaValue invokeMethod(Object instance, Varargs args) {
Object[] a = convertArgs(args);
try {
return CoerceJavaToLua.coerce( method.invoke(instance, a) );
} catch (InvocationTargetException e) {
throw new LuaError(e.getTargetException());
} catch (Exception e) {
return LuaValue.error("coercion error "+e);
}
}
/**
* LuaValue that represents an overloaded Java method.
* <p>
* On invocation, will pick the best method fromi the list, and invoke it.
*/
static class Overload extends LuaFunction {
final JavaMethod[] methods;
Overload(JavaMethod[] methods) {
this.methods = methods;
}
public LuaValue call() {
return error("method cannot be called without instance");
}
public LuaValue call(LuaValue arg) {
return invokeBestMethod(arg.checkuserdata(), LuaValue.NONE);
}
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return invokeBestMethod(arg1.checkuserdata(), arg2);
}
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return invokeBestMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
}
public Varargs invoke(Varargs args) {
return invokeBestMethod(args.checkuserdata(1), args.subargs(2));
}
private LuaValue invokeBestMethod(Object instance, Varargs args) {
JavaMethod best = null;
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
for ( int i=0; i<methods.length; i++ ) {
int s = methods[i].score(args);
if ( s < score ) {
score = s;
best = methods[i];
if ( score == 0 )
break;
}
}
// any match?
if ( best == null )
LuaValue.error("no coercible public method");
// invoke it
return best.invokeMethod(instance, args);
}
}
}

View File

@@ -23,28 +23,22 @@ package org.luaj.vm2.lib.jse;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaUserdata;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.PackageLib;
import org.luaj.vm2.lib.ThreeArgFunction;
import org.luaj.vm2.lib.TwoArgFunction;
import org.luaj.vm2.lib.VarArgFunction;
import org.luaj.vm2.lib.jme.JmePlatform;
/**
* Subclass of {@link LibFunction} which implements the features of the luajava package.
@@ -124,7 +118,7 @@ public class LuajavaLib extends VarArgFunction {
}
case BINDCLASS: {
final Class clazz = classForName(args.checkjstring(1));
return toUserdata( clazz, clazz );
return JavaClass.forClass(clazz);
}
case NEWINSTANCE:
case NEW: {
@@ -132,16 +126,7 @@ public class LuajavaLib extends VarArgFunction {
final LuaValue c = args.checkvalue(1);
final Class clazz = (opcode==NEWINSTANCE? classForName(c.tojstring()): (Class) c.checkuserdata(Class.class));
final Varargs consargs = args.subargs(2);
final long paramssig = LuajavaLib.paramsSignatureOf( consargs );
final Constructor con = resolveConstructor( clazz, paramssig );
final boolean isvarargs = ((con.getModifiers() & METHOD_MODIFIERS_VARARGS) != 0);
// coerce args, construct instance
final Object[] cargs = CoerceLuaToJava.coerceArgs( consargs, con.getParameterTypes(), isvarargs );
final Object o = con.newInstance( cargs );
// return result
return toUserdata( o, clazz );
return JavaClass.forClass(clazz).getConstructor().invoke(consargs);
}
case CREATEPROXY: {
@@ -179,7 +164,7 @@ public class LuajavaLib extends VarArgFunction {
v[i] = CoerceJavaToLua.coerce(args[i]);
}
LuaValue result = func.invoke(v).arg1();
return CoerceLuaToJava.coerceArg(result, method.getReturnType());
return CoerceLuaToJava.coerce(result, method.getReturnType());
}
};
@@ -218,258 +203,5 @@ public class LuajavaLib extends VarArgFunction {
protected Class classForName(String name) throws ClassNotFoundException {
return Class.forName(name, true, ClassLoader.getSystemClassLoader());
}
// params signature is
// - low 6-bits are number of parameters
// - each of next 9 6-bit fields encode a parameter type:
// - low 4 bits are lua type
// - high 2 bits are number of indexes deep (0,1,2, or 3)
public static long paramsSignatureOf( Varargs args ) {
long sig = 0;
int narg = args.narg();
int n = Math.min( narg, 9 );
for ( int i=1; i<=n; i++ ) {
LuaValue a = args.arg(i);
sig |= (paramTypeOf(a) << (i*6));
}
return sig | Math.min( narg, 0x3F );
}
public static int paramTypeOf( LuaValue arg ) {
int type = arg.type();
int tabledepth = 0;
if ( type == TTABLE ) {
for ( tabledepth=1; (type=(arg=arg.get(1)).type()) == TTABLE && (tabledepth<3); )
++tabledepth;
}
if ( type == TNUMBER && arg.isinttype() )
type = TINT;
if ( type == TUSERDATA ) {
Class c = arg.touserdata().getClass();
for ( ; c.isArray() && (tabledepth<3); ) {
c = c.getComponentType();
++tabledepth;
}
}
return (type & 0xF) | (tabledepth << 4);
}
public static int paramsCountFromSig( long paramssig ) {
return ((int) paramssig) & 0x3F;
}
public static int paramTypeFromSig(long paramssig, int argindex) {
return ((int) (paramssig>>(6*(argindex+1)))) & 0x3F;
}
public static int paramBaseTypeFromParamType(int paramType) {
int t = paramType & 0xf;
return t == (TINT & 0xF)? TINT: t;
}
public static int paramDepthFromParamType(int paramType) {
return (paramType >> 4) & 0x3;
}
public static int paramComponentTypeOfParamType(int paramType) {
int b = paramBaseTypeFromParamType( paramType );
int d = paramDepthFromParamType( paramType );
d = d>0? d-1: 0;
return (d<<4) | (b&0xF);
}
static LuaUserdata toUserdata(Object instance, final Class clazz) {
LuaTable mt = (LuaTable) classMetatables.get(clazz);
if ( mt == null ) {
mt = new LuaTable();
mt.set( LuaValue.INDEX, new TwoArgFunction() {
private Map methods;
public LuaValue call(LuaValue table, LuaValue key) {
Object instance = table.touserdata();
if ( key.isinttype() ) {
if ( clazz.isArray() ) {
int index = key.toint() - 1;
if ( index >= 0 && index < Array.getLength(instance) )
return CoerceJavaToLua.coerce( Array.get(instance, index) );
return NIL;
}
}
final String s = key.tojstring();
try {
Field f = clazz.getField(s);
Object o = f.get(instance);
return CoerceJavaToLua.coerce( o );
} catch (NoSuchFieldException nsfe) {
if ( clazz.isArray() && key.equals(LENGTH) )
return LuaValue.valueOf( Array.getLength(instance) );
if ( methods == null )
methods = new HashMap();
LMethod m = (LMethod) methods.get(s);
if ( m == null ) {
m = new LMethod(clazz,s);
// not safe - param list needs to
// distinguish between more cases
// methods.put(s, m);
}
return m;
} catch (Exception e) {
throw new LuaError(e);
}
}
});
mt.set( LuaValue.NEWINDEX, new ThreeArgFunction() {
public LuaValue call(LuaValue table, LuaValue key, LuaValue val) {
Object instance = table.touserdata();
if ( key.isinttype() ) {
if ( clazz.isArray() ) {
Object v = CoerceLuaToJava.coerceArg(val, clazz.getComponentType());
int index = key.toint() - 1;
if ( index >= 0 && index < Array.getLength(instance) )
Array.set(instance, index, v);
else
throw new LuaError("array bounds exceeded "+index);
return NIL;
}
}
String s = key.tojstring();
try {
Field f = clazz.getField(s);
Object v = CoerceLuaToJava.coerceArg(val, f.getType());
f.set(table.checkuserdata(Object.class),v);
} catch (Exception e) {
throw new LuaError(e);
}
return NONE;
}
});
classMetatables.put(clazz, mt);
}
return LuaValue.userdataOf(instance,mt);
}
static final class LMethod extends VarArgFunction {
private final Class clazz;
private final String s;
private LMethod(Class clazz, String s) {
this.clazz = clazz;
this.s = s;
}
public String tojstring() {
return clazz.getName()+"."+s+"()";
}
public Varargs invoke(Varargs args) {
try {
// find the method
final Object instance = args.touserdata(1);
final Varargs methargs = args.subargs(2);
final long paramssig = LuajavaLib.paramsSignatureOf(methargs);
final Method meth = resolveMethod( clazz, s, paramssig );
final boolean isvarargs = ((meth.getModifiers() & METHOD_MODIFIERS_VARARGS) != 0);
// coerce the arguments
final Object[] margs = CoerceLuaToJava.coerceArgs( methargs, meth.getParameterTypes(), isvarargs );
final Object result = meth.invoke( instance, margs );
// coerce the result
return CoerceJavaToLua.coerce(result);
} catch (InvocationTargetException ite) {
throw new LuaError(ite.getTargetException());
} catch (Exception e) {
throw new LuaError(e);
}
}
}
static Constructor resolveConstructor(Class clazz, long paramssig ) {
// get the cache
Map cache = (Map) consCache.get( clazz );
if ( cache == null )
consCache.put( clazz, cache = new HashMap() );
// look up in the cache
Constructor c = (Constructor) cache.get( Long.valueOf(paramssig) );
if ( c != null )
return c;
// get index
Constructor[] cons = (Constructor[]) consIndex.get( clazz );
if ( cons == null ) {
consIndex.put( clazz, cons = clazz.getConstructors() );
if ( cons == null )
throw new IllegalArgumentException("no public constructors");
}
// find constructor with best score
int bests = Integer.MAX_VALUE;
int besti = 0;
for ( int i=0, size=cons.length; i<size; i++ ) {
Constructor con = cons[i];
int s = CoerceLuaToJava.scoreParamTypes(paramssig, con.getParameterTypes());
if ( s < bests ) {
bests = s;
besti = i;
}
}
// put into cache
c = cons[besti];
cache.put( Long.valueOf(paramssig), c );
return c;
}
static Method resolveMethod(Class clazz, String methodName, long paramssig ) {
// get the cache
Map nameCache = (Map) methCache.get( clazz );
if ( nameCache == null )
methCache.put( clazz, nameCache = new HashMap() );
Map cache = (Map) nameCache.get( methodName );
if ( cache == null )
nameCache.put( methodName, cache = new HashMap() );
// look up in the cache
Method m = (Method) cache.get( Long.valueOf(paramssig) );
if ( m != null )
return m;
// get index
Map index = (Map) methIndex.get( clazz );
if ( index == null ) {
methIndex.put( clazz, index = new HashMap() );
Method[] meths = clazz.getMethods();
for ( int i=0; i<meths.length; i++ ) {
Method meth = meths[i];
String s = meth.getName();
List list = (List) index.get(s);
if ( list == null )
index.put( s, list = new ArrayList() );
list.add( meth );
}
}
// figure out best list of arguments == supplied args
List list = (List) index.get(methodName);
if ( list == null )
throw new IllegalArgumentException("no method named '"+methodName+"'");
// find method with best score
int bests = Integer.MAX_VALUE;
int besti = 0;
for ( int i=0, size=list.size(); i<size; i++ ) {
Method meth = (Method) list.get(i);
int s = CoerceLuaToJava.scoreParamTypes(paramssig, meth.getParameterTypes());
if ( s < bests ) {
bests = s;
besti = i;
}
}
// put into cache
m = (Method) list.get(besti);
cache.put( Long.valueOf(paramssig), m );
return m;
}
}