emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sun, 03 Feb 2013 11:01:08 +0100
branchreflection
changeset 650 2569d9dd4b28
parent 555 cde0c2d7794e
child 654 26a86cc00224
permissions -rw-r--r--
Test for proper behavior of MethodImpl own 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         + "     arr.push(m);\n"
    60         + "     arr.push(c[m]);\n"
    61         + "  }"
    62         + "}\n"
    63         + "return arr;")
    64     private static native Object[] findMethodData(
    65         Class<?> clazz, String prefix);
    66 
    67     public static Method findMethod(
    68         Class<?> clazz, String name, Class<?>... parameterTypes) {
    69         Object[] data = findMethodData(clazz, name + "__");
    70         BIG: for (int i = 0; i < data.length; i += 2) {
    71             String sig = ((String) data[0]).substring(name.length() + 2);
    72             Method tmp = INSTANCE.create(clazz, name, data[1], sig);
    73             Class<?>[] tmpParms = tmp.getParameterTypes();
    74             if (parameterTypes.length != tmpParms.length) {
    75                 continue;
    76             }
    77             for (int j = 0; j < tmpParms.length; j++) {
    78                 if (!parameterTypes[j].equals(tmpParms[j])) {
    79                     continue BIG;
    80                 }
    81             }
    82             return tmp;
    83         }
    84         return null;
    85     }
    86 
    87     public static Method[] findMethods(Class<?> clazz, int mask) {
    88         Object[] namesAndData = findMethodData(clazz, "");
    89         int cnt = 0;
    90         for (int i = 0; i < namesAndData.length; i += 2) {
    91             String sig = (String) namesAndData[i];
    92             Object data = namesAndData[i + 1];
    93             int middle = sig.indexOf("__");
    94             if (middle == -1) {
    95                 continue;
    96             }
    97             String name = sig.substring(0, middle);
    98             sig = sig.substring(middle + 2);
    99             final Method m = INSTANCE.create(clazz, name, data, sig);
   100             if ((m.getModifiers() & mask) == 0) {
   101                 continue;
   102             }
   103             namesAndData[cnt++] = m;
   104         }
   105         Method[] arr = new Method[cnt];
   106         for (int i = 0; i < cnt; i++) {
   107             arr[i] = (Method) namesAndData[i];
   108         }
   109         return arr;
   110     }
   111     static String toSignature(Method m) {
   112         StringBuilder sb = new StringBuilder();
   113         sb.append(m.getName()).append("__");
   114         appendType(sb, m.getReturnType());
   115         Class<?>[] arr = m.getParameterTypes();
   116         for (int i = 0; i < arr.length; i++) {
   117             appendType(sb, arr[i]);
   118         }
   119         return sb.toString();
   120     }
   121     
   122     private static void appendType(StringBuilder sb, Class<?> type) {
   123         if (type == Integer.TYPE) {
   124             sb.append('I');
   125             return;
   126         }
   127         if (type == Long.TYPE) {
   128             sb.append('J');
   129             return;
   130         }
   131         if (type == Double.TYPE) {
   132             sb.append('D');
   133             return;
   134         }
   135         if (type == Float.TYPE) {
   136             sb.append('F');
   137             return;
   138         }
   139         if (type == Byte.TYPE) {
   140             sb.append('B');
   141             return;
   142         }
   143         if (type == Boolean.TYPE) {
   144             sb.append('Z');
   145             return;
   146         }
   147         if (type == Short.TYPE) {
   148             sb.append('S');
   149             return;
   150         }
   151         if (type == Void.TYPE) {
   152             sb.append('V');
   153             return;
   154         }
   155         if (type == Character.TYPE) {
   156             sb.append('C');
   157             return;
   158         }
   159         if (type.isArray()) {
   160             sb.append("_3");
   161             appendType(sb, type.getComponentType());
   162             return;
   163         }
   164         sb.append('L').append(type.getName().replace('.', '_'));
   165         sb.append("_2");
   166     }
   167 
   168     public static int signatureElements(String sig) {
   169         Enumeration<Class> en = signatureParser(sig);
   170         int cnt = 0;
   171         while (en.hasMoreElements()) {
   172             en.nextElement();
   173             cnt++;
   174         }
   175         return cnt;
   176     }
   177     
   178     public static Enumeration<Class> signatureParser(final String sig) {
   179         class E implements Enumeration<Class> {
   180             int pos;
   181             
   182             public boolean hasMoreElements() {
   183                 return pos < sig.length();
   184             }
   185 
   186             public Class nextElement() {
   187                 switch (sig.charAt(pos++)) {
   188                     case 'I':
   189                         return Integer.TYPE;
   190                     case 'J':
   191                         return Long.TYPE;
   192                     case 'D':
   193                         return Double.TYPE;
   194                     case 'F':
   195                         return Float.TYPE;
   196                     case 'B':
   197                         return Byte.TYPE;
   198                     case 'Z':
   199                         return Boolean.TYPE;
   200                     case 'S':
   201                         return Short.TYPE;
   202                     case 'V':
   203                         return Void.TYPE;
   204                     case 'C':
   205                         return Character.TYPE;
   206                     case 'L':
   207                         try {
   208                             int up = sig.indexOf("_2", pos);
   209                             String type = sig.substring(pos, up);
   210                             pos = up + 2;
   211                             return Class.forName(type.replace('_', '.'));
   212                         } catch (ClassNotFoundException ex) {
   213                             throw new IllegalStateException(ex);
   214                         }
   215                     case '_': {
   216                         char nch = sig.charAt(pos++);
   217                         assert nch == '3' : "Can't find '3' at " + sig.substring(pos - 1);
   218                         final Class compType = nextElement();
   219                         return Array.newInstance(compType, 0).getClass();
   220                     }
   221                 }
   222                 throw new UnsupportedOperationException(sig + " at " + pos);
   223             }
   224         }
   225         return new E();
   226     }
   227 }