rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 26 Feb 2013 16:54:16 +0100
changeset 772 d382dacfd73f
parent 666 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java@8338ab1991e6
child 1321 7a78a84ab583
permissions -rw-r--r--
Moving modules around so the runtime is under one master pom and can be built without building other modules that are in the repository
     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.Method;
    22 import java.util.Enumeration;
    23 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    24 
    25 /** Utilities to work on methods.
    26  *
    27  * @author Jaroslav Tulach <jtulach@netbeans.org>
    28  */
    29 public abstract class MethodImpl {
    30     public static MethodImpl INSTANCE;
    31     static {
    32         try {
    33             Class.forName(Method.class.getName());
    34         } catch (ClassNotFoundException ex) {
    35             throw new IllegalStateException(ex);
    36         }
    37     }
    38 
    39     protected abstract Method create(Class<?> declaringClass, String name, Object data, String sig);
    40     
    41     
    42     //
    43     // bck2brwsr implementation
    44     //
    45 
    46     @JavaScriptBody(args = {"clazz", "prefix"},
    47         body = ""
    48         + "var c = clazz.cnstr.prototype;"
    49         + "var arr = new Array();\n"
    50         + "for (m in c) {\n"
    51         + "  if (m.indexOf(prefix) === 0) {\n"
    52         + "     if (!c[m].cls) continue;\n"
    53         + "     arr.push(m);\n"
    54         + "     arr.push(c[m]);\n"
    55         + "     arr.push(c[m].cls.$class);\n"
    56         + "  }"
    57         + "}\n"
    58         + "return arr;")
    59     private static native Object[] findMethodData(
    60         Class<?> clazz, String prefix);
    61 
    62     public static Method findMethod(
    63         Class<?> clazz, String name, Class<?>... parameterTypes) {
    64         Object[] data = findMethodData(clazz, name + "__");
    65         BIG: for (int i = 0; i < data.length; i += 3) {
    66             String sig = ((String) data[i]).substring(name.length() + 2);
    67             Class<?> cls = (Class<?>) data[i + 2];
    68             Method tmp = INSTANCE.create(cls, name, data[i + 1], sig);
    69             Class<?>[] tmpParms = tmp.getParameterTypes();
    70             if (parameterTypes.length != tmpParms.length) {
    71                 continue;
    72             }
    73             for (int j = 0; j < tmpParms.length; j++) {
    74                 if (!parameterTypes[j].equals(tmpParms[j])) {
    75                     continue BIG;
    76                 }
    77             }
    78             return tmp;
    79         }
    80         return null;
    81     }
    82 
    83     public static Method[] findMethods(Class<?> clazz, int mask) {
    84         Object[] namesAndData = findMethodData(clazz, "");
    85         int cnt = 0;
    86         for (int i = 0; i < namesAndData.length; i += 3) {
    87             String sig = (String) namesAndData[i];
    88             Object data = namesAndData[i + 1];
    89             int middle = sig.indexOf("__");
    90             if (middle == -1) {
    91                 continue;
    92             }
    93             String name = sig.substring(0, middle);
    94             sig = sig.substring(middle + 2);
    95             Class<?> cls = (Class<?>) namesAndData[i + 2];
    96             final Method m = INSTANCE.create(cls, name, data, sig);
    97             if ((m.getModifiers() & mask) == 0) {
    98                 continue;
    99             }
   100             namesAndData[cnt++] = m;
   101         }
   102         Method[] arr = new Method[cnt];
   103         for (int i = 0; i < cnt; i++) {
   104             arr[i] = (Method) namesAndData[i];
   105         }
   106         return arr;
   107     }
   108     static String toSignature(Method m) {
   109         StringBuilder sb = new StringBuilder();
   110         sb.append(m.getName()).append("__");
   111         appendType(sb, m.getReturnType());
   112         Class<?>[] arr = m.getParameterTypes();
   113         for (int i = 0; i < arr.length; i++) {
   114             appendType(sb, arr[i]);
   115         }
   116         return sb.toString();
   117     }
   118     
   119     private static void appendType(StringBuilder sb, Class<?> type) {
   120         if (type == Integer.TYPE) {
   121             sb.append('I');
   122             return;
   123         }
   124         if (type == Long.TYPE) {
   125             sb.append('J');
   126             return;
   127         }
   128         if (type == Double.TYPE) {
   129             sb.append('D');
   130             return;
   131         }
   132         if (type == Float.TYPE) {
   133             sb.append('F');
   134             return;
   135         }
   136         if (type == Byte.TYPE) {
   137             sb.append('B');
   138             return;
   139         }
   140         if (type == Boolean.TYPE) {
   141             sb.append('Z');
   142             return;
   143         }
   144         if (type == Short.TYPE) {
   145             sb.append('S');
   146             return;
   147         }
   148         if (type == Void.TYPE) {
   149             sb.append('V');
   150             return;
   151         }
   152         if (type == Character.TYPE) {
   153             sb.append('C');
   154             return;
   155         }
   156         if (type.isArray()) {
   157             sb.append("_3");
   158             appendType(sb, type.getComponentType());
   159             return;
   160         }
   161         sb.append('L').append(type.getName().replace('.', '_'));
   162         sb.append("_2");
   163     }
   164 
   165     public static int signatureElements(String sig) {
   166         Enumeration<Class> en = signatureParser(sig);
   167         int cnt = 0;
   168         while (en.hasMoreElements()) {
   169             en.nextElement();
   170             cnt++;
   171         }
   172         return cnt;
   173     }
   174     
   175     public static Enumeration<Class> signatureParser(final String sig) {
   176         class E implements Enumeration<Class> {
   177             int pos;
   178             
   179             public boolean hasMoreElements() {
   180                 return pos < sig.length();
   181             }
   182 
   183             public Class nextElement() {
   184                 switch (sig.charAt(pos++)) {
   185                     case 'I':
   186                         return Integer.TYPE;
   187                     case 'J':
   188                         return Long.TYPE;
   189                     case 'D':
   190                         return Double.TYPE;
   191                     case 'F':
   192                         return Float.TYPE;
   193                     case 'B':
   194                         return Byte.TYPE;
   195                     case 'Z':
   196                         return Boolean.TYPE;
   197                     case 'S':
   198                         return Short.TYPE;
   199                     case 'V':
   200                         return Void.TYPE;
   201                     case 'C':
   202                         return Character.TYPE;
   203                     case 'L':
   204                         try {
   205                             int up = sig.indexOf("_2", pos);
   206                             String type = sig.substring(pos, up);
   207                             pos = up + 2;
   208                             return Class.forName(type.replace('_', '.'));
   209                         } catch (ClassNotFoundException ex) {
   210                             throw new IllegalStateException(ex);
   211                         }
   212                     case '_': {
   213                         char nch = sig.charAt(pos++);
   214                         assert nch == '3' : "Can't find '3' at " + sig.substring(pos - 1);
   215                         final Class compType = nextElement();
   216                         return Array.newInstance(compType, 0).getClass();
   217                     }
   218                 }
   219                 throw new UnsupportedOperationException(sig + " at " + pos);
   220             }
   221         }
   222         return new E();
   223     }
   224 }