jaroslav@604: /** jaroslav@604: * Back 2 Browser Bytecode Translator jaroslav@604: * Copyright (C) 2012 Jaroslav Tulach jaroslav@391: * jaroslav@604: * This program is free software: you can redistribute it and/or modify jaroslav@604: * it under the terms of the GNU General Public License as published by jaroslav@604: * the Free Software Foundation, version 2 of the License. jaroslav@391: * jaroslav@604: * This program is distributed in the hope that it will be useful, jaroslav@604: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@604: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@604: * GNU General Public License for more details. jaroslav@391: * jaroslav@604: * You should have received a copy of the GNU General Public License jaroslav@604: * along with this program. Look for COPYING file in the top folder. jaroslav@604: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@391: */ jaroslav@555: package org.apidesign.bck2brwsr.emul.reflect; jaroslav@391: jaroslav@650: import java.lang.reflect.Array; jaroslav@391: import java.lang.reflect.Method; jaroslav@418: import java.util.Enumeration; jaroslav@391: import org.apidesign.bck2brwsr.core.JavaScriptBody; jaroslav@391: jaroslav@391: /** Utilities to work on methods. jaroslav@391: * jaroslav@391: * @author Jaroslav Tulach jaroslav@391: */ jaroslav@391: public abstract class MethodImpl { jaroslav@391: public static MethodImpl INSTANCE; jaroslav@391: static { jaroslav@391: try { jaroslav@391: Class.forName(Method.class.getName()); jaroslav@391: } catch (ClassNotFoundException ex) { jaroslav@391: throw new IllegalStateException(ex); jaroslav@391: } jaroslav@391: } jaroslav@650: jaroslav@391: protected abstract Method create(Class declaringClass, String name, Object data, String sig); jaroslav@391: jaroslav@391: jaroslav@391: // jaroslav@391: // bck2brwsr implementation jaroslav@391: // jaroslav@391: jaroslav@391: @JavaScriptBody(args = {"clazz", "prefix"}, jaroslav@391: body = "" jaroslav@391: + "var c = clazz.cnstr.prototype;" jaroslav@391: + "var arr = new Array();\n" jaroslav@391: + "for (m in c) {\n" jaroslav@391: + " if (m.indexOf(prefix) === 0) {\n" jaroslav@654: + " if (!c[m].cls) continue;\n" jaroslav@391: + " arr.push(m);\n" jaroslav@391: + " arr.push(c[m]);\n" jaroslav@654: + " arr.push(c[m].cls.$class);\n" jaroslav@391: + " }" jaroslav@391: + "}\n" jaroslav@391: + "return arr;") jaroslav@391: private static native Object[] findMethodData( jaroslav@391: Class clazz, String prefix); jaroslav@391: jaroslav@391: public static Method findMethod( jaroslav@391: Class clazz, String name, Class... parameterTypes) { jaroslav@391: Object[] data = findMethodData(clazz, name + "__"); jaroslav@654: BIG: for (int i = 0; i < data.length; i += 3) { jaroslav@654: String sig = ((String) data[i]).substring(name.length() + 2); jaroslav@654: Class cls = (Class) data[i + 2]; jaroslav@654: Method tmp = INSTANCE.create(cls, name, data[i + 1], sig); jaroslav@420: Class[] tmpParms = tmp.getParameterTypes(); jaroslav@420: if (parameterTypes.length != tmpParms.length) { jaroslav@420: continue; jaroslav@420: } jaroslav@420: for (int j = 0; j < tmpParms.length; j++) { jaroslav@420: if (!parameterTypes[j].equals(tmpParms[j])) { jaroslav@420: continue BIG; jaroslav@420: } jaroslav@420: } jaroslav@420: return tmp; jaroslav@391: } jaroslav@420: return null; jaroslav@391: } jaroslav@391: jaroslav@392: public static Method[] findMethods(Class clazz, int mask) { jaroslav@391: Object[] namesAndData = findMethodData(clazz, ""); jaroslav@391: int cnt = 0; jaroslav@654: for (int i = 0; i < namesAndData.length; i += 3) { jaroslav@391: String sig = (String) namesAndData[i]; jaroslav@391: Object data = namesAndData[i + 1]; jaroslav@391: int middle = sig.indexOf("__"); jaroslav@391: if (middle == -1) { jaroslav@391: continue; jaroslav@391: } jaroslav@391: String name = sig.substring(0, middle); jaroslav@391: sig = sig.substring(middle + 2); jaroslav@654: Class cls = (Class) namesAndData[i + 2]; jaroslav@654: final Method m = INSTANCE.create(cls, name, data, sig); jaroslav@392: if ((m.getModifiers() & mask) == 0) { jaroslav@392: continue; jaroslav@392: } jaroslav@392: namesAndData[cnt++] = m; jaroslav@391: } jaroslav@391: Method[] arr = new Method[cnt]; jaroslav@391: for (int i = 0; i < cnt; i++) { jaroslav@391: arr[i] = (Method) namesAndData[i]; jaroslav@391: } jaroslav@391: return arr; jaroslav@391: } jaroslav@650: static String toSignature(Method m) { jaroslav@650: StringBuilder sb = new StringBuilder(); jaroslav@650: sb.append(m.getName()).append("__"); jaroslav@650: appendType(sb, m.getReturnType()); jaroslav@650: Class[] arr = m.getParameterTypes(); jaroslav@650: for (int i = 0; i < arr.length; i++) { jaroslav@650: appendType(sb, arr[i]); jaroslav@650: } jaroslav@650: return sb.toString(); jaroslav@650: } jaroslav@650: jaroslav@650: private static void appendType(StringBuilder sb, Class type) { jaroslav@650: if (type == Integer.TYPE) { jaroslav@650: sb.append('I'); jaroslav@650: return; jaroslav@650: } jaroslav@650: if (type == Long.TYPE) { jaroslav@650: sb.append('J'); jaroslav@650: return; jaroslav@650: } jaroslav@650: if (type == Double.TYPE) { jaroslav@650: sb.append('D'); jaroslav@650: return; jaroslav@650: } jaroslav@650: if (type == Float.TYPE) { jaroslav@650: sb.append('F'); jaroslav@650: return; jaroslav@650: } jaroslav@650: if (type == Byte.TYPE) { jaroslav@650: sb.append('B'); jaroslav@650: return; jaroslav@650: } jaroslav@650: if (type == Boolean.TYPE) { jaroslav@650: sb.append('Z'); jaroslav@650: return; jaroslav@650: } jaroslav@650: if (type == Short.TYPE) { jaroslav@650: sb.append('S'); jaroslav@650: return; jaroslav@650: } jaroslav@650: if (type == Void.TYPE) { jaroslav@650: sb.append('V'); jaroslav@650: return; jaroslav@650: } jaroslav@650: if (type == Character.TYPE) { jaroslav@650: sb.append('C'); jaroslav@650: return; jaroslav@650: } jaroslav@650: if (type.isArray()) { jaroslav@650: sb.append("_3"); jaroslav@650: appendType(sb, type.getComponentType()); jaroslav@650: return; jaroslav@650: } jaroslav@650: sb.append('L').append(type.getName().replace('.', '_')); jaroslav@650: sb.append("_2"); jaroslav@650: } jaroslav@418: jaroslav@418: public static int signatureElements(String sig) { jaroslav@418: Enumeration en = signatureParser(sig); jaroslav@418: int cnt = 0; jaroslav@418: while (en.hasMoreElements()) { jaroslav@418: en.nextElement(); jaroslav@418: cnt++; jaroslav@418: } jaroslav@418: return cnt; jaroslav@418: } jaroslav@391: jaroslav@418: public static Enumeration signatureParser(final String sig) { jaroslav@418: class E implements Enumeration { jaroslav@418: int pos; jaroslav@418: jaroslav@418: public boolean hasMoreElements() { jaroslav@418: return pos < sig.length(); jaroslav@418: } jaroslav@418: jaroslav@418: public Class nextElement() { jaroslav@418: switch (sig.charAt(pos++)) { jaroslav@418: case 'I': jaroslav@418: return Integer.TYPE; jaroslav@418: case 'J': jaroslav@418: return Long.TYPE; jaroslav@418: case 'D': jaroslav@418: return Double.TYPE; jaroslav@418: case 'F': jaroslav@418: return Float.TYPE; jaroslav@418: case 'B': jaroslav@418: return Byte.TYPE; jaroslav@418: case 'Z': jaroslav@418: return Boolean.TYPE; jaroslav@418: case 'S': jaroslav@418: return Short.TYPE; jaroslav@418: case 'V': jaroslav@418: return Void.TYPE; jaroslav@430: case 'C': jaroslav@430: return Character.TYPE; jaroslav@418: case 'L': jaroslav@418: try { jaroslav@650: int up = sig.indexOf("_2", pos); jaroslav@650: String type = sig.substring(pos, up); jaroslav@418: pos = up + 2; jaroslav@650: return Class.forName(type.replace('_', '.')); jaroslav@418: } catch (ClassNotFoundException ex) { jaroslav@650: throw new IllegalStateException(ex); jaroslav@418: } jaroslav@650: case '_': { jaroslav@650: char nch = sig.charAt(pos++); jaroslav@650: assert nch == '3' : "Can't find '3' at " + sig.substring(pos - 1); jaroslav@650: final Class compType = nextElement(); jaroslav@650: return Array.newInstance(compType, 0).getClass(); jaroslav@650: } jaroslav@418: } jaroslav@418: throw new UnsupportedOperationException(sig + " at " + pos); jaroslav@418: } jaroslav@418: } jaroslav@418: return new E(); jaroslav@418: } jaroslav@391: }