emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sun, 03 Feb 2013 22:58:42 +0100
branchreflection
changeset 654 26a86cc00224
parent 650 2569d9dd4b28
child 666 8338ab1991e6
permissions -rw-r--r--
Correct getDeclaringClass for returned methods
     1 /*
     2  * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 package org.apidesign.bck2brwsr.emul.reflect;
    26 
    27 import java.lang.reflect.Array;
    28 import java.lang.reflect.Method;
    29 import java.util.Enumeration;
    30 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    31 
    32 /** Utilities to work on methods.
    33  *
    34  * @author Jaroslav Tulach <jtulach@netbeans.org>
    35  */
    36 public abstract class MethodImpl {
    37     public static MethodImpl INSTANCE;
    38     static {
    39         try {
    40             Class.forName(Method.class.getName());
    41         } catch (ClassNotFoundException ex) {
    42             throw new IllegalStateException(ex);
    43         }
    44     }
    45 
    46     protected abstract Method create(Class<?> declaringClass, String name, Object data, String sig);
    47     
    48     
    49     //
    50     // bck2brwsr implementation
    51     //
    52 
    53     @JavaScriptBody(args = {"clazz", "prefix"},
    54         body = ""
    55         + "var c = clazz.cnstr.prototype;"
    56         + "var arr = new Array();\n"
    57         + "for (m in c) {\n"
    58         + "  if (m.indexOf(prefix) === 0) {\n"
    59         + "     if (!c[m].cls) continue;\n"
    60         + "     arr.push(m);\n"
    61         + "     arr.push(c[m]);\n"
    62         + "     arr.push(c[m].cls.$class);\n"
    63         + "  }"
    64         + "}\n"
    65         + "return arr;")
    66     private static native Object[] findMethodData(
    67         Class<?> clazz, String prefix);
    68 
    69     public static Method findMethod(
    70         Class<?> clazz, String name, Class<?>... parameterTypes) {
    71         Object[] data = findMethodData(clazz, name + "__");
    72         BIG: for (int i = 0; i < data.length; i += 3) {
    73             String sig = ((String) data[i]).substring(name.length() + 2);
    74             Class<?> cls = (Class<?>) data[i + 2];
    75             Method tmp = INSTANCE.create(cls, name, data[i + 1], sig);
    76             Class<?>[] tmpParms = tmp.getParameterTypes();
    77             if (parameterTypes.length != tmpParms.length) {
    78                 continue;
    79             }
    80             for (int j = 0; j < tmpParms.length; j++) {
    81                 if (!parameterTypes[j].equals(tmpParms[j])) {
    82                     continue BIG;
    83                 }
    84             }
    85             return tmp;
    86         }
    87         return null;
    88     }
    89 
    90     public static Method[] findMethods(Class<?> clazz, int mask) {
    91         Object[] namesAndData = findMethodData(clazz, "");
    92         int cnt = 0;
    93         for (int i = 0; i < namesAndData.length; i += 3) {
    94             String sig = (String) namesAndData[i];
    95             Object data = namesAndData[i + 1];
    96             int middle = sig.indexOf("__");
    97             if (middle == -1) {
    98                 continue;
    99             }
   100             String name = sig.substring(0, middle);
   101             sig = sig.substring(middle + 2);
   102             Class<?> cls = (Class<?>) namesAndData[i + 2];
   103             final Method m = INSTANCE.create(cls, name, data, sig);
   104             if ((m.getModifiers() & mask) == 0) {
   105                 continue;
   106             }
   107             namesAndData[cnt++] = m;
   108         }
   109         Method[] arr = new Method[cnt];
   110         for (int i = 0; i < cnt; i++) {
   111             arr[i] = (Method) namesAndData[i];
   112         }
   113         return arr;
   114     }
   115     static String toSignature(Method m) {
   116         StringBuilder sb = new StringBuilder();
   117         sb.append(m.getName()).append("__");
   118         appendType(sb, m.getReturnType());
   119         Class<?>[] arr = m.getParameterTypes();
   120         for (int i = 0; i < arr.length; i++) {
   121             appendType(sb, arr[i]);
   122         }
   123         return sb.toString();
   124     }
   125     
   126     private static void appendType(StringBuilder sb, Class<?> type) {
   127         if (type == Integer.TYPE) {
   128             sb.append('I');
   129             return;
   130         }
   131         if (type == Long.TYPE) {
   132             sb.append('J');
   133             return;
   134         }
   135         if (type == Double.TYPE) {
   136             sb.append('D');
   137             return;
   138         }
   139         if (type == Float.TYPE) {
   140             sb.append('F');
   141             return;
   142         }
   143         if (type == Byte.TYPE) {
   144             sb.append('B');
   145             return;
   146         }
   147         if (type == Boolean.TYPE) {
   148             sb.append('Z');
   149             return;
   150         }
   151         if (type == Short.TYPE) {
   152             sb.append('S');
   153             return;
   154         }
   155         if (type == Void.TYPE) {
   156             sb.append('V');
   157             return;
   158         }
   159         if (type == Character.TYPE) {
   160             sb.append('C');
   161             return;
   162         }
   163         if (type.isArray()) {
   164             sb.append("_3");
   165             appendType(sb, type.getComponentType());
   166             return;
   167         }
   168         sb.append('L').append(type.getName().replace('.', '_'));
   169         sb.append("_2");
   170     }
   171 
   172     public static int signatureElements(String sig) {
   173         Enumeration<Class> en = signatureParser(sig);
   174         int cnt = 0;
   175         while (en.hasMoreElements()) {
   176             en.nextElement();
   177             cnt++;
   178         }
   179         return cnt;
   180     }
   181     
   182     public static Enumeration<Class> signatureParser(final String sig) {
   183         class E implements Enumeration<Class> {
   184             int pos;
   185             
   186             public boolean hasMoreElements() {
   187                 return pos < sig.length();
   188             }
   189 
   190             public Class nextElement() {
   191                 switch (sig.charAt(pos++)) {
   192                     case 'I':
   193                         return Integer.TYPE;
   194                     case 'J':
   195                         return Long.TYPE;
   196                     case 'D':
   197                         return Double.TYPE;
   198                     case 'F':
   199                         return Float.TYPE;
   200                     case 'B':
   201                         return Byte.TYPE;
   202                     case 'Z':
   203                         return Boolean.TYPE;
   204                     case 'S':
   205                         return Short.TYPE;
   206                     case 'V':
   207                         return Void.TYPE;
   208                     case 'C':
   209                         return Character.TYPE;
   210                     case 'L':
   211                         try {
   212                             int up = sig.indexOf("_2", pos);
   213                             String type = sig.substring(pos, up);
   214                             pos = up + 2;
   215                             return Class.forName(type.replace('_', '.'));
   216                         } catch (ClassNotFoundException ex) {
   217                             throw new IllegalStateException(ex);
   218                         }
   219                     case '_': {
   220                         char nch = sig.charAt(pos++);
   221                         assert nch == '3' : "Can't find '3' at " + sig.substring(pos - 1);
   222                         final Class compType = nextElement();
   223                         return Array.newInstance(compType, 0).getClass();
   224                     }
   225                 }
   226                 throw new UnsupportedOperationException(sig + " at " + pos);
   227             }
   228         }
   229         return new E();
   230     }
   231 }