rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 25 Jun 2014 22:50:33 +0200
branchdefprop
changeset 1636 eb97a082741b
parent 1586 d4ee65642d8d
child 1637 4156b1bd4b82
permissions -rw-r--r--
Methods on object need to be manually enumerated
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.bck2brwsr.emul.reflect;
    19 
    20 import java.lang.reflect.Array;
    21 import java.lang.reflect.Constructor;
    22 import java.lang.reflect.Method;
    23 import java.util.Enumeration;
    24 import org.apidesign.bck2brwsr.core.Exported;
    25 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    26 
    27 /** Utilities to work on methods.
    28  *
    29  * @author Jaroslav Tulach <jtulach@netbeans.org>
    30  */
    31 public abstract class MethodImpl {
    32     public static MethodImpl INSTANCE;
    33     static {
    34         try {
    35             Class.forName(Method.class.getName());
    36         } catch (ClassNotFoundException ex) {
    37             throw new IllegalStateException(ex);
    38         }
    39     }
    40 
    41     protected abstract Method create(Class<?> declaringClass, String name, Object data, String sig);
    42     protected abstract Constructor create(Class<?> declaringClass, Object data, String sig);
    43     
    44     
    45     //
    46     // bck2brwsr implementation
    47     //
    48 
    49     @JavaScriptBody(args = {"clazz", "prefix", "cnstr"},
    50         body = ""
    51         + "var c = clazz.cnstr;\n"
    52         + "if (!cnstr) c = c.prototype;\n"
    53         + "var arr = new Array();\n"
    54         + "function check(m) {\n"
    55         + "  if (m.indexOf(prefix) === 0) {\n"
    56         + "     if (!c[m].cls) return;\n"
    57         + "     arr.push(m);\n"
    58         + "     arr.push(c[m]);\n"
    59         + "     arr.push(c[m].cls.$class);\n"
    60         + "  }\n"
    61         + "}\n"
    62         + "for (m in c) {\n"
    63         + "  check(m)\n"
    64         + "}\n"
    65         + "check('wait__V');\n"
    66         + "check('wait__VJ');\n"
    67         + "check('wait__VJI');\n"
    68         + "check('equals__ZLjava_lang_Object_2');\n"
    69         + "check('toString__Ljava_lang_String_2');\n"
    70         + "check('hashCode__I');\n"
    71         + "check('getClass__Ljava_lang_Class_2');\n"
    72         + "check('notify__V');\n"
    73         + "check('notifyAll__V');\n"
    74         + "return arr;\n")
    75     private static native Object[] findMethodData(
    76         Class<?> clazz, String prefix, boolean cnstr);
    77 
    78     public static Constructor findConstructor(
    79         Class<?> clazz, Class<?>... parameterTypes) {
    80         Object[] data = findMethodData(clazz, "cons__", true);
    81         BIG: for (int i = 0; i < data.length; i += 3) {
    82             String sig = ((String) data[i]).substring(6);
    83             Class<?> cls = (Class<?>) data[i + 2];
    84             Constructor tmp = INSTANCE.create(cls, data[i + 1], sig);
    85             Class<?>[] tmpParms = tmp.getParameterTypes();
    86             if (parameterTypes.length != tmpParms.length) {
    87                 continue;
    88             }
    89             for (int j = 0; j < tmpParms.length; j++) {
    90                 if (!parameterTypes[j].equals(tmpParms[j])) {
    91                     continue BIG;
    92                 }
    93             }
    94             return tmp;
    95         }
    96         return null;
    97     }
    98 
    99     public static Constructor[] findConstructors(Class<?> clazz, int mask) {
   100         Object[] namesAndData = findMethodData(clazz, "", true);
   101         int cnt = 0;
   102         for (int i = 0; i < namesAndData.length; i += 3) {
   103             String sig = (String) namesAndData[i];
   104             Object data = namesAndData[i + 1];
   105             if (!sig.startsWith("cons__")) {
   106                 continue;
   107             }
   108             sig = sig.substring(6);
   109             Class<?> cls = (Class<?>) namesAndData[i + 2];
   110             final Constructor m = INSTANCE.create(cls, data, sig);
   111             if ((m.getModifiers() & mask) == 0) {
   112                 continue;
   113             }
   114             namesAndData[cnt++] = m;
   115         }
   116         Constructor[] arr = new Constructor[cnt];
   117         for (int i = 0; i < cnt; i++) {
   118             arr[i] = (Constructor) namesAndData[i];
   119         }
   120         return arr;
   121     }
   122     public static Method findMethod(
   123         Class<?> clazz, String name, Class<?>... parameterTypes) {
   124         Object[] data = findMethodData(clazz, name + "__", false);
   125         BIG: for (int i = 0; i < data.length; i += 3) {
   126             String sig = ((String) data[i]).substring(name.length() + 2);
   127             Class<?> cls = (Class<?>) data[i + 2];
   128             Method tmp = INSTANCE.create(cls, name, data[i + 1], sig);
   129             Class<?>[] tmpParms = tmp.getParameterTypes();
   130             if (parameterTypes.length != tmpParms.length) {
   131                 continue;
   132             }
   133             for (int j = 0; j < tmpParms.length; j++) {
   134                 if (!parameterTypes[j].equals(tmpParms[j])) {
   135                     continue BIG;
   136                 }
   137             }
   138             return tmp;
   139         }
   140         return null;
   141     }
   142     
   143     public static Method[] findMethods(Class<?> clazz, int mask) {
   144         Object[] namesAndData = findMethodData(clazz, "", false);
   145         int cnt = 0;
   146         for (int i = 0; i < namesAndData.length; i += 3) {
   147             String sig = (String) namesAndData[i];
   148             Object data = namesAndData[i + 1];
   149             int middle = sig.indexOf("__");
   150             if (middle == -1) {
   151                 continue;
   152             }
   153             if (sig.startsWith("$") && sig.endsWith("$")) {
   154                 // produced by Closure compiler in debug mode
   155                 // needs to be ignored
   156                 continue;
   157             }
   158             String name = sig.substring(0, middle);
   159             sig = sig.substring(middle + 2);
   160             Class<?> cls = (Class<?>) namesAndData[i + 2];
   161             final Method m = INSTANCE.create(cls, name, data, sig);
   162             if ((m.getModifiers() & mask) == 0) {
   163                 continue;
   164             }
   165             namesAndData[cnt++] = m;
   166         }
   167         Method[] arr = new Method[cnt];
   168         for (int i = 0; i < cnt; i++) {
   169             arr[i] = (Method) namesAndData[i];
   170         }
   171         return arr;
   172     }
   173     
   174     @Exported static String toSignature(Method m) {
   175         StringBuilder sb = new StringBuilder();
   176         sb.append(m.getName()).append("__");
   177         appendType(sb, m.getReturnType());
   178         Class<?>[] arr = m.getParameterTypes();
   179         for (int i = 0; i < arr.length; i++) {
   180             appendType(sb, arr[i]);
   181         }
   182         return sb.toString();
   183     }
   184     
   185     private static void appendType(StringBuilder sb, Class<?> type) {
   186         if (type == Integer.TYPE) {
   187             sb.append('I');
   188             return;
   189         }
   190         if (type == Long.TYPE) {
   191             sb.append('J');
   192             return;
   193         }
   194         if (type == Double.TYPE) {
   195             sb.append('D');
   196             return;
   197         }
   198         if (type == Float.TYPE) {
   199             sb.append('F');
   200             return;
   201         }
   202         if (type == Byte.TYPE) {
   203             sb.append('B');
   204             return;
   205         }
   206         if (type == Boolean.TYPE) {
   207             sb.append('Z');
   208             return;
   209         }
   210         if (type == Short.TYPE) {
   211             sb.append('S');
   212             return;
   213         }
   214         if (type == Void.TYPE) {
   215             sb.append('V');
   216             return;
   217         }
   218         if (type == Character.TYPE) {
   219             sb.append('C');
   220             return;
   221         }
   222         if (type.isArray()) {
   223             sb.append("_3");
   224             appendType(sb, type.getComponentType());
   225             return;
   226         }
   227         sb.append('L').append(type.getName().replace('.', '_'));
   228         sb.append("_2");
   229     }
   230 
   231     public static int signatureElements(String sig) {
   232         Enumeration<Class> en = signatureParser(sig);
   233         int cnt = 0;
   234         while (en.hasMoreElements()) {
   235             en.nextElement();
   236             cnt++;
   237         }
   238         return cnt;
   239     }
   240     
   241     public static Enumeration<Class> signatureParser(final String sig) {
   242         class E implements Enumeration<Class> {
   243             int pos;
   244             int len;
   245             
   246             E() {
   247                 len = sig.length();
   248                 while (sig.charAt(len - 1) == '$') {
   249                     len--;
   250                 }
   251             }
   252             
   253             public boolean hasMoreElements() {
   254                 return pos < len;
   255             }
   256 
   257             public Class nextElement() {
   258                 switch (sig.charAt(pos++)) {
   259                     case 'I':
   260                         return Integer.TYPE;
   261                     case 'J':
   262                         return Long.TYPE;
   263                     case 'D':
   264                         return Double.TYPE;
   265                     case 'F':
   266                         return Float.TYPE;
   267                     case 'B':
   268                         return Byte.TYPE;
   269                     case 'Z':
   270                         return Boolean.TYPE;
   271                     case 'S':
   272                         return Short.TYPE;
   273                     case 'V':
   274                         return Void.TYPE;
   275                     case 'C':
   276                         return Character.TYPE;
   277                     case 'L':
   278                         try {
   279                             int up = sig.indexOf("_2", pos);
   280                             String type = sig.substring(pos, up);
   281                             pos = up + 2;
   282                             return Class.forName(type.replace('_', '.'));
   283                         } catch (ClassNotFoundException ex) {
   284                             throw new IllegalStateException(ex);
   285                         }
   286                     case '_': {
   287                         char nch = sig.charAt(pos++);
   288                         assert nch == '3' : "Can't find '3' at " + sig.substring(pos - 1);
   289                         final Class compType = nextElement();
   290                         return Array.newInstance(compType, 0).getClass();
   291                     }
   292                 }
   293                 throw new UnsupportedOperationException(sig + " at " + pos);
   294             }
   295         }
   296         return new E();
   297     }
   298 }