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