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