aboutsummaryrefslogtreecommitdiffstats
path: root/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
diff options
context:
space:
mode:
authorandrew <devnull@localhost>2010-10-19 17:55:59 +0100
committerandrew <devnull@localhost>2010-10-19 17:55:59 +0100
commit7603e948d7a0a7eb2e72358cb4a40ae6779f95da (patch)
treec6441f7d14eafe8119d890cddd09b05b8f88c52a /plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
Initial import from IcedTea6.
2010-10-19 Andrew John Hughes <[email protected]> * .hgignore, * Makefile.am, * acinclude.m4, * autogen.sh, * configure.ac, * extra/net/sourceforge/jnlp/about/HTMLPanel.java, * extra/net/sourceforge/jnlp/about/Main.java, * extra/net/sourceforge/jnlp/about/resources/about.html, * extra/net/sourceforge/jnlp/about/resources/applications.html, * extra/net/sourceforge/jnlp/about/resources/notes.html, * javac.in, * javaws.desktop: Imported from IcedTea6. * launcher/java.c, * launcher/java.h, * launcher/java_md.c, * launcher/java_md.h, * launcher/jli_util.h, * launcher/jni.h, * launcher/jvm.h, * launcher/jvm_md.h, * launcher/manifest_info.h, * launcher/splashscreen.h, * launcher/splashscreen_stubs.c, * launcher/version_comp.h, * launcher/wildcard.h: Imported from OpenJDK. * netx/javaws.1, * netx/javax/jnlp/BasicService.java, * netx/javax/jnlp/ClipboardService.java, * netx/javax/jnlp/DownloadService.java, * netx/javax/jnlp/DownloadServiceListener.java, * netx/javax/jnlp/ExtendedService.java, * netx/javax/jnlp/ExtensionInstallerService.java, * netx/javax/jnlp/FileContents.java, * netx/javax/jnlp/FileOpenService.java, * netx/javax/jnlp/FileSaveService.java, * netx/javax/jnlp/JNLPRandomAccessFile.java, * netx/javax/jnlp/PersistenceService.java, * netx/javax/jnlp/PrintService.java, * netx/javax/jnlp/ServiceManager.java, * netx/javax/jnlp/ServiceManagerStub.java, * netx/javax/jnlp/SingleInstanceListener.java, * netx/javax/jnlp/SingleInstanceService.java, * netx/javax/jnlp/UnavailableServiceException.java, * netx/net/sourceforge/jnlp/AppletDesc.java, * netx/net/sourceforge/jnlp/ApplicationDesc.java, * netx/net/sourceforge/jnlp/AssociationDesc.java, * netx/net/sourceforge/jnlp/ComponentDesc.java, * netx/net/sourceforge/jnlp/DefaultLaunchHandler.java, * netx/net/sourceforge/jnlp/ExtensionDesc.java, * netx/net/sourceforge/jnlp/IconDesc.java, * netx/net/sourceforge/jnlp/InformationDesc.java, * netx/net/sourceforge/jnlp/InstallerDesc.java, * netx/net/sourceforge/jnlp/JARDesc.java, * netx/net/sourceforge/jnlp/JNLPFile.java, * netx/net/sourceforge/jnlp/JNLPSplashScreen.java, * netx/net/sourceforge/jnlp/JREDesc.java, * netx/net/sourceforge/jnlp/LaunchException.java, * netx/net/sourceforge/jnlp/LaunchHandler.java, * netx/net/sourceforge/jnlp/Launcher.java, * netx/net/sourceforge/jnlp/MenuDesc.java, * netx/net/sourceforge/jnlp/NetxPanel.java, * netx/net/sourceforge/jnlp/Node.java, * netx/net/sourceforge/jnlp/PackageDesc.java, * netx/net/sourceforge/jnlp/ParseException.java, * netx/net/sourceforge/jnlp/Parser.java, * netx/net/sourceforge/jnlp/PluginBridge.java, * netx/net/sourceforge/jnlp/PropertyDesc.java, * netx/net/sourceforge/jnlp/RelatedContentDesc.java, * netx/net/sourceforge/jnlp/ResourcesDesc.java, * netx/net/sourceforge/jnlp/SecurityDesc.java, * netx/net/sourceforge/jnlp/ShortcutDesc.java, * netx/net/sourceforge/jnlp/StreamEater.java, * netx/net/sourceforge/jnlp/UpdateDesc.java, * netx/net/sourceforge/jnlp/Version.java, * netx/net/sourceforge/jnlp/cache/CacheEntry.java, * netx/net/sourceforge/jnlp/cache/CacheUtil.java, * netx/net/sourceforge/jnlp/cache/DefaultDownloadIndicator.java, * netx/net/sourceforge/jnlp/cache/DownloadIndicator.java, * netx/net/sourceforge/jnlp/cache/Resource.java, * netx/net/sourceforge/jnlp/cache/ResourceTracker.java, * netx/net/sourceforge/jnlp/cache/UpdatePolicy.java, * netx/net/sourceforge/jnlp/cache/package.html, * netx/net/sourceforge/jnlp/event/ApplicationEvent.java, * netx/net/sourceforge/jnlp/event/ApplicationListener.java, * netx/net/sourceforge/jnlp/event/DownloadEvent.java, * netx/net/sourceforge/jnlp/event/DownloadListener.java, * netx/net/sourceforge/jnlp/event/package.html, * netx/net/sourceforge/jnlp/package.html, * netx/net/sourceforge/jnlp/resources/Manifest.mf, * netx/net/sourceforge/jnlp/resources/Messages.properties, * netx/net/sourceforge/jnlp/resources/about.jnlp, * netx/net/sourceforge/jnlp/resources/default.jnlp, * netx/net/sourceforge/jnlp/runtime/AppThreadGroup.java, * netx/net/sourceforge/jnlp/runtime/AppletAudioClip.java, * netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java, * netx/net/sourceforge/jnlp/runtime/AppletInstance.java, * netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java, * netx/net/sourceforge/jnlp/runtime/Boot.java, * netx/net/sourceforge/jnlp/runtime/Boot13.java, * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java, * netx/net/sourceforge/jnlp/runtime/JNLPPolicy.java, * netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java, * netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java, * netx/net/sourceforge/jnlp/runtime/package.html, * netx/net/sourceforge/jnlp/security/AccessWarningPane.java, * netx/net/sourceforge/jnlp/security/AppletWarningPane.java, * netx/net/sourceforge/jnlp/security/CertVerifier.java, * netx/net/sourceforge/jnlp/security/CertWarningPane.java, * netx/net/sourceforge/jnlp/security/CertsInfoPane.java, * netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java, * netx/net/sourceforge/jnlp/security/MoreInfoPane.java, * netx/net/sourceforge/jnlp/security/NotAllSignedWarningPane.java, * netx/net/sourceforge/jnlp/security/SecurityDialogPanel.java, * netx/net/sourceforge/jnlp/security/SecurityUtil.java, * netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java, * netx/net/sourceforge/jnlp/security/SingleCertInfoPane.java, * netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java, * netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java, * netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java, * netx/net/sourceforge/jnlp/services/ExtendedSingleInstanceService.java, * netx/net/sourceforge/jnlp/services/InstanceExistsException.java, * netx/net/sourceforge/jnlp/services/ServiceUtil.java, * netx/net/sourceforge/jnlp/services/SingleInstanceLock.java, * netx/net/sourceforge/jnlp/services/XBasicService.java, * netx/net/sourceforge/jnlp/services/XClipboardService.java, * netx/net/sourceforge/jnlp/services/XDownloadService.java, * netx/net/sourceforge/jnlp/services/XExtendedService.java, * netx/net/sourceforge/jnlp/services/XExtensionInstallerService.java, * netx/net/sourceforge/jnlp/services/XFileContents.java, * netx/net/sourceforge/jnlp/services/XFileOpenService.java, * netx/net/sourceforge/jnlp/services/XFileSaveService.java, * netx/net/sourceforge/jnlp/services/XJNLPRandomAccessFile.java, * netx/net/sourceforge/jnlp/services/XPersistenceService.java, * netx/net/sourceforge/jnlp/services/XPrintService.java, * netx/net/sourceforge/jnlp/services/XServiceManagerStub.java, * netx/net/sourceforge/jnlp/services/XSingleInstanceService.java, * netx/net/sourceforge/jnlp/services/package.html, * netx/net/sourceforge/jnlp/tools/CharacterEncoder.java, * netx/net/sourceforge/jnlp/tools/HexDumpEncoder.java, * netx/net/sourceforge/jnlp/tools/JarRunner.java, * netx/net/sourceforge/jnlp/tools/JarSigner.java, * netx/net/sourceforge/jnlp/tools/JarSignerResources.java, * netx/net/sourceforge/jnlp/tools/KeyStoreUtil.java, * netx/net/sourceforge/jnlp/tools/KeyTool.java, * netx/net/sourceforge/jnlp/util/FileUtils.java, * netx/net/sourceforge/jnlp/util/PropertiesFile.java, * netx/net/sourceforge/jnlp/util/Reflect.java, * netx/net/sourceforge/jnlp/util/WeakList.java, * netx/net/sourceforge/jnlp/util/XDesktopEntry.java, * netx/net/sourceforge/nanoxml/XMLElement.java, * netx/net/sourceforge/nanoxml/XMLParseException.java, * plugin/icedteanp/IcedTeaJavaRequestProcessor.cc, * plugin/icedteanp/IcedTeaJavaRequestProcessor.h, * plugin/icedteanp/IcedTeaNPPlugin.cc, * plugin/icedteanp/IcedTeaNPPlugin.h, * plugin/icedteanp/IcedTeaPluginRequestProcessor.cc, * plugin/icedteanp/IcedTeaPluginRequestProcessor.h, * plugin/icedteanp/IcedTeaPluginUtils.cc, * plugin/icedteanp/IcedTeaPluginUtils.h, * plugin/icedteanp/IcedTeaRunnable.cc, * plugin/icedteanp/IcedTeaRunnable.h, * plugin/icedteanp/IcedTeaScriptablePluginObject.cc, * plugin/icedteanp/IcedTeaScriptablePluginObject.h, * plugin/icedteanp/java/netscape/javascript/JSException.java, * plugin/icedteanp/java/netscape/javascript/JSObject.java, * plugin/icedteanp/java/netscape/javascript/JSObjectCreatePermission.java, * plugin/icedteanp/java/netscape/javascript/JSProxy.java, * plugin/icedteanp/java/netscape/javascript/JSRunnable.java, * plugin/icedteanp/java/netscape/javascript/JSUtil.java, * plugin/icedteanp/java/netscape/security/ForbiddenTargetException.java, * plugin/icedteanp/java/sun/applet/AppletSecurityContextManager.java, * plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java, * plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java, * plugin/icedteanp/java/sun/applet/JavaConsole.java, * plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java, * plugin/icedteanp/java/sun/applet/PasswordAuthenticationDialog.java, * plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java, * plugin/icedteanp/java/sun/applet/PluginAppletViewer.java, * plugin/icedteanp/java/sun/applet/PluginCallRequest.java, * plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java, * plugin/icedteanp/java/sun/applet/PluginClassLoader.java, * plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java, * plugin/icedteanp/java/sun/applet/PluginCookieManager.java, * plugin/icedteanp/java/sun/applet/PluginDebug.java, * plugin/icedteanp/java/sun/applet/PluginException.java, * plugin/icedteanp/java/sun/applet/PluginMain.java, * plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java, * plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java, * plugin/icedteanp/java/sun/applet/PluginObjectStore.java, * plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java, * plugin/icedteanp/java/sun/applet/PluginProxySelector.java, * plugin/icedteanp/java/sun/applet/PluginStreamHandler.java, * plugin/icedteanp/java/sun/applet/RequestQueue.java, * plugin/icedteanp/java/sun/applet/TestEnv.java, * plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java, * plugin/tests/LiveConnect/DummyObject.java, * plugin/tests/LiveConnect/OverloadTestHelper1.java, * plugin/tests/LiveConnect/OverloadTestHelper2.java, * plugin/tests/LiveConnect/OverloadTestHelper3.java, * plugin/tests/LiveConnect/PluginTest.java, * plugin/tests/LiveConnect/build, * plugin/tests/LiveConnect/common.js, * plugin/tests/LiveConnect/index.html, * plugin/tests/LiveConnect/jjs_eval_test.js, * plugin/tests/LiveConnect/jjs_func_parameters_tests.js, * plugin/tests/LiveConnect/jjs_func_rettype_tests.js, * plugin/tests/LiveConnect/jjs_get_tests.js, * plugin/tests/LiveConnect/jjs_set_tests.js, * plugin/tests/LiveConnect/jsj_func_overload_tests.js, * plugin/tests/LiveConnect/jsj_func_parameters_tests.js, * plugin/tests/LiveConnect/jsj_func_rettype_tests.js, * plugin/tests/LiveConnect/jsj_get_tests.js, * plugin/tests/LiveConnect/jsj_set_tests.js, * plugin/tests/LiveConnect/jsj_type_casting_tests.js, * plugin/tests/LiveConnect/jsj_type_conversion_tests.js: Initial import from IcedTea6. * AUTHORS, * COPYING * INSTALL, * NEWS, * README: New documentation.
Diffstat (limited to 'plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java')
-rw-r--r--plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java696
1 files changed, 696 insertions, 0 deletions
diff --git a/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java b/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
new file mode 100644
index 0000000..bb41e27
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
@@ -0,0 +1,696 @@
+/* MethodOverloadResolver -- Resolves overloaded methods
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+/*
+ * This class resolved overloaded methods in Java objects using a cost
+ * based-approach as described here:
+ *
+ * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
+ */
+
+public class MethodOverloadResolver {
+
+ private static boolean debugging = false;
+
+ public static void main(String[] args) {
+ testMethodResolver();
+ }
+
+ 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");
+
+ }
+
+ }
+
+ /*
+ * Cost based overload resolution algorithm based on cost rules specified here:
+ *
+ * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
+ */
+
+ public static Object[] getMatchingMethod(Object[] callList) {
+ Object[] ret = null;
+ Class c = (Class) callList[0];
+ String methodName = (String) callList[1];
+
+ Method[] matchingMethods = getMatchingMethods(c, methodName, callList.length - 2);
+
+ if (debugging)
+ System.out.println("getMatchingMethod called with: " + printList(callList));
+
+ int lowestCost = Integer.MAX_VALUE;
+
+ ArrayList<Object> paramList = new ArrayList<Object>();
+
+ for (Method matchingMethod : matchingMethods) {
+
+ int methodCost = 0;
+ Class[] paramTypes = matchingMethod.getParameterTypes();
+ Object[] methodAndArgs = new Object[paramTypes.length + 1];
+ methodAndArgs[0] = matchingMethod;
+
+ // 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;
+
+ Object[] costAndCastedObj = getCostAndCastedObject(
+ suppliedParam, paramTypeClass);
+ methodCost += (Integer) costAndCastedObj[0];
+
+ if ((Integer) costAndCastedObj[0] < 0) break;
+
+ Object castedObj = paramTypeClass.isPrimitive() ? costAndCastedObj[1]
+ : paramTypeClass.cast(costAndCastedObj[1]);
+ methodAndArgs[i + 1] = castedObj;
+
+ Class castedObjClass = castedObj == null ? null : castedObj
+ .getClass();
+ Boolean castedObjIsPrim = castedObj == null ? null : castedObj
+ .getClass().isPrimitive();
+
+ 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);
+ }
+
+ if ((methodCost > 0 && methodCost < lowestCost) ||
+ paramTypes.length == 0) {
+ ret = methodAndArgs;
+ lowestCost = methodCost;
+ }
+
+ }
+
+ return ret;
+ }
+
+ 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));
+
+ int lowestCost = Integer.MAX_VALUE;
+
+ ArrayList<Object> paramList = new ArrayList<Object>();
+
+ for (Constructor matchingConstructor : matchingConstructors) {
+
+ int constructorCost = 0;
+ Class[] paramTypes = matchingConstructor.getParameterTypes();
+ Object[] constructorAndArgs = new Object[paramTypes.length + 1];
+ constructorAndArgs[0] = matchingConstructor;
+
+ // 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[] costAndCastedObj = getCostAndCastedObject(
+ suppliedParam, paramTypeClass);
+ constructorCost += (Integer) costAndCastedObj[0];
+
+ if ((Integer) costAndCastedObj[0] < 0) break;
+
+ Object castedObj = paramTypeClass.isPrimitive() ? costAndCastedObj[1]
+ : paramTypeClass.cast(costAndCastedObj[1]);
+ constructorAndArgs[i + 1] = castedObj;
+
+ Class castedObjClass = castedObj == null ? null : castedObj
+ .getClass();
+ Boolean castedObjIsPrim = castedObj == null ? null : castedObj
+ .getClass().isPrimitive();
+
+ if (debugging)
+ System.out.println("Param " + i + " of constructor "
+ + matchingConstructor + " has cost "
+ + (Integer) costAndCastedObj[0]
+ + " original param type " + suppliedParamClass
+ + " casted to " + castedObjClass + " isPrimitive="
+ + castedObjIsPrim + " value " + castedObj);
+ }
+
+ if ((constructorCost > 0 && constructorCost < lowestCost) ||
+ paramTypes.length == 0) {
+ ret = constructorAndArgs;
+ lowestCost = constructorCost;
+ }
+ }
+
+ return ret;
+ }
+
+ public static Object[] getCostAndCastedObject(Object suppliedParam, Class paramTypeClass) {
+
+ Object[] ret = new Object[2];
+ Integer cost = new Integer(0);
+ Object castedObj;
+
+ Class suppliedParamClass = suppliedParam != null ? suppliedParam.getClass() : null ;
+
+ // 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;
+ }
+
+ // 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 (paramTypeClass.isArray()) {
+
+ 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
+
+ if (original == null && paramTypeClass.getComponentType().isPrimitive())
+ original = 0;
+
+ Object[] costAndCastedObject = getCostAndCastedObject(original, paramTypeClass.getComponentType());
+
+ if ((Integer) costAndCastedObject[0] < 0) {
+ ret[0] = Integer.MIN_VALUE; // Not allowed
+ ret[1] = suppliedParam;
+ return ret;
+ }
+
+ Array.set(newArray, i, costAndCastedObject[1]);
+ }
+
+ ret[0] = 9;
+ ret[1] = newArray;
+ return ret;
+ }
+
+ if (suppliedParamIsArray && paramTypeClass.equals(String.class)) {
+
+ ret[0] = 9;
+ ret[1] = getArrayAsString(suppliedParam);
+ return ret;
+ }
+
+ // If this is null, there are only 2 possible cases
+ if (suppliedParamClass == null) {
+ castedObj = null; // if value is null.. well, it is null
+
+ if (!paramTypeClass.isPrimitive()) {
+ cost += 2; // Null to any non-primitive type
+ } else {
+ cost = Integer.MIN_VALUE; // Null to primitive not allowed
+ }
+ } 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;
+
+ return ret;
+
+ }
+
+ private static Method[] getMatchingMethods(Class c, String name, int paramCount) {
+ Method[] allMethods = c.getMethods();
+ ArrayList<Method> matchingMethods = new ArrayList(5);
+
+ for (Method m: allMethods) {
+ if (m.getName().equals(name) && 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);
+
+ for (Constructor cs: allConstructors) {
+ 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;
+ }
+
+ return o.getClass();
+ }
+
+ 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;
+
+ // At this point, it _has_ to be a string else automatically
+ // return false
+ if (!(o instanceof java.lang.String))
+ return false;
+
+ try {
+ Long.parseLong((String) o); // whole number test
+ return true;
+ } catch (NumberFormatException nfe) {}
+
+ try {
+ Float.parseFloat((String) o); // decimal
+ return true;
+ } catch (NumberFormatException nfe) {}
+
+
+ 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);
+
+ // 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 (c.equals(java.lang.Float.class) ||
+ c.equals(java.lang.Float.TYPE)) {
+ return n.floatValue();
+ }
+
+ 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();
+ }
+
+ return n;
+ }
+
+ 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 += ", ";
+ }
+ 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
+
+ String ret = new String();
+
+ for (int i=0; i < Array.getLength(array); i++) {
+ Object element = Array.get(array, i);
+
+ if (element != null) {
+ if (element.getClass().isArray()) {
+ ret += getArrayAsString(element);
+ } else {
+ ret += element;
+ }
+ }
+
+ ret += ",";
+ }
+
+ // Trim the final ","
+ if (ret.length() > 0) {
+ ret = ret.substring(0, ret.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) {}
+
+ 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 {}