diff options
author | andrew <devnull@localhost> | 2010-10-19 17:55:59 +0100 |
---|---|---|
committer | andrew <devnull@localhost> | 2010-10-19 17:55:59 +0100 |
commit | 7603e948d7a0a7eb2e72358cb4a40ae6779f95da (patch) | |
tree | c6441f7d14eafe8119d890cddd09b05b8f88c52a /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.java | 696 |
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 {} |