emul/mini/src/main/java/java/lang/reflect/Method.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 26 Jan 2013 08:47:05 +0100
changeset 592 5e13b1ac2886
parent 555 cde0c2d7794e
permissions -rw-r--r--
In order to support fields of the same name in subclasses we are now prefixing them with name of the class that defines them. To provide convenient way to access them from generated bytecode and also directly from JavaScript, there is a getter/setter function for each field. It starts with _ followed by the field name. If called with a parameter, it sets the field, with a parameter it just returns it.
jtulach@258
     1
/*
jtulach@258
     2
 * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
jtulach@258
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jtulach@258
     4
 *
jtulach@258
     5
 * This code is free software; you can redistribute it and/or modify it
jtulach@258
     6
 * under the terms of the GNU General Public License version 2 only, as
jtulach@258
     7
 * published by the Free Software Foundation.  Oracle designates this
jtulach@258
     8
 * particular file as subject to the "Classpath" exception as provided
jtulach@258
     9
 * by Oracle in the LICENSE file that accompanied this code.
jtulach@258
    10
 *
jtulach@258
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jtulach@258
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jtulach@258
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jtulach@258
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jtulach@258
    15
 * accompanied this code).
jtulach@258
    16
 *
jtulach@258
    17
 * You should have received a copy of the GNU General Public License version
jtulach@258
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jtulach@258
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jtulach@258
    20
 *
jtulach@258
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jtulach@258
    22
 * or visit www.oracle.com if you need additional information or have any
jtulach@258
    23
 * questions.
jtulach@258
    24
 */
jtulach@258
    25
jtulach@258
    26
package java.lang.reflect;
jtulach@258
    27
jtulach@258
    28
import java.lang.annotation.Annotation;
jaroslav@418
    29
import java.util.Enumeration;
jaroslav@262
    30
import org.apidesign.bck2brwsr.core.JavaScriptBody;
jaroslav@555
    31
import org.apidesign.bck2brwsr.emul.reflect.AnnotationImpl;
jaroslav@555
    32
import org.apidesign.bck2brwsr.emul.reflect.MethodImpl;
jtulach@258
    33
jtulach@258
    34
/**
jtulach@258
    35
 * A {@code Method} provides information about, and access to, a single method
jtulach@258
    36
 * on a class or interface.  The reflected method may be a class method
jtulach@258
    37
 * or an instance method (including an abstract method).
jtulach@258
    38
 *
jtulach@258
    39
 * <p>A {@code Method} permits widening conversions to occur when matching the
jtulach@258
    40
 * actual parameters to invoke with the underlying method's formal
jtulach@258
    41
 * parameters, but it throws an {@code IllegalArgumentException} if a
jtulach@258
    42
 * narrowing conversion would occur.
jtulach@258
    43
 *
jtulach@258
    44
 * @see Member
jtulach@258
    45
 * @see java.lang.Class
jtulach@258
    46
 * @see java.lang.Class#getMethods()
jtulach@258
    47
 * @see java.lang.Class#getMethod(String, Class[])
jtulach@258
    48
 * @see java.lang.Class#getDeclaredMethods()
jtulach@258
    49
 * @see java.lang.Class#getDeclaredMethod(String, Class[])
jtulach@258
    50
 *
jtulach@258
    51
 * @author Kenneth Russell
jtulach@258
    52
 * @author Nakul Saraiya
jtulach@258
    53
 */
jtulach@258
    54
public final
jtulach@258
    55
    class Method extends AccessibleObject implements GenericDeclaration,
jtulach@258
    56
                                                     Member {
jaroslav@262
    57
    private final Class<?> clazz;
jaroslav@262
    58
    private final String name;
jaroslav@262
    59
    private final Object data;
jaroslav@264
    60
    private final String sig;
jtulach@258
    61
jtulach@258
    62
   // Generics infrastructure
jtulach@258
    63
jaroslav@262
    64
    private String getGenericSignature() {return null;}
jtulach@258
    65
jtulach@258
    66
    /**
jtulach@258
    67
     * Package-private constructor used by ReflectAccess to enable
jtulach@258
    68
     * instantiation of these objects in Java code from the java.lang
jtulach@258
    69
     * package via sun.reflect.LangReflectAccess.
jtulach@258
    70
     */
jaroslav@264
    71
    Method(Class<?> declaringClass, String name, Object data, String sig)
jtulach@258
    72
    {
jtulach@258
    73
        this.clazz = declaringClass;
jtulach@258
    74
        this.name = name;
jaroslav@262
    75
        this.data = data;
jaroslav@264
    76
        this.sig = sig;
jtulach@258
    77
    }
jtulach@258
    78
jtulach@258
    79
    /**
jtulach@258
    80
     * Package-private routine (exposed to java.lang.Class via
jtulach@258
    81
     * ReflectAccess) which returns a copy of this Method. The copy's
jtulach@258
    82
     * "root" field points to this Method.
jtulach@258
    83
     */
jtulach@258
    84
    Method copy() {
jaroslav@262
    85
        return this;
jtulach@258
    86
    }
jtulach@258
    87
jtulach@258
    88
    /**
jtulach@258
    89
     * Returns the {@code Class} object representing the class or interface
jtulach@258
    90
     * that declares the method represented by this {@code Method} object.
jtulach@258
    91
     */
jtulach@258
    92
    public Class<?> getDeclaringClass() {
jtulach@258
    93
        return clazz;
jtulach@258
    94
    }
jtulach@258
    95
jtulach@258
    96
    /**
jtulach@258
    97
     * Returns the name of the method represented by this {@code Method}
jtulach@258
    98
     * object, as a {@code String}.
jtulach@258
    99
     */
jtulach@258
   100
    public String getName() {
jtulach@258
   101
        return name;
jtulach@258
   102
    }
jtulach@258
   103
jtulach@258
   104
    /**
jtulach@258
   105
     * Returns the Java language modifiers for the method represented
jtulach@258
   106
     * by this {@code Method} object, as an integer. The {@code Modifier} class should
jtulach@258
   107
     * be used to decode the modifiers.
jtulach@258
   108
     *
jtulach@258
   109
     * @see Modifier
jtulach@258
   110
     */
jtulach@258
   111
    public int getModifiers() {
jaroslav@392
   112
        return getAccess(data);
jtulach@258
   113
    }
jaroslav@392
   114
    
jaroslav@392
   115
    @JavaScriptBody(args = "self", body = "return self.access;")
jaroslav@392
   116
    private static native int getAccess(Object self);
jaroslav@392
   117
    
jtulach@258
   118
    /**
jtulach@258
   119
     * Returns an array of {@code TypeVariable} objects that represent the
jtulach@258
   120
     * type variables declared by the generic declaration represented by this
jtulach@258
   121
     * {@code GenericDeclaration} object, in declaration order.  Returns an
jtulach@258
   122
     * array of length 0 if the underlying generic declaration declares no type
jtulach@258
   123
     * variables.
jtulach@258
   124
     *
jtulach@258
   125
     * @return an array of {@code TypeVariable} objects that represent
jtulach@258
   126
     *     the type variables declared by this generic declaration
jtulach@258
   127
     * @throws GenericSignatureFormatError if the generic
jtulach@258
   128
     *     signature of this generic declaration does not conform to
jtulach@258
   129
     *     the format specified in
jtulach@258
   130
     *     <cite>The Java&trade; Virtual Machine Specification</cite>
jtulach@258
   131
     * @since 1.5
jtulach@258
   132
     */
jtulach@258
   133
    public TypeVariable<Method>[] getTypeParameters() {
jaroslav@260
   134
        throw new UnsupportedOperationException();
jtulach@258
   135
    }
jtulach@258
   136
jtulach@258
   137
    /**
jtulach@258
   138
     * Returns a {@code Class} object that represents the formal return type
jtulach@258
   139
     * of the method represented by this {@code Method} object.
jtulach@258
   140
     *
jtulach@258
   141
     * @return the return type for the method this object represents
jtulach@258
   142
     */
jtulach@258
   143
    public Class<?> getReturnType() {
jaroslav@418
   144
        return MethodImpl.signatureParser(sig).nextElement();
jtulach@258
   145
    }
jtulach@258
   146
jtulach@258
   147
    /**
jtulach@258
   148
     * Returns a {@code Type} object that represents the formal return
jtulach@258
   149
     * type of the method represented by this {@code Method} object.
jtulach@258
   150
     *
jtulach@258
   151
     * <p>If the return type is a parameterized type,
jtulach@258
   152
     * the {@code Type} object returned must accurately reflect
jtulach@258
   153
     * the actual type parameters used in the source code.
jtulach@258
   154
     *
jtulach@258
   155
     * <p>If the return type is a type variable or a parameterized type, it
jtulach@258
   156
     * is created. Otherwise, it is resolved.
jtulach@258
   157
     *
jtulach@258
   158
     * @return  a {@code Type} object that represents the formal return
jtulach@258
   159
     *     type of the underlying  method
jtulach@258
   160
     * @throws GenericSignatureFormatError
jtulach@258
   161
     *     if the generic method signature does not conform to the format
jtulach@258
   162
     *     specified in
jtulach@258
   163
     *     <cite>The Java&trade; Virtual Machine Specification</cite>
jtulach@258
   164
     * @throws TypeNotPresentException if the underlying method's
jtulach@258
   165
     *     return type refers to a non-existent type declaration
jtulach@258
   166
     * @throws MalformedParameterizedTypeException if the
jtulach@258
   167
     *     underlying method's return typed refers to a parameterized
jtulach@258
   168
     *     type that cannot be instantiated for any reason
jtulach@258
   169
     * @since 1.5
jtulach@258
   170
     */
jtulach@258
   171
    public Type getGenericReturnType() {
jaroslav@260
   172
        throw new UnsupportedOperationException();
jtulach@258
   173
    }
jtulach@258
   174
jtulach@258
   175
jtulach@258
   176
    /**
jtulach@258
   177
     * Returns an array of {@code Class} objects that represent the formal
jtulach@258
   178
     * parameter types, in declaration order, of the method
jtulach@258
   179
     * represented by this {@code Method} object.  Returns an array of length
jtulach@258
   180
     * 0 if the underlying method takes no parameters.
jtulach@258
   181
     *
jtulach@258
   182
     * @return the parameter types for the method this object
jtulach@258
   183
     * represents
jtulach@258
   184
     */
jtulach@258
   185
    public Class<?>[] getParameterTypes() {
jaroslav@418
   186
        Class[] arr = new Class[MethodImpl.signatureElements(sig) - 1];
jaroslav@418
   187
        Enumeration<Class> en = MethodImpl.signatureParser(sig);
jaroslav@418
   188
        en.nextElement(); // return type
jaroslav@418
   189
        for (int i = 0; i < arr.length; i++) {
jaroslav@418
   190
            arr[i] = en.nextElement();
jaroslav@418
   191
        }
jaroslav@418
   192
        return arr;
jtulach@258
   193
    }
jtulach@258
   194
jtulach@258
   195
    /**
jtulach@258
   196
     * Returns an array of {@code Type} objects that represent the formal
jtulach@258
   197
     * parameter types, in declaration order, of the method represented by
jtulach@258
   198
     * this {@code Method} object. Returns an array of length 0 if the
jtulach@258
   199
     * underlying method takes no parameters.
jtulach@258
   200
     *
jtulach@258
   201
     * <p>If a formal parameter type is a parameterized type,
jtulach@258
   202
     * the {@code Type} object returned for it must accurately reflect
jtulach@258
   203
     * the actual type parameters used in the source code.
jtulach@258
   204
     *
jtulach@258
   205
     * <p>If a formal parameter type is a type variable or a parameterized
jtulach@258
   206
     * type, it is created. Otherwise, it is resolved.
jtulach@258
   207
     *
jtulach@258
   208
     * @return an array of Types that represent the formal
jtulach@258
   209
     *     parameter types of the underlying method, in declaration order
jtulach@258
   210
     * @throws GenericSignatureFormatError
jtulach@258
   211
     *     if the generic method signature does not conform to the format
jtulach@258
   212
     *     specified in
jtulach@258
   213
     *     <cite>The Java&trade; Virtual Machine Specification</cite>
jtulach@258
   214
     * @throws TypeNotPresentException if any of the parameter
jtulach@258
   215
     *     types of the underlying method refers to a non-existent type
jtulach@258
   216
     *     declaration
jtulach@258
   217
     * @throws MalformedParameterizedTypeException if any of
jtulach@258
   218
     *     the underlying method's parameter types refer to a parameterized
jtulach@258
   219
     *     type that cannot be instantiated for any reason
jtulach@258
   220
     * @since 1.5
jtulach@258
   221
     */
jtulach@258
   222
    public Type[] getGenericParameterTypes() {
jaroslav@260
   223
        throw new UnsupportedOperationException();
jtulach@258
   224
    }
jtulach@258
   225
jtulach@258
   226
jtulach@258
   227
    /**
jtulach@258
   228
     * Returns an array of {@code Class} objects that represent
jtulach@258
   229
     * the types of the exceptions declared to be thrown
jtulach@258
   230
     * by the underlying method
jtulach@258
   231
     * represented by this {@code Method} object.  Returns an array of length
jtulach@258
   232
     * 0 if the method declares no exceptions in its {@code throws} clause.
jtulach@258
   233
     *
jtulach@258
   234
     * @return the exception types declared as being thrown by the
jtulach@258
   235
     * method this object represents
jtulach@258
   236
     */
jtulach@258
   237
    public Class<?>[] getExceptionTypes() {
jaroslav@262
   238
        throw new UnsupportedOperationException();
jaroslav@262
   239
        //return (Class<?>[]) exceptionTypes.clone();
jtulach@258
   240
    }
jtulach@258
   241
jtulach@258
   242
    /**
jtulach@258
   243
     * Returns an array of {@code Type} objects that represent the
jtulach@258
   244
     * exceptions declared to be thrown by this {@code Method} object.
jtulach@258
   245
     * Returns an array of length 0 if the underlying method declares
jtulach@258
   246
     * no exceptions in its {@code throws} clause.
jtulach@258
   247
     *
jtulach@258
   248
     * <p>If an exception type is a type variable or a parameterized
jtulach@258
   249
     * type, it is created. Otherwise, it is resolved.
jtulach@258
   250
     *
jtulach@258
   251
     * @return an array of Types that represent the exception types
jtulach@258
   252
     *     thrown by the underlying method
jtulach@258
   253
     * @throws GenericSignatureFormatError
jtulach@258
   254
     *     if the generic method signature does not conform to the format
jtulach@258
   255
     *     specified in
jtulach@258
   256
     *     <cite>The Java&trade; Virtual Machine Specification</cite>
jtulach@258
   257
     * @throws TypeNotPresentException if the underlying method's
jtulach@258
   258
     *     {@code throws} clause refers to a non-existent type declaration
jtulach@258
   259
     * @throws MalformedParameterizedTypeException if
jtulach@258
   260
     *     the underlying method's {@code throws} clause refers to a
jtulach@258
   261
     *     parameterized type that cannot be instantiated for any reason
jtulach@258
   262
     * @since 1.5
jtulach@258
   263
     */
jtulach@258
   264
      public Type[] getGenericExceptionTypes() {
jaroslav@260
   265
        throw new UnsupportedOperationException();
jtulach@258
   266
      }
jtulach@258
   267
jtulach@258
   268
    /**
jtulach@258
   269
     * Compares this {@code Method} against the specified object.  Returns
jtulach@258
   270
     * true if the objects are the same.  Two {@code Methods} are the same if
jtulach@258
   271
     * they were declared by the same class and have the same name
jtulach@258
   272
     * and formal parameter types and return type.
jtulach@258
   273
     */
jtulach@258
   274
    public boolean equals(Object obj) {
jtulach@258
   275
        if (obj != null && obj instanceof Method) {
jtulach@258
   276
            Method other = (Method)obj;
jaroslav@262
   277
            return data == other.data;
jtulach@258
   278
        }
jtulach@258
   279
        return false;
jtulach@258
   280
    }
jtulach@258
   281
jtulach@258
   282
    /**
jtulach@258
   283
     * Returns a hashcode for this {@code Method}.  The hashcode is computed
jtulach@258
   284
     * as the exclusive-or of the hashcodes for the underlying
jtulach@258
   285
     * method's declaring class name and the method's name.
jtulach@258
   286
     */
jtulach@258
   287
    public int hashCode() {
jtulach@258
   288
        return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
jtulach@258
   289
    }
jtulach@258
   290
jtulach@258
   291
    /**
jtulach@258
   292
     * Returns a string describing this {@code Method}.  The string is
jtulach@258
   293
     * formatted as the method access modifiers, if any, followed by
jtulach@258
   294
     * the method return type, followed by a space, followed by the
jtulach@258
   295
     * class declaring the method, followed by a period, followed by
jtulach@258
   296
     * the method name, followed by a parenthesized, comma-separated
jtulach@258
   297
     * list of the method's formal parameter types. If the method
jtulach@258
   298
     * throws checked exceptions, the parameter list is followed by a
jtulach@258
   299
     * space, followed by the word throws followed by a
jtulach@258
   300
     * comma-separated list of the thrown exception types.
jtulach@258
   301
     * For example:
jtulach@258
   302
     * <pre>
jtulach@258
   303
     *    public boolean java.lang.Object.equals(java.lang.Object)
jtulach@258
   304
     * </pre>
jtulach@258
   305
     *
jtulach@258
   306
     * <p>The access modifiers are placed in canonical order as
jtulach@258
   307
     * specified by "The Java Language Specification".  This is
jtulach@258
   308
     * {@code public}, {@code protected} or {@code private} first,
jtulach@258
   309
     * and then other modifiers in the following order:
jtulach@258
   310
     * {@code abstract}, {@code static}, {@code final},
jtulach@258
   311
     * {@code synchronized}, {@code native}, {@code strictfp}.
jtulach@258
   312
     */
jtulach@258
   313
    public String toString() {
jtulach@258
   314
        try {
jtulach@258
   315
            StringBuilder sb = new StringBuilder();
jtulach@258
   316
            int mod = getModifiers() & Modifier.methodModifiers();
jtulach@258
   317
            if (mod != 0) {
jtulach@258
   318
                sb.append(Modifier.toString(mod)).append(' ');
jtulach@258
   319
            }
jtulach@258
   320
            sb.append(Field.getTypeName(getReturnType())).append(' ');
jtulach@258
   321
            sb.append(Field.getTypeName(getDeclaringClass())).append('.');
jtulach@258
   322
            sb.append(getName()).append('(');
jaroslav@420
   323
            Class<?>[] params = getParameterTypes(); // avoid clone
jtulach@258
   324
            for (int j = 0; j < params.length; j++) {
jtulach@258
   325
                sb.append(Field.getTypeName(params[j]));
jtulach@258
   326
                if (j < (params.length - 1))
jtulach@258
   327
                    sb.append(',');
jtulach@258
   328
            }
jtulach@258
   329
            sb.append(')');
jaroslav@420
   330
            /*
jtulach@258
   331
            Class<?>[] exceptions = exceptionTypes; // avoid clone
jtulach@258
   332
            if (exceptions.length > 0) {
jtulach@258
   333
                sb.append(" throws ");
jtulach@258
   334
                for (int k = 0; k < exceptions.length; k++) {
jtulach@258
   335
                    sb.append(exceptions[k].getName());
jtulach@258
   336
                    if (k < (exceptions.length - 1))
jtulach@258
   337
                        sb.append(',');
jtulach@258
   338
                }
jtulach@258
   339
            }
jaroslav@262
   340
            */
jtulach@258
   341
            return sb.toString();
jtulach@258
   342
        } catch (Exception e) {
jtulach@258
   343
            return "<" + e + ">";
jtulach@258
   344
        }
jtulach@258
   345
    }
jtulach@258
   346
jtulach@258
   347
    /**
jtulach@258
   348
     * Returns a string describing this {@code Method}, including
jtulach@258
   349
     * type parameters.  The string is formatted as the method access
jtulach@258
   350
     * modifiers, if any, followed by an angle-bracketed
jtulach@258
   351
     * comma-separated list of the method's type parameters, if any,
jtulach@258
   352
     * followed by the method's generic return type, followed by a
jtulach@258
   353
     * space, followed by the class declaring the method, followed by
jtulach@258
   354
     * a period, followed by the method name, followed by a
jtulach@258
   355
     * parenthesized, comma-separated list of the method's generic
jtulach@258
   356
     * formal parameter types.
jtulach@258
   357
     *
jtulach@258
   358
     * If this method was declared to take a variable number of
jtulach@258
   359
     * arguments, instead of denoting the last parameter as
jtulach@258
   360
     * "<tt><i>Type</i>[]</tt>", it is denoted as
jtulach@258
   361
     * "<tt><i>Type</i>...</tt>".
jtulach@258
   362
     *
jtulach@258
   363
     * A space is used to separate access modifiers from one another
jtulach@258
   364
     * and from the type parameters or return type.  If there are no
jtulach@258
   365
     * type parameters, the type parameter list is elided; if the type
jtulach@258
   366
     * parameter list is present, a space separates the list from the
jtulach@258
   367
     * class name.  If the method is declared to throw exceptions, the
jtulach@258
   368
     * parameter list is followed by a space, followed by the word
jtulach@258
   369
     * throws followed by a comma-separated list of the generic thrown
jtulach@258
   370
     * exception types.  If there are no type parameters, the type
jtulach@258
   371
     * parameter list is elided.
jtulach@258
   372
     *
jtulach@258
   373
     * <p>The access modifiers are placed in canonical order as
jtulach@258
   374
     * specified by "The Java Language Specification".  This is
jtulach@258
   375
     * {@code public}, {@code protected} or {@code private} first,
jtulach@258
   376
     * and then other modifiers in the following order:
jtulach@258
   377
     * {@code abstract}, {@code static}, {@code final},
jtulach@258
   378
     * {@code synchronized}, {@code native}, {@code strictfp}.
jtulach@258
   379
     *
jtulach@258
   380
     * @return a string describing this {@code Method},
jtulach@258
   381
     * include type parameters
jtulach@258
   382
     *
jtulach@258
   383
     * @since 1.5
jtulach@258
   384
     */
jtulach@258
   385
    public String toGenericString() {
jtulach@258
   386
        try {
jtulach@258
   387
            StringBuilder sb = new StringBuilder();
jtulach@258
   388
            int mod = getModifiers() & Modifier.methodModifiers();
jtulach@258
   389
            if (mod != 0) {
jtulach@258
   390
                sb.append(Modifier.toString(mod)).append(' ');
jtulach@258
   391
            }
jtulach@258
   392
            TypeVariable<?>[] typeparms = getTypeParameters();
jtulach@258
   393
            if (typeparms.length > 0) {
jtulach@258
   394
                boolean first = true;
jtulach@258
   395
                sb.append('<');
jtulach@258
   396
                for(TypeVariable<?> typeparm: typeparms) {
jtulach@258
   397
                    if (!first)
jtulach@258
   398
                        sb.append(',');
jtulach@258
   399
                    // Class objects can't occur here; no need to test
jtulach@258
   400
                    // and call Class.getName().
jtulach@258
   401
                    sb.append(typeparm.toString());
jtulach@258
   402
                    first = false;
jtulach@258
   403
                }
jtulach@258
   404
                sb.append("> ");
jtulach@258
   405
            }
jtulach@258
   406
jtulach@258
   407
            Type genRetType = getGenericReturnType();
jtulach@258
   408
            sb.append( ((genRetType instanceof Class<?>)?
jtulach@258
   409
                        Field.getTypeName((Class<?>)genRetType):genRetType.toString()))
jtulach@258
   410
                    .append(' ');
jtulach@258
   411
jtulach@258
   412
            sb.append(Field.getTypeName(getDeclaringClass())).append('.');
jtulach@258
   413
            sb.append(getName()).append('(');
jtulach@258
   414
            Type[] params = getGenericParameterTypes();
jtulach@258
   415
            for (int j = 0; j < params.length; j++) {
jtulach@258
   416
                String param = (params[j] instanceof Class)?
jtulach@258
   417
                    Field.getTypeName((Class)params[j]):
jtulach@258
   418
                    (params[j].toString());
jtulach@258
   419
                if (isVarArgs() && (j == params.length - 1)) // replace T[] with T...
jtulach@258
   420
                    param = param.replaceFirst("\\[\\]$", "...");
jtulach@258
   421
                sb.append(param);
jtulach@258
   422
                if (j < (params.length - 1))
jtulach@258
   423
                    sb.append(',');
jtulach@258
   424
            }
jtulach@258
   425
            sb.append(')');
jtulach@258
   426
            Type[] exceptions = getGenericExceptionTypes();
jtulach@258
   427
            if (exceptions.length > 0) {
jtulach@258
   428
                sb.append(" throws ");
jtulach@258
   429
                for (int k = 0; k < exceptions.length; k++) {
jtulach@258
   430
                    sb.append((exceptions[k] instanceof Class)?
jtulach@258
   431
                              ((Class)exceptions[k]).getName():
jtulach@258
   432
                              exceptions[k].toString());
jtulach@258
   433
                    if (k < (exceptions.length - 1))
jtulach@258
   434
                        sb.append(',');
jtulach@258
   435
                }
jtulach@258
   436
            }
jtulach@258
   437
            return sb.toString();
jtulach@258
   438
        } catch (Exception e) {
jtulach@258
   439
            return "<" + e + ">";
jtulach@258
   440
        }
jtulach@258
   441
    }
jtulach@258
   442
jtulach@258
   443
    /**
jtulach@258
   444
     * Invokes the underlying method represented by this {@code Method}
jtulach@258
   445
     * object, on the specified object with the specified parameters.
jtulach@258
   446
     * Individual parameters are automatically unwrapped to match
jtulach@258
   447
     * primitive formal parameters, and both primitive and reference
jtulach@258
   448
     * parameters are subject to method invocation conversions as
jtulach@258
   449
     * necessary.
jtulach@258
   450
     *
jtulach@258
   451
     * <p>If the underlying method is static, then the specified {@code obj}
jtulach@258
   452
     * argument is ignored. It may be null.
jtulach@258
   453
     *
jtulach@258
   454
     * <p>If the number of formal parameters required by the underlying method is
jtulach@258
   455
     * 0, the supplied {@code args} array may be of length 0 or null.
jtulach@258
   456
     *
jtulach@258
   457
     * <p>If the underlying method is an instance method, it is invoked
jtulach@258
   458
     * using dynamic method lookup as documented in The Java Language
jtulach@258
   459
     * Specification, Second Edition, section 15.12.4.4; in particular,
jtulach@258
   460
     * overriding based on the runtime type of the target object will occur.
jtulach@258
   461
     *
jtulach@258
   462
     * <p>If the underlying method is static, the class that declared
jtulach@258
   463
     * the method is initialized if it has not already been initialized.
jtulach@258
   464
     *
jtulach@258
   465
     * <p>If the method completes normally, the value it returns is
jtulach@258
   466
     * returned to the caller of invoke; if the value has a primitive
jtulach@258
   467
     * type, it is first appropriately wrapped in an object. However,
jtulach@258
   468
     * if the value has the type of an array of a primitive type, the
jtulach@258
   469
     * elements of the array are <i>not</i> wrapped in objects; in
jtulach@258
   470
     * other words, an array of primitive type is returned.  If the
jtulach@258
   471
     * underlying method return type is void, the invocation returns
jtulach@258
   472
     * null.
jtulach@258
   473
     *
jtulach@258
   474
     * @param obj  the object the underlying method is invoked from
jtulach@258
   475
     * @param args the arguments used for the method call
jtulach@258
   476
     * @return the result of dispatching the method represented by
jtulach@258
   477
     * this object on {@code obj} with parameters
jtulach@258
   478
     * {@code args}
jtulach@258
   479
     *
jtulach@258
   480
     * @exception IllegalAccessException    if this {@code Method} object
jtulach@258
   481
     *              is enforcing Java language access control and the underlying
jtulach@258
   482
     *              method is inaccessible.
jtulach@258
   483
     * @exception IllegalArgumentException  if the method is an
jtulach@258
   484
     *              instance method and the specified object argument
jtulach@258
   485
     *              is not an instance of the class or interface
jtulach@258
   486
     *              declaring the underlying method (or of a subclass
jtulach@258
   487
     *              or implementor thereof); if the number of actual
jtulach@258
   488
     *              and formal parameters differ; if an unwrapping
jtulach@258
   489
     *              conversion for primitive arguments fails; or if,
jtulach@258
   490
     *              after possible unwrapping, a parameter value
jtulach@258
   491
     *              cannot be converted to the corresponding formal
jtulach@258
   492
     *              parameter type by a method invocation conversion.
jtulach@258
   493
     * @exception InvocationTargetException if the underlying method
jtulach@258
   494
     *              throws an exception.
jtulach@258
   495
     * @exception NullPointerException      if the specified object is null
jtulach@258
   496
     *              and the method is an instance method.
jtulach@258
   497
     * @exception ExceptionInInitializerError if the initialization
jtulach@258
   498
     * provoked by this method fails.
jtulach@258
   499
     */
jaroslav@354
   500
    public Object invoke(Object obj, Object... args)
jaroslav@354
   501
        throws IllegalAccessException, IllegalArgumentException,
jaroslav@354
   502
           InvocationTargetException
jaroslav@354
   503
    {
jaroslav@418
   504
        final boolean isStatic = (getModifiers() & Modifier.STATIC) == 0;
jaroslav@418
   505
        if (isStatic && obj == null) {
jaroslav@413
   506
            throw new NullPointerException();
jaroslav@413
   507
        }
jaroslav@418
   508
        Class[] types = getParameterTypes();
jaroslav@418
   509
        if (types.length != args.length) {
jaroslav@418
   510
            throw new IllegalArgumentException("Types len " + types.length + " args: " + args.length);
jaroslav@418
   511
        } else {
jaroslav@418
   512
            args = args.clone();
jaroslav@418
   513
            for (int i = 0; i < types.length; i++) {
jaroslav@418
   514
                Class c = types[i];
jaroslav@418
   515
                if (c.isPrimitive()) {
jaroslav@418
   516
                    args[i] = toPrimitive(c, args[i]);
jaroslav@418
   517
                }
jaroslav@418
   518
            }
jaroslav@418
   519
        }
jaroslav@418
   520
        Object res = invoke0(isStatic, this, obj, args);
jaroslav@354
   521
        if (getReturnType().isPrimitive()) {
jaroslav@354
   522
            res = fromPrimitive(getReturnType(), res);
jaroslav@354
   523
        }
jaroslav@354
   524
        return res;
jaroslav@354
   525
    }
jaroslav@354
   526
    
jaroslav@418
   527
    @JavaScriptBody(args = { "st", "method", "self", "args" }, body =
jaroslav@418
   528
          "var p;\n"
jaroslav@418
   529
        + "if (st) {\n"
jaroslav@418
   530
        + "  p = new Array(1);\n"
jaroslav@418
   531
        + "  p[0] = self;\n"
jaroslav@418
   532
        + "  p = p.concat(args);\n"
jaroslav@418
   533
        + "} else {\n"
jaroslav@418
   534
        + "  p = args;\n"
jaroslav@418
   535
        + "}\n"
jaroslav@592
   536
        + "return method._data().apply(self, p);\n"
jaroslav@262
   537
    )
jaroslav@418
   538
    private static native Object invoke0(boolean isStatic, Method m, Object self, Object[] args);
jaroslav@354
   539
jaroslav@486
   540
    static Object fromPrimitive(Class<?> type, Object o) {
jaroslav@354
   541
        if (type == Integer.TYPE) {
jaroslav@355
   542
            return fromRaw(Integer.class, "valueOf__Ljava_lang_Integer_2I", o);
jaroslav@354
   543
        }
jaroslav@355
   544
        if (type == Long.TYPE) {
jaroslav@355
   545
            return fromRaw(Long.class, "valueOf__Ljava_lang_Long_2J", o);
jaroslav@355
   546
        }
jaroslav@355
   547
        if (type == Double.TYPE) {
jaroslav@355
   548
            return fromRaw(Double.class, "valueOf__Ljava_lang_Double_2D", o);
jaroslav@355
   549
        }
jaroslav@355
   550
        if (type == Float.TYPE) {
jaroslav@355
   551
            return fromRaw(Float.class, "valueOf__Ljava_lang_Float_2F", o);
jaroslav@355
   552
        }
jaroslav@355
   553
        if (type == Byte.TYPE) {
jaroslav@355
   554
            return fromRaw(Byte.class, "valueOf__Ljava_lang_Byte_2B", o);
jaroslav@355
   555
        }
jaroslav@355
   556
        if (type == Boolean.TYPE) {
jaroslav@355
   557
            return fromRaw(Boolean.class, "valueOf__Ljava_lang_Boolean_2Z", o);
jaroslav@355
   558
        }
jaroslav@355
   559
        if (type == Short.TYPE) {
jaroslav@355
   560
            return fromRaw(Short.class, "valueOf__Ljava_lang_Short_2S", o);
jaroslav@355
   561
        }
jaroslav@430
   562
        if (type == Character.TYPE) {
jaroslav@430
   563
            return fromRaw(Character.class, "valueOf__Ljava_lang_Character_2C", o);
jaroslav@430
   564
        }
jaroslav@413
   565
        if (type.getName().equals("void")) {
jaroslav@413
   566
            return null;
jaroslav@413
   567
        }
jaroslav@355
   568
        throw new IllegalStateException("Can't convert " + o);
jtulach@258
   569
    }
jaroslav@354
   570
    
jaroslav@355
   571
    @JavaScriptBody(args = { "cls", "m", "o" }, 
jaroslav@355
   572
        body = "return cls.cnstr(false)[m](o);"
jaroslav@355
   573
    )
jaroslav@355
   574
    private static native Integer fromRaw(Class<?> cls, String m, Object o);
jaroslav@418
   575
jaroslav@418
   576
    private static Object toPrimitive(Class<?> type, Object o) {
jaroslav@418
   577
        if (type == Integer.TYPE) {
jaroslav@418
   578
            return toRaw("intValue__I", o);
jaroslav@418
   579
        }
jaroslav@418
   580
        if (type == Long.TYPE) {
jaroslav@418
   581
            return toRaw("longValue__J", o);
jaroslav@418
   582
        }
jaroslav@418
   583
        if (type == Double.TYPE) {
jaroslav@418
   584
            return toRaw("doubleValue__D", o);
jaroslav@418
   585
        }
jaroslav@418
   586
        if (type == Float.TYPE) {
jaroslav@418
   587
            return toRaw("floatValue__F", o);
jaroslav@418
   588
        }
jaroslav@418
   589
        if (type == Byte.TYPE) {
jaroslav@418
   590
            return toRaw("byteValue__B", o);
jaroslav@418
   591
        }
jaroslav@418
   592
        if (type == Boolean.TYPE) {
jaroslav@418
   593
            return toRaw("booleanValue__Z", o);
jaroslav@418
   594
        }
jaroslav@418
   595
        if (type == Short.TYPE) {
jaroslav@418
   596
            return toRaw("shortValue__S", o);
jaroslav@418
   597
        }
jaroslav@430
   598
        if (type == Character.TYPE) {
jaroslav@430
   599
            return toRaw("charValue__C", o);
jaroslav@430
   600
        }
jaroslav@418
   601
        if (type.getName().equals("void")) {
jaroslav@418
   602
            return o;
jaroslav@418
   603
        }
jaroslav@418
   604
        throw new IllegalStateException("Can't convert " + o);
jaroslav@418
   605
    }
jaroslav@418
   606
    
jaroslav@418
   607
    @JavaScriptBody(args = { "m", "o" }, 
jaroslav@418
   608
        body = "return o[m](o);"
jaroslav@418
   609
    )
jaroslav@418
   610
    private static native Object toRaw(String m, Object o);
jaroslav@354
   611
    
jtulach@258
   612
    /**
jtulach@258
   613
     * Returns {@code true} if this method is a bridge
jtulach@258
   614
     * method; returns {@code false} otherwise.
jtulach@258
   615
     *
jtulach@258
   616
     * @return true if and only if this method is a bridge
jtulach@258
   617
     * method as defined by the Java Language Specification.
jtulach@258
   618
     * @since 1.5
jtulach@258
   619
     */
jtulach@258
   620
    public boolean isBridge() {
jtulach@258
   621
        return (getModifiers() & Modifier.BRIDGE) != 0;
jtulach@258
   622
    }
jtulach@258
   623
jtulach@258
   624
    /**
jtulach@258
   625
     * Returns {@code true} if this method was declared to take
jtulach@258
   626
     * a variable number of arguments; returns {@code false}
jtulach@258
   627
     * otherwise.
jtulach@258
   628
     *
jtulach@258
   629
     * @return {@code true} if an only if this method was declared to
jtulach@258
   630
     * take a variable number of arguments.
jtulach@258
   631
     * @since 1.5
jtulach@258
   632
     */
jtulach@258
   633
    public boolean isVarArgs() {
jtulach@258
   634
        return (getModifiers() & Modifier.VARARGS) != 0;
jtulach@258
   635
    }
jtulach@258
   636
jtulach@258
   637
    /**
jtulach@258
   638
     * Returns {@code true} if this method is a synthetic
jtulach@258
   639
     * method; returns {@code false} otherwise.
jtulach@258
   640
     *
jtulach@258
   641
     * @return true if and only if this method is a synthetic
jtulach@258
   642
     * method as defined by the Java Language Specification.
jtulach@258
   643
     * @since 1.5
jtulach@258
   644
     */
jtulach@258
   645
    public boolean isSynthetic() {
jtulach@258
   646
        return Modifier.isSynthetic(getModifiers());
jtulach@258
   647
    }
jtulach@258
   648
jaroslav@443
   649
    @JavaScriptBody(args = { "ac" }, 
jaroslav@266
   650
        body = 
jaroslav@592
   651
          "var a = this._data().anno;"
jaroslav@592
   652
        + "if (a) {"
jaroslav@592
   653
        + "  return a['L' + ac.jvmName + ';'];"
jaroslav@266
   654
        + "} else return null;"
jaroslav@266
   655
    )
jaroslav@266
   656
    private Object getAnnotationData(Class<?> annotationClass) {
jaroslav@266
   657
        throw new UnsupportedOperationException();
jaroslav@266
   658
    }
jaroslav@266
   659
    
jtulach@258
   660
    /**
jtulach@258
   661
     * @throws NullPointerException {@inheritDoc}
jtulach@258
   662
     * @since 1.5
jtulach@258
   663
     */
jtulach@258
   664
    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
jaroslav@266
   665
        Object data = getAnnotationData(annotationClass);
jaroslav@266
   666
        return data == null ? null : AnnotationImpl.create(annotationClass, data);
jtulach@258
   667
    }
jtulach@258
   668
jtulach@258
   669
    /**
jtulach@258
   670
     * @since 1.5
jtulach@258
   671
     */
jtulach@258
   672
    public Annotation[] getDeclaredAnnotations()  {
jaroslav@260
   673
        throw new UnsupportedOperationException();
jtulach@258
   674
    }
jtulach@258
   675
jtulach@258
   676
    /**
jtulach@258
   677
     * Returns the default value for the annotation member represented by
jtulach@258
   678
     * this {@code Method} instance.  If the member is of a primitive type,
jtulach@258
   679
     * an instance of the corresponding wrapper type is returned. Returns
jtulach@258
   680
     * null if no default is associated with the member, or if the method
jtulach@258
   681
     * instance does not represent a declared member of an annotation type.
jtulach@258
   682
     *
jtulach@258
   683
     * @return the default value for the annotation member represented
jtulach@258
   684
     *     by this {@code Method} instance.
jtulach@258
   685
     * @throws TypeNotPresentException if the annotation is of type
jtulach@258
   686
     *     {@link Class} and no definition can be found for the
jtulach@258
   687
     *     default class value.
jtulach@258
   688
     * @since  1.5
jtulach@258
   689
     */
jtulach@258
   690
    public Object getDefaultValue() {
jaroslav@260
   691
        throw new UnsupportedOperationException();
jtulach@258
   692
    }
jtulach@258
   693
jtulach@258
   694
    /**
jtulach@258
   695
     * Returns an array of arrays that represent the annotations on the formal
jtulach@258
   696
     * parameters, in declaration order, of the method represented by
jtulach@258
   697
     * this {@code Method} object. (Returns an array of length zero if the
jtulach@258
   698
     * underlying method is parameterless.  If the method has one or more
jtulach@258
   699
     * parameters, a nested array of length zero is returned for each parameter
jtulach@258
   700
     * with no annotations.) The annotation objects contained in the returned
jtulach@258
   701
     * arrays are serializable.  The caller of this method is free to modify
jtulach@258
   702
     * the returned arrays; it will have no effect on the arrays returned to
jtulach@258
   703
     * other callers.
jtulach@258
   704
     *
jtulach@258
   705
     * @return an array of arrays that represent the annotations on the formal
jtulach@258
   706
     *    parameters, in declaration order, of the method represented by this
jtulach@258
   707
     *    Method object
jtulach@258
   708
     * @since 1.5
jtulach@258
   709
     */
jtulach@258
   710
    public Annotation[][] getParameterAnnotations() {
jaroslav@260
   711
        throw new UnsupportedOperationException();
jtulach@258
   712
    }
jaroslav@262
   713
jaroslav@391
   714
    static {
jaroslav@391
   715
        MethodImpl.INSTANCE = new MethodImpl() {
jaroslav@391
   716
            protected Method create(Class<?> declaringClass, String name, Object data, String sig) {
jaroslav@391
   717
                return new Method(declaringClass, name, data, sig);
jaroslav@264
   718
            }
jaroslav@391
   719
        };
jaroslav@262
   720
    }
jtulach@258
   721
}