aboutsummaryrefslogtreecommitdiffstats
path: root/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java')
-rw-r--r--plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java895
1 files changed, 344 insertions, 551 deletions
diff --git a/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java b/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
index f4e6850..8fb2989 100644
--- a/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
+++ b/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
@@ -41,449 +41,403 @@ import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import netscape.javascript.JSObject;
/*
* This class resolved overloaded methods in Java objects using a cost
- * based-approach as described here:
+ * based-approach described here:
*
- * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
+ * http://jdk6.java.net/plugin2/liveconnect/#OVERLOADED_METHODS
*/
public class MethodOverloadResolver {
+ static final int NUMERIC_SAME_COST = 1;
+ static final int NULL_TO_OBJECT_COST = 2;
+ static final int CLASS_SAME_COST = 3;
+ static final int NUMERIC_CAST_COST = 4;
+ static final int NUMERIC_BOOLEAN_COST = 5;
- private static boolean debugging = false;
+ static final int STRING_NUMERIC_CAST_COST = 5;
- public static void main(String[] args) {
- testMethodResolver();
- }
+ static final int CLASS_SUPERCLASS_COST = 6;
+
+ static final int CLASS_STRING_COST = 7;
+ static final int JSOBJECT_TO_ARRAY_COST = CLASS_STRING_COST;
+ static final int ARRAY_CAST_COST = 8;
+
+ /* A method signature with its casted parameters
+ * We pretend a Constructor is a normal 'method' for ease of code reuse */
+ static class ResolvedMethod {
- public static void testMethodResolver() {
- debugging = true;
-
- ArrayList<Object[]> list = new ArrayList<Object[]>(20);
- FooClass fc = new FooClass();
-
- // Numeric to java primitive
- // foo_i has Integer and int params
- String s1 = "foo_string_int(S,I)";
- String s1a = "foo_string_int(S,S)";
- Object[] o1 = { fc.getClass(), "foo_string_int", "blah", 42 };
- list.add(o1);
- Object[] o1a = { fc.getClass(), "foo_string_int", "blah", "42.42" };
- list.add(o1a);
-
- // Null to non-primitive type
- // foo_i is overloaded with Integer and int
- String s2 = "foo_string_int(N)";
- Object[] o2 = { fc.getClass(), "foo_string_int", "blah", null };
- list.add(o2);
-
- // foo_jsobj is overloaded with JSObject and String params
- String s3 = "foo_jsobj(LLowCostSignatureComputer/JSObject;)";
- Object[] o3 = { fc.getClass(), "foo_jsobj", new JSObject() };
- list.add(o3);
-
- // foo_classtype is overloaded with Number and Integer
- String s4 = "foo_classtype(Ljava/lang/Integer;)";
- Object[] o4 = { fc.getClass(), "foo_classtype", 42 };
- list.add(o4);
-
- // foo_multiprim is overloaded with int, long and float types
- String s5 = "foo_multiprim(I)";
- String s6 = "foo_multiprim(F)";
- String s6a = "foo_multiprim(D)";
-
- Object[] o5 = { fc.getClass(), "foo_multiprim", new Integer(42) };
- Object[] o6 = { fc.getClass(), "foo_multiprim", new Float(42.42) };
- Object[] o6a = { fc.getClass(), "foo_multiprim", new Double(42.42) };
- list.add(o5);
- list.add(o6);
- list.add(o6a);
-
- // foo_float has float, String and JSObject type
- String s7 = "foo_float(I)";
- Object[] o7 = { fc.getClass(), "foo_float", new Integer(42) };
- list.add(o7);
-
- // foo_multiprim(float) is what this should convert
- String s8 = "foo_float(S)";
- Object[] o8 = { fc.getClass(), "foo_float", "42" };
- list.add(o8);
-
- // foo_class is overloaded with BarClass 2 and 3
- String s9 = "foo_class(LLowCostSignatureComputer/BarClass3;)";
- Object[] o9 = { fc.getClass(), "foo_class", new BarClass3() };
- list.add(o9);
-
- // foo_strandbyteonly takes string and byte
- String s10 = "foo_strandbyteonly(I)";
- Object[] o10 = { fc.getClass(), "foo_strandbyteonly", 42 };
- list.add(o10);
-
- // JSOBject to string
- String s11 = "foo_strandbyteonly(LLowCostSignatureComputer/JSObject;)";
- Object[] o11 = { fc.getClass(), "foo_strandbyteonly", new JSObject() };
- list.add(o11);
-
- // jsobject to string and int to float
- String s12 = "foo_str_and_float(S,I)";
- Object[] o12 = { fc.getClass(), "foo_str_and_float", new JSObject(), new Integer(42) };
- list.add(o12);
-
- // call for which no match will be found
- String s13 = "foo_int_only(JSObject)";
- Object[] o13 = { fc.getClass(), "foo_int_only", new JSObject() };
- list.add(o13);
-
- // method with no args
- String s14 = "foo_noargs()";
- Object[] o14 = { fc.getClass(), "foo_noargs" };
- list.add(o14);
-
- // method which takes a primitive bool, given a Boolean
- String s15 = "foo_boolonly()";
- Object[] o15 = { fc.getClass(), "foo_boolonly", new Boolean(true) };
- list.add(o15);
-
- for (Object[] o : list) {
- Object[] methodAndArgs = getMatchingMethod(o);
- if (debugging)
- if (methodAndArgs != null)
- System.out.println("Best match: " + methodAndArgs[0] + "\n");
- else
- System.out.println("No match found.\n");
+ private java.lang.reflect.AccessibleObject method;
+ private Object[] castedParameters;
+ private int cost;
+ public ResolvedMethod(int cost, java.lang.reflect.AccessibleObject method, Object[] castedParameters) {
+ this.cost = cost;
+ this.method = method;
+ this.castedParameters = castedParameters;
}
- }
+ java.lang.reflect.AccessibleObject getAccessibleObject() {
+ return method;
+ }
- /*
- * Cost based overload resolution algorithm based on cost rules specified here:
- *
- * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
- */
+ public Method getMethod() {
+ return (Method)method;
+ }
- public static Object[] getMatchingMethod(Object[] callList) {
- Object[] ret = null;
- Class<?> c = (Class<?>) callList[0];
- String methodName = (String) callList[1];
+ public Constructor<?> getConstructor() {
+ return (Constructor<?>)method;
+ }
- Method[] matchingMethods = getMatchingMethods(c, methodName, callList.length - 2);
+ public Object[] getCastedParameters() {
+ return castedParameters;
+ }
- if (debugging)
- System.out.println("getMatchingMethod called with: " + printList(callList));
+ public int getCost() {
+ return cost;
+ }
+ }
- int lowestCost = Integer.MAX_VALUE;
+ /* A cast with an associated 'cost', used for picking method overloads */
+ static class WeightedCast {
- for (Method matchingMethod : matchingMethods) {
+ private int cost;
+ private Object castedObject;
- int methodCost = 0;
- Class[] paramTypes = matchingMethod.getParameterTypes();
- Object[] methodAndArgs = new Object[paramTypes.length + 1];
- methodAndArgs[0] = matchingMethod;
+ public WeightedCast(int cost, Object castedObject) {
+ this.cost = cost;
+ this.castedObject = castedObject;
+ }
- // Figure out which of the matched methods best represents what we
- // want
- for (int i = 0; i < paramTypes.length; i++) {
- Class<?> paramTypeClass = paramTypes[i];
- Object suppliedParam = callList[i + 2];
- Class<?> suppliedParamClass = suppliedParam != null ? suppliedParam
- .getClass()
- : null;
+ public Object getCastedObject() {
+ return castedObject;
+ }
- Object[] costAndCastedObj = getCostAndCastedObject(
- suppliedParam, paramTypeClass);
- methodCost += (Integer) costAndCastedObj[0];
+ public int getCost() {
+ return cost;
+ }
+ }
- if ((Integer) costAndCastedObj[0] < 0)
- break;
- Object castedObj = paramTypeClass.isPrimitive() ? costAndCastedObj[1]
- : paramTypeClass.cast(costAndCastedObj[1]);
- methodAndArgs[i + 1] = castedObj;
+ public static ResolvedMethod getBestMatchMethod(Class<?> c, String methodName, Object[] args) {
+ Method[] matchingMethods = getMatchingMethods(c, methodName, args.length);
- Class<?> castedObjClass = castedObj == null ? null : castedObj
- .getClass();
- Boolean castedObjIsPrim = castedObj == null ? null : castedObj
- .getClass().isPrimitive();
+ if (PluginDebug.DEBUG) { /* avoid toString if not needed */
+ PluginDebug.debug("getMatchingMethod called with: "
+ + Arrays.toString(args));
+ }
- if (debugging)
- System.out.println("Param " + i + " of method "
- + matchingMethod + " has cost "
- + (Integer) costAndCastedObj[0]
- + " original param type " + suppliedParamClass
- + " casted to " + castedObjClass + " isPrimitive="
- + castedObjIsPrim + " value " + castedObj);
- }
+ return getBestOverloadMatch(c, args, matchingMethods);
+ }
- if ((methodCost > 0 && methodCost < lowestCost) ||
- paramTypes.length == 0) {
- ret = methodAndArgs;
- lowestCost = methodCost;
- }
+ public static ResolvedMethod getBestMatchConstructor(Class<?> c, Object[] args) {
+ Constructor<?>[] matchingConstructors = getMatchingConstructors(c, args.length);
+ if (PluginDebug.DEBUG) { /* avoid toString if not needed */
+ PluginDebug.debug("getMatchingConstructor called with: "
+ + Arrays.toString(args));
}
- return ret;
+ return getBestOverloadMatch(c, args, matchingConstructors);
}
- public static Object[] getMatchingConstructor(Object[] callList) {
- Object[] ret = null;
- Class<?> c = (Class<?>) callList[0];
-
- Constructor[] matchingConstructors = getMatchingConstructors(c, callList.length - 1);
-
- if (debugging)
- System.out.println("getMatchingConstructor called with: " + printList(callList));
+ /*
+ * Get best-matching method based on a cost based overload resolution
+ * algorithm is used, described here:
+ *
+ * http://jdk6.java.net/plugin2/liveconnect/#OVERLOADED_METHODS
+ *
+ * Note that we consider Constructor's to be 'methods' for convenience. We
+ * use the common parent class of Method/Constructor, 'AccessibleObject'
+ *
+ * NB: Although the spec specifies that ambiguous method calls (ie, same
+ * cost) should throw errors, we simply pick the first overload for
+ * simplicity. Method overrides should not be doing wildly different things
+ * anyway.
+ */
+ static ResolvedMethod getBestOverloadMatch(Class<?> c, Object[] args,
+ java.lang.reflect.AccessibleObject[] candidates) {
int lowestCost = Integer.MAX_VALUE;
+ java.lang.reflect.AccessibleObject cheapestMethod = null;
+ Object[] cheapestArgs = null;
+ boolean ambiguous = false;
- for (Constructor matchingConstructor : matchingConstructors) {
+ methodLoop:
+ for (java.lang.reflect.AccessibleObject candidate : candidates) {
+ int methodCost = 0;
- int constructorCost = 0;
- Class<?>[] paramTypes = matchingConstructor.getParameterTypes();
- Object[] constructorAndArgs = new Object[paramTypes.length + 1];
- constructorAndArgs[0] = matchingConstructor;
+ Class<?>[] paramTypes = getParameterTypesFor(candidate);
+ Object[] castedArgs = new Object[paramTypes.length];
// Figure out which of the matched methods best represents what we
// want
for (int i = 0; i < paramTypes.length; i++) {
Class<?> paramTypeClass = paramTypes[i];
- Object suppliedParam = callList[i + 1];
- Class suppliedParamClass = suppliedParam != null ? suppliedParam
- .getClass()
- : null;
+ Object suppliedParam = args[i];
+ Class<?> suppliedParamClass = suppliedParam != null ? suppliedParam
+ .getClass() : null;
- Object[] costAndCastedObj = getCostAndCastedObject(
+ WeightedCast weightedCast = getCostAndCastedObject(
suppliedParam, paramTypeClass);
- constructorCost += (Integer) costAndCastedObj[0];
- if ((Integer) costAndCastedObj[0] < 0)
- break;
+ if (weightedCast == null) {
+ continue methodLoop; // Cannot call this constructor!
+ }
+
+ methodCost += weightedCast.getCost();
- Object castedObj = paramTypeClass.isPrimitive() ? costAndCastedObj[1]
- : paramTypeClass.cast(costAndCastedObj[1]);
- constructorAndArgs[i + 1] = castedObj;
+ Object castedObj = paramTypeClass.isPrimitive() ?
+ weightedCast.getCastedObject()
+ : paramTypeClass.cast(weightedCast.getCastedObject());
- Class<?> castedObjClass = castedObj == null ? null : castedObj
- .getClass();
- Boolean castedObjIsPrim = castedObj == null ? null : castedObj
- .getClass().isPrimitive();
+ castedArgs[i] = castedObj;
- if (debugging)
- System.out.println("Param " + i + " of constructor "
- + matchingConstructor + " has cost "
- + (Integer) costAndCastedObj[0]
+ Class<?> castedObjClass = castedObj == null ? null : castedObj.getClass();
+ boolean castedObjIsPrim = castedObj == null ? false : castedObj.getClass().isPrimitive();
+
+ if (PluginDebug.DEBUG) { /* avoid toString if not needed */
+ PluginDebug.debug("Param " + i + " of method " + candidate
+ + " has cost " + weightedCast.getCost()
+ " original param type " + suppliedParamClass
+ " casted to " + castedObjClass + " isPrimitive="
+ castedObjIsPrim + " value " + castedObj);
+ }
}
- if ((constructorCost > 0 && constructorCost < lowestCost) ||
- paramTypes.length == 0) {
- ret = constructorAndArgs;
- lowestCost = constructorCost;
+ if (methodCost <= lowestCost) {
+ if (methodCost < lowestCost
+ || argumentsAreSubclassesOf(castedArgs, cheapestArgs)) {
+ lowestCost = methodCost;
+ cheapestArgs = castedArgs;
+ cheapestMethod = candidate;
+ ambiguous = false;
+ } else {
+ ambiguous = true;
+ }
}
+
+ }
+
+ // The spec says we should error out if the method call is ambiguous
+ // Instead we will report it in debug output
+ if (ambiguous) {
+ PluginDebug.debug("*** Warning: Ambiguous overload of ", c.getClass(), "#", cheapestMethod, "!");
}
- return ret;
+ return new ResolvedMethod(lowestCost, cheapestMethod, cheapestArgs);
}
- public static Object[] getCostAndCastedObject(Object suppliedParam, Class<?> paramTypeClass) {
+ public static WeightedCast getCostAndCastedObject(Object suppliedParam,
+ Class<?> paramTypeClass) {
+ Class<?> suppliedParamClass = suppliedParam != null ? suppliedParam
+ .getClass() : null;
- Object[] ret = new Object[2];
- Integer cost = new Integer(0);
- Object castedObj;
+ boolean suppliedParamIsArray = suppliedParamClass != null
+ && suppliedParamClass.isArray();
- Class<?> suppliedParamClass = suppliedParam != null ? suppliedParam.getClass() : null;
+ if (suppliedParamIsArray) {
+ if (paramTypeClass.isArray()) {
+ return getArrayToArrayCastWeightedCost(suppliedParam,
+ paramTypeClass);
+ }
- // Either both are an array, or neither are
- boolean suppliedParamIsArray = suppliedParamClass != null && suppliedParamClass.isArray();
- if (paramTypeClass.isArray() != suppliedParamIsArray &&
- !paramTypeClass.equals(Object.class) &&
- !paramTypeClass.equals(String.class)) {
- ret[0] = Integer.MIN_VALUE; // Not allowed
- ret[1] = suppliedParam;
- return ret;
+ // Target type must be an array, Object or String
+ // If it an object, we return "as is" [Everything can be narrowed to an
+ // object, cost=CLASS_SUPERCLASS_COST]
+ // If it is a string, we need to convert according to the JS engine
+ // rules
+ if (paramTypeClass != String.class
+ && paramTypeClass != Object.class) {
+ return null;
+ }
+ if (paramTypeClass.equals(String.class)) {
+ return new WeightedCast(ARRAY_CAST_COST,
+ arrayToJavascriptStyleString(suppliedParam));
+ }
}
- // If param type is an array, supplied obj must be an array, Object or String (guaranteed by checks above)
- // If it is an array, we need to copy/cast as we scan the array
- // If it an object, we return "as is" [Everything can be narrowed to an object, cost=6]
- // If it is a string, we need to convert according to the JS engine rules
+ // If this is null, there are only 2 possible cases
+ if (suppliedParamClass == null) {
+ if (!paramTypeClass.isPrimitive()) {
+ return new WeightedCast(NULL_TO_OBJECT_COST, null); // Null to any non-primitive type
+ }
+ return null;// Null to primitive not allowed
+ }
- if (paramTypeClass.isArray()) {
+ // Numeric type to the analogous Java primitive type
+ if (paramTypeClass.isPrimitive()
+ && paramTypeClass == getPrimitiveType(suppliedParam.getClass())) {
+ return new WeightedCast(NUMERIC_SAME_COST, suppliedParam);
- Object newArray = Array.newInstance(paramTypeClass.getComponentType(), Array.getLength(suppliedParam));
- for (int i = 0; i < Array.getLength(suppliedParam); i++) {
- Object original = Array.get(suppliedParam, i);
+ }
- // When dealing with arrays, we represent empty slots with
- // null. We need to convert this to 0 before recursive
- // calling, since normal transformation does not allow
- // null -> primitive
+ // Class type to Class type where the types are the same
+ if (suppliedParamClass == paramTypeClass) {
+ return new WeightedCast(CLASS_SAME_COST, suppliedParam);
- if (original == null && paramTypeClass.getComponentType().isPrimitive())
- original = 0;
+ }
- Object[] costAndCastedObject = getCostAndCastedObject(original, paramTypeClass.getComponentType());
+ // Numeric type to a different primitive type
+ boolean wrapsPrimitive = (getPrimitiveType(suppliedParam.getClass()) != null);
+ if (wrapsPrimitive && paramTypeClass.isPrimitive()) {
+ double val;
- if ((Integer) costAndCastedObject[0] < 0) {
- ret[0] = Integer.MIN_VALUE; // Not allowed
- ret[1] = suppliedParam;
- return ret;
- }
+ // Coerce booleans
+ if (suppliedParam.equals(Boolean.TRUE)) {
+ val = 1.0;
+ } else if (suppliedParam.equals(Boolean.FALSE)){
+ val = 0.0;
+ } else if (suppliedParam instanceof Character) {
+ val = (double)(Character)suppliedParam;
+ } else {
+ val = ((Number)suppliedParam).doubleValue();
+ }
+
+ int castCost = NUMERIC_CAST_COST;
+ Object castedObj;
+ if (paramTypeClass.equals(Boolean.TYPE)) {
+ castedObj = (val != 0D && !Double.isNaN(val));
- Array.set(newArray, i, costAndCastedObject[1]);
+ if (suppliedParam.getClass() != Boolean.class) {
+ castCost = NUMERIC_BOOLEAN_COST;
+ }
+ } else {
+ castedObj = toBoxedPrimitiveType(val, paramTypeClass);
+ }
+ return new WeightedCast(castCost, castedObj);
+ }
+
+ // Numeric string to numeric type
+ if (isNumericString(suppliedParam) && paramTypeClass.isPrimitive()) {
+ Object castedObj;
+ if (paramTypeClass.equals(Character.TYPE)) {
+ castedObj = (char) Short.decode((String)suppliedParam).shortValue();
+ } else {
+ castedObj = stringAsPrimitiveType((String)suppliedParam, paramTypeClass);
}
+ return new WeightedCast(STRING_NUMERIC_CAST_COST, castedObj);
+ }
- ret[0] = 9;
- ret[1] = newArray;
- return ret;
+ // Same cost as above
+ if (suppliedParam instanceof java.lang.String
+ && (paramTypeClass == java.lang.Boolean.class || paramTypeClass == java.lang.Boolean.TYPE)) {
+ return new WeightedCast(STRING_NUMERIC_CAST_COST, !suppliedParam.equals(""));
}
- if (suppliedParamIsArray && paramTypeClass.equals(String.class)) {
+ // Class type to superclass type;
+ if (paramTypeClass.isAssignableFrom(suppliedParamClass)) {
+ return new WeightedCast(CLASS_SUPERCLASS_COST, paramTypeClass.cast(suppliedParam));
+ }
- ret[0] = 9;
- ret[1] = getArrayAsString(suppliedParam);
- return ret;
+ // Any java value to String
+ if (paramTypeClass.equals(String.class)) {
+ return new WeightedCast(CLASS_STRING_COST, suppliedParam.toString());
}
- // If this is null, there are only 2 possible cases
- if (suppliedParamClass == null) {
- castedObj = null; // if value is null.. well, it is null
+ // JSObject to Java array
+ if (suppliedParam instanceof JSObject
+ && paramTypeClass.isArray()) {
+ return new WeightedCast(JSOBJECT_TO_ARRAY_COST, suppliedParam);
+ }
- if (!paramTypeClass.isPrimitive()) {
- cost += 2; // Null to any non-primitive type
- } else {
- cost = Integer.MIN_VALUE; // Null to primitive not allowed
+ return null;
+ }
+
+ private static WeightedCast getArrayToArrayCastWeightedCost(Object suppliedArray,
+ Class<?> paramTypeClass) {
+
+ int arrLength = Array.getLength(suppliedArray);
+ Class<?> arrType = paramTypeClass.getComponentType();
+
+ // If it is an array, we need to copy/cast as we scan the array
+ Object newArray = Array.newInstance(arrType, arrLength);
+
+ for (int i = 0; i < arrLength; i++) {
+ Object original = Array.get(suppliedArray, i);
+
+ // When dealing with arrays, we represent empty slots with
+ // null. We need to convert this to 0 before recursive
+ // calling, since normal transformation does not allow
+ // null -> primitive
+
+ if (original == null && arrType.isPrimitive()) {
+ original = 0;
}
- } else if (paramTypeClass.isPrimitive() && paramTypeClass.equals(getPrimitive(suppliedParam))) {
- cost += 1; // Numeric type to the analogous Java primitive type
- castedObj = suppliedParam; // Let auto-boxing handle it
- } else if (suppliedParamClass.equals(paramTypeClass)) {
- cost += 3; // Class type to Class type where the types are equal
- castedObj = suppliedParam;
- } else if (isNum(suppliedParam) &&
- (paramTypeClass.isPrimitive() ||
- java.lang.Number.class.isAssignableFrom(paramTypeClass) ||
- java.lang.Character.class.isAssignableFrom(paramTypeClass) ||
- java.lang.Byte.class.isAssignableFrom(paramTypeClass)
- )) {
- cost += 4; // Numeric type to a different primitive type
-
- if (suppliedParam.toString().equals("true"))
- suppliedParam = "1";
- else if (suppliedParam.toString().equals("false"))
- suppliedParam = "0";
-
- if (paramTypeClass.equals(Boolean.TYPE))
- castedObj = getNum(suppliedParam.toString(), paramTypeClass).doubleValue() != 0D;
- else if (paramTypeClass.equals(Character.TYPE))
- castedObj = (char) Short.decode(suppliedParam.toString()).shortValue();
- else
- castedObj = getNum(suppliedParam.toString(), paramTypeClass);
- } else if (suppliedParam instanceof java.lang.String &&
- isNum(suppliedParam) &&
- (paramTypeClass.isInstance(java.lang.Number.class) ||
- paramTypeClass.isInstance(java.lang.Character.class) ||
- paramTypeClass.isInstance(java.lang.Byte.class) ||
- paramTypeClass.isPrimitive())) {
- cost += 5; // String to numeric type
-
- if (suppliedParam.toString().equals("true"))
- suppliedParam = "1";
- else if (suppliedParam.toString().equals("false"))
- suppliedParam = "0";
-
- if (paramTypeClass.equals(Character.TYPE))
- castedObj = (char) Short.decode(suppliedParam.toString()).shortValue();
- else
- castedObj = getNum(suppliedParam.toString(), paramTypeClass);
- } else if (suppliedParam instanceof java.lang.String &&
- (paramTypeClass.equals(java.lang.Boolean.class) ||
- paramTypeClass.equals(java.lang.Boolean.TYPE))) {
-
- cost += 5; // Same cost as above
- castedObj = new Boolean(suppliedParam.toString().length() > 0);
- } else if (paramTypeClass.isAssignableFrom(suppliedParamClass)) {
- cost += 6; // Class type to superclass type;
- castedObj = paramTypeClass.cast(suppliedParam);
- } else if (paramTypeClass.equals(String.class)) {
- cost += 7; // Any Java value to String
- castedObj = suppliedParam.toString();
- } else if (suppliedParam instanceof JSObject &&
- paramTypeClass.isArray()) {
- cost += 8; // JSObject to Java array
- castedObj = (JSObject) suppliedParam;
- } else {
- cost = Integer.MIN_VALUE; // Not allowed
- castedObj = suppliedParam;
- }
- ret[0] = cost;
- ret[1] = castedObj;
+ WeightedCast costAndCastedObject = getCostAndCastedObject(original,
+ paramTypeClass.getComponentType());
- return ret;
+ if (costAndCastedObject == null) {
+ return null;
+ }
+ Array.set(newArray, i, costAndCastedObject.getCastedObject());
+ }
+
+ return new WeightedCast(ARRAY_CAST_COST, newArray);
}
- private static Method[] getMatchingMethods(Class<?> c, String name, int paramCount) {
- Method[] allMethods = c.getMethods();
- ArrayList<Method> matchingMethods = new ArrayList<Method>(5);
+ private static Method[] getMatchingMethods(Class<?> c, String name,
+ int paramCount) {
+ List<Method> matchingMethods = new ArrayList<Method>();
- for (Method m : allMethods) {
- if (m.getName().equals(name) && m.getParameterTypes().length == paramCount)
- matchingMethods.add(m);
+ for (Method m : c.getMethods()) {
+ if (m.getName().equals(name)) {
+ if (m.getParameterTypes().length == paramCount) {
+ matchingMethods.add(m);
+ }
+ }
}
return matchingMethods.toArray(new Method[0]);
}
- private static Constructor[] getMatchingConstructors(Class<?> c, int paramCount) {
- Constructor[] allConstructors = c.getConstructors();
- ArrayList<Constructor> matchingConstructors = new ArrayList<Constructor>(5);
+ private static Constructor<?>[] getMatchingConstructors(Class<?> c,
+ int paramCount) {
+ List<Constructor<?>> matchingConstructors = new ArrayList<Constructor<?>>();
- for (Constructor cs : allConstructors) {
- if (cs.getParameterTypes().length == paramCount)
+ for (Constructor<?> cs : c.getConstructors()) {
+ if (cs.getParameterTypes().length == paramCount) {
matchingConstructors.add(cs);
+ }
}
return matchingConstructors.toArray(new Constructor[0]);
}
- private static Class getPrimitive(Object o) {
-
- if (o instanceof java.lang.Byte) {
- return java.lang.Byte.TYPE;
- } else if (o instanceof java.lang.Character) {
- return java.lang.Character.TYPE;
- } else if (o instanceof java.lang.Short) {
- return java.lang.Short.TYPE;
- } else if (o instanceof java.lang.Integer) {
- return java.lang.Integer.TYPE;
- } else if (o instanceof java.lang.Long) {
- return java.lang.Long.TYPE;
- } else if (o instanceof java.lang.Float) {
- return java.lang.Float.TYPE;
- } else if (o instanceof java.lang.Double) {
- return java.lang.Double.TYPE;
- } else if (o instanceof java.lang.Boolean) {
- return java.lang.Boolean.TYPE;
+ private static Class<?> getPrimitiveType(Class<?> c) {
+ if (c.isPrimitive()) {
+ return c;
}
- return o.getClass();
+ if (c == Byte.class) {
+ return Byte.TYPE;
+ } else if (c == Character.class) {
+ return Character.TYPE;
+ } else if (c == Short.class) {
+ return Short.TYPE;
+ } else if (c == Integer.class) {
+ return Integer.TYPE;
+ } else if (c == Long.class) {
+ return Long.TYPE;
+ } else if (c == Float.class) {
+ return Float.TYPE;
+ } else if (c == Double.class) {
+ return Double.TYPE;
+ } else if (c == Boolean.class) {
+ return Boolean.TYPE;
+ } else {
+ return null;
+ }
}
- private static boolean isNum(Object o) {
-
- if (o instanceof java.lang.Number)
- return true;
-
- // Boolean is changeable to number as well
- if (o instanceof java.lang.Boolean)
- return true;
-
+ private static boolean isNumericString(Object o) {
// At this point, it _has_ to be a string else automatically
// return false
if (!(o instanceof java.lang.String))
@@ -504,239 +458,78 @@ public class MethodOverloadResolver {
return false;
}
- private static Number getNum(String s, Class<?> c) throws NumberFormatException {
-
- Number n;
- if (s.contains("."))
- n = new Double(s);
- else
- n = new Long(s);
+ private static Object toBoxedPrimitiveType(double val, Class<?> c) {
+ Class<?> prim = getPrimitiveType(c);
// See if we need to collapse first
- if (c.equals(java.lang.Integer.class) ||
- c.equals(java.lang.Integer.TYPE)) {
- return n.intValue();
- }
-
- if (c.equals(java.lang.Long.class) ||
- c.equals(java.lang.Long.TYPE)) {
- return n.longValue();
- }
-
- if (c.equals(java.lang.Short.class) ||
- c.equals(java.lang.Short.TYPE)) {
- return n.shortValue();
+ if (prim == Integer.TYPE) {
+ return (int)val;
+ } else if (prim == Long.TYPE) {
+ return (long)val;
+ } else if (prim == Short.TYPE) {
+ return (short)val;
+ } else if (prim == Float.TYPE) {
+ return (float)val;
+ } else if (prim == Double.TYPE) {
+ return val;
+ } else if (prim == Byte.TYPE) {
+ return (byte)val;
+ } else if (prim == Character.TYPE) {
+ return (char)(short)val;
}
+ return val;
+ }
- if (c.equals(java.lang.Float.class) ||
- c.equals(java.lang.Float.TYPE)) {
- return n.floatValue();
- }
+ private static Object stringAsPrimitiveType(String s, Class<?> c)
+ throws NumberFormatException {
+ double val = Double.parseDouble(s);
+ return toBoxedPrimitiveType(val, c);
- if (c.equals(java.lang.Double.class) ||
- c.equals(java.lang.Double.TYPE)) {
- return n.doubleValue();
- }
+ }
- if (c.equals(java.lang.Byte.class) ||
- c.equals(java.lang.Byte.TYPE)) {
- return n.byteValue();
+ // Test whether we can get from 'args' to 'testArgs' only by using widening conversions,
+ // eg String -> Object
+ private static boolean argumentsAreSubclassesOf(Object[] args, Object[] testArgs) {
+ for (int i = 0; i < args.length; i++) {
+ if (!testArgs[i].getClass().isAssignableFrom(args[i].getClass())) {
+ return false;
+ }
}
-
- return n;
+ return true;
}
- private static String printList(Object[] oList) {
-
- String ret = "";
-
- ret += "{ ";
- for (Object o : oList) {
-
- String oStr = o != null ? o.toString() + " [" + o.getClass() + "]" : "null";
-
- ret += oStr;
- ret += ", ";
+ static Class<?>[] getParameterTypesFor(java.lang.reflect.AccessibleObject method) {
+ if (method instanceof Method) {
+ return ((Method)method).getParameterTypes();
+ } else /*m instanceof Constructor*/ {
+ return ((Constructor<?>)method).getParameterTypes();
}
- ret = ret.substring(0, ret.length() - 2); // remove last ", "
- ret += " }";
-
- return ret;
}
- private static String getArrayAsString(Object array) {
- // We are guaranteed that supplied object is a String
+ private static String arrayToJavascriptStyleString(Object array) {
+ int arrLength = Array.getLength(array);
- String ret = new String();
+ StringBuilder sb = new StringBuilder();
- for (int i = 0; i < Array.getLength(array); i++) {
+ for (int i = 0; i < arrLength; i++) {
Object element = Array.get(array, i);
if (element != null) {
if (element.getClass().isArray()) {
- ret += getArrayAsString(element);
+ sb.append(arrayToJavascriptStyleString(element));
} else {
- ret += element;
+ sb.append(element);
}
}
- ret += ",";
+ sb.append(',');
}
// Trim the final ","
- if (ret.length() > 0) {
- ret = ret.substring(0, ret.length() - 1);
+ if (arrLength > 0) {
+ sb.setLength(sb.length() - 1);
}
- return ret;
- }
-}
-
-/** Begin test classes **/
-
-class FooClass {
-
- public FooClass() {
- }
-
- public FooClass(Boolean b, int i) {
- }
-
- public FooClass(Boolean b, Integer i) {
- }
-
- public FooClass(Boolean b, short s) {
- }
-
- public FooClass(String s, int i) {
- }
-
- public FooClass(String s, Integer i) {
- }
-
- public FooClass(java.lang.Number num) {
- }
-
- public FooClass(java.lang.Integer integer) {
- }
-
- public FooClass(long l) {
- }
-
- public FooClass(double d) {
- }
-
- public FooClass(float f) {
- }
-
- public FooClass(JSObject j) {
- }
-
- public FooClass(BarClass1 b) {
- }
-
- public FooClass(BarClass2 b) {
- }
-
- public FooClass(String s) {
- }
-
- public FooClass(byte b) {
- }
-
- public FooClass(String s, Float f) {
- }
-
- public FooClass(int i) {
- }
-
- public void FooClass() {
- }
-
- public void FooClass(boolean b) {
- }
-
- public void foo(Boolean b, int i) {
+ return sb.toString();
}
-
- public void foo(Boolean b, Integer i) {
- }
-
- public void foo(Boolean b, short s) {
- }
-
- public void foo_string_int(String s, int i) {
- }
-
- public void foo_string_int(String s, Integer i) {
- }
-
- public void foo_jsobj(JSObject j) {
- }
-
- public void foo_jsobj(String s) {
- }
-
- public void foo_classtype(java.lang.Number num) {
- }
-
- public void foo_classtype(java.lang.Integer integer) {
- }
-
- public void foo_multiprim(int i) {
- }
-
- public void foo_multiprim(long l) {
- }
-
- public void foo_multiprim(float f) {
- }
-
- public void foo_multiprim(double d) {
- }
-
- public void foo_float(float f) {
- }
-
- public void foo_float(String s) {
- }
-
- public void foo_float(JSObject j) {
- }
-
- public void foo_class(BarClass1 b) {
- }
-
- public void foo_class(BarClass2 b) {
- }
-
- public void foo_strandbyteonly(String s) {
- }
-
- public void foo_strandbyteonly(byte b) {
- }
-
- public void foo_str_and_float(String s, Float f) {
- }
-
- public void foo_int_only(int i) {
- }
-
- public void foo_noargs() {
- }
-
- public void foo_boolonly(boolean b) {
- }
-}
-
-class BarClass1 {
-}
-
-class BarClass2 extends BarClass1 {
-}
-
-class BarClass3 extends BarClass2 {
-}
-
-class JSObject {
-}
+} \ No newline at end of file