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.
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.
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.
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).
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.
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
26 package java.lang.reflect;
28 import java.lang.annotation.Annotation;
29 import java.util.Enumeration;
30 import org.apidesign.bck2brwsr.core.JavaScriptBody;
31 import org.apidesign.bck2brwsr.emul.reflect.AnnotationImpl;
32 import org.apidesign.bck2brwsr.emul.reflect.MethodImpl;
35 * A {@code Method} provides information about, and access to, a single method
36 * on a class or interface. The reflected method may be a class method
37 * or an instance method (including an abstract method).
39 * <p>A {@code Method} permits widening conversions to occur when matching the
40 * actual parameters to invoke with the underlying method's formal
41 * parameters, but it throws an {@code IllegalArgumentException} if a
42 * narrowing conversion would occur.
45 * @see java.lang.Class
46 * @see java.lang.Class#getMethods()
47 * @see java.lang.Class#getMethod(String, Class[])
48 * @see java.lang.Class#getDeclaredMethods()
49 * @see java.lang.Class#getDeclaredMethod(String, Class[])
51 * @author Kenneth Russell
52 * @author Nakul Saraiya
55 class Method extends AccessibleObject implements GenericDeclaration,
57 private final Class<?> clazz;
58 private final String name;
59 private final Object data;
60 private final String sig;
62 // Generics infrastructure
64 private String getGenericSignature() {return null;}
67 * Package-private constructor used by ReflectAccess to enable
68 * instantiation of these objects in Java code from the java.lang
69 * package via sun.reflect.LangReflectAccess.
71 Method(Class<?> declaringClass, String name, Object data, String sig)
73 this.clazz = declaringClass;
80 * Package-private routine (exposed to java.lang.Class via
81 * ReflectAccess) which returns a copy of this Method. The copy's
82 * "root" field points to this Method.
89 * Returns the {@code Class} object representing the class or interface
90 * that declares the method represented by this {@code Method} object.
92 public Class<?> getDeclaringClass() {
97 * Returns the name of the method represented by this {@code Method}
98 * object, as a {@code String}.
100 public String getName() {
105 * Returns the Java language modifiers for the method represented
106 * by this {@code Method} object, as an integer. The {@code Modifier} class should
107 * be used to decode the modifiers.
111 public int getModifiers() {
112 return getAccess(data);
115 @JavaScriptBody(args = "self", body = "return self.access;")
116 private static native int getAccess(Object self);
119 * Returns an array of {@code TypeVariable} objects that represent the
120 * type variables declared by the generic declaration represented by this
121 * {@code GenericDeclaration} object, in declaration order. Returns an
122 * array of length 0 if the underlying generic declaration declares no type
125 * @return an array of {@code TypeVariable} objects that represent
126 * the type variables declared by this generic declaration
127 * @throws GenericSignatureFormatError if the generic
128 * signature of this generic declaration does not conform to
129 * the format specified in
130 * <cite>The Java™ Virtual Machine Specification</cite>
133 public TypeVariable<Method>[] getTypeParameters() {
134 throw new UnsupportedOperationException();
138 * Returns a {@code Class} object that represents the formal return type
139 * of the method represented by this {@code Method} object.
141 * @return the return type for the method this object represents
143 public Class<?> getReturnType() {
144 return MethodImpl.signatureParser(sig).nextElement();
148 * Returns a {@code Type} object that represents the formal return
149 * type of the method represented by this {@code Method} object.
151 * <p>If the return type is a parameterized type,
152 * the {@code Type} object returned must accurately reflect
153 * the actual type parameters used in the source code.
155 * <p>If the return type is a type variable or a parameterized type, it
156 * is created. Otherwise, it is resolved.
158 * @return a {@code Type} object that represents the formal return
159 * type of the underlying method
160 * @throws GenericSignatureFormatError
161 * if the generic method signature does not conform to the format
163 * <cite>The Java™ Virtual Machine Specification</cite>
164 * @throws TypeNotPresentException if the underlying method's
165 * return type refers to a non-existent type declaration
166 * @throws MalformedParameterizedTypeException if the
167 * underlying method's return typed refers to a parameterized
168 * type that cannot be instantiated for any reason
171 public Type getGenericReturnType() {
172 throw new UnsupportedOperationException();
177 * Returns an array of {@code Class} objects that represent the formal
178 * parameter types, in declaration order, of the method
179 * represented by this {@code Method} object. Returns an array of length
180 * 0 if the underlying method takes no parameters.
182 * @return the parameter types for the method this object
185 public Class<?>[] getParameterTypes() {
186 Class[] arr = new Class[MethodImpl.signatureElements(sig) - 1];
187 Enumeration<Class> en = MethodImpl.signatureParser(sig);
188 en.nextElement(); // return type
189 for (int i = 0; i < arr.length; i++) {
190 arr[i] = en.nextElement();
196 * Returns an array of {@code Type} objects that represent the formal
197 * parameter types, in declaration order, of the method represented by
198 * this {@code Method} object. Returns an array of length 0 if the
199 * underlying method takes no parameters.
201 * <p>If a formal parameter type is a parameterized type,
202 * the {@code Type} object returned for it must accurately reflect
203 * the actual type parameters used in the source code.
205 * <p>If a formal parameter type is a type variable or a parameterized
206 * type, it is created. Otherwise, it is resolved.
208 * @return an array of Types that represent the formal
209 * parameter types of the underlying method, in declaration order
210 * @throws GenericSignatureFormatError
211 * if the generic method signature does not conform to the format
213 * <cite>The Java™ Virtual Machine Specification</cite>
214 * @throws TypeNotPresentException if any of the parameter
215 * types of the underlying method refers to a non-existent type
217 * @throws MalformedParameterizedTypeException if any of
218 * the underlying method's parameter types refer to a parameterized
219 * type that cannot be instantiated for any reason
222 public Type[] getGenericParameterTypes() {
223 throw new UnsupportedOperationException();
228 * Returns an array of {@code Class} objects that represent
229 * the types of the exceptions declared to be thrown
230 * by the underlying method
231 * represented by this {@code Method} object. Returns an array of length
232 * 0 if the method declares no exceptions in its {@code throws} clause.
234 * @return the exception types declared as being thrown by the
235 * method this object represents
237 public Class<?>[] getExceptionTypes() {
238 throw new UnsupportedOperationException();
239 //return (Class<?>[]) exceptionTypes.clone();
243 * Returns an array of {@code Type} objects that represent the
244 * exceptions declared to be thrown by this {@code Method} object.
245 * Returns an array of length 0 if the underlying method declares
246 * no exceptions in its {@code throws} clause.
248 * <p>If an exception type is a type variable or a parameterized
249 * type, it is created. Otherwise, it is resolved.
251 * @return an array of Types that represent the exception types
252 * thrown by the underlying method
253 * @throws GenericSignatureFormatError
254 * if the generic method signature does not conform to the format
256 * <cite>The Java™ Virtual Machine Specification</cite>
257 * @throws TypeNotPresentException if the underlying method's
258 * {@code throws} clause refers to a non-existent type declaration
259 * @throws MalformedParameterizedTypeException if
260 * the underlying method's {@code throws} clause refers to a
261 * parameterized type that cannot be instantiated for any reason
264 public Type[] getGenericExceptionTypes() {
265 throw new UnsupportedOperationException();
269 * Compares this {@code Method} against the specified object. Returns
270 * true if the objects are the same. Two {@code Methods} are the same if
271 * they were declared by the same class and have the same name
272 * and formal parameter types and return type.
274 public boolean equals(Object obj) {
275 if (obj != null && obj instanceof Method) {
276 Method other = (Method)obj;
277 return data == other.data;
283 * Returns a hashcode for this {@code Method}. The hashcode is computed
284 * as the exclusive-or of the hashcodes for the underlying
285 * method's declaring class name and the method's name.
287 public int hashCode() {
288 return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
292 * Returns a string describing this {@code Method}. The string is
293 * formatted as the method access modifiers, if any, followed by
294 * the method return type, followed by a space, followed by the
295 * class declaring the method, followed by a period, followed by
296 * the method name, followed by a parenthesized, comma-separated
297 * list of the method's formal parameter types. If the method
298 * throws checked exceptions, the parameter list is followed by a
299 * space, followed by the word throws followed by a
300 * comma-separated list of the thrown exception types.
303 * public boolean java.lang.Object.equals(java.lang.Object)
306 * <p>The access modifiers are placed in canonical order as
307 * specified by "The Java Language Specification". This is
308 * {@code public}, {@code protected} or {@code private} first,
309 * and then other modifiers in the following order:
310 * {@code abstract}, {@code static}, {@code final},
311 * {@code synchronized}, {@code native}, {@code strictfp}.
313 public String toString() {
315 StringBuilder sb = new StringBuilder();
316 int mod = getModifiers() & Modifier.methodModifiers();
318 sb.append(Modifier.toString(mod)).append(' ');
320 sb.append(Field.getTypeName(getReturnType())).append(' ');
321 sb.append(Field.getTypeName(getDeclaringClass())).append('.');
322 sb.append(getName()).append('(');
323 Class<?>[] params = getParameterTypes(); // avoid clone
324 for (int j = 0; j < params.length; j++) {
325 sb.append(Field.getTypeName(params[j]));
326 if (j < (params.length - 1))
331 Class<?>[] exceptions = exceptionTypes; // avoid clone
332 if (exceptions.length > 0) {
333 sb.append(" throws ");
334 for (int k = 0; k < exceptions.length; k++) {
335 sb.append(exceptions[k].getName());
336 if (k < (exceptions.length - 1))
341 return sb.toString();
342 } catch (Exception e) {
343 return "<" + e + ">";
348 * Returns a string describing this {@code Method}, including
349 * type parameters. The string is formatted as the method access
350 * modifiers, if any, followed by an angle-bracketed
351 * comma-separated list of the method's type parameters, if any,
352 * followed by the method's generic return type, followed by a
353 * space, followed by the class declaring the method, followed by
354 * a period, followed by the method name, followed by a
355 * parenthesized, comma-separated list of the method's generic
356 * formal parameter types.
358 * If this method was declared to take a variable number of
359 * arguments, instead of denoting the last parameter as
360 * "<tt><i>Type</i>[]</tt>", it is denoted as
361 * "<tt><i>Type</i>...</tt>".
363 * A space is used to separate access modifiers from one another
364 * and from the type parameters or return type. If there are no
365 * type parameters, the type parameter list is elided; if the type
366 * parameter list is present, a space separates the list from the
367 * class name. If the method is declared to throw exceptions, the
368 * parameter list is followed by a space, followed by the word
369 * throws followed by a comma-separated list of the generic thrown
370 * exception types. If there are no type parameters, the type
371 * parameter list is elided.
373 * <p>The access modifiers are placed in canonical order as
374 * specified by "The Java Language Specification". This is
375 * {@code public}, {@code protected} or {@code private} first,
376 * and then other modifiers in the following order:
377 * {@code abstract}, {@code static}, {@code final},
378 * {@code synchronized}, {@code native}, {@code strictfp}.
380 * @return a string describing this {@code Method},
381 * include type parameters
385 public String toGenericString() {
387 StringBuilder sb = new StringBuilder();
388 int mod = getModifiers() & Modifier.methodModifiers();
390 sb.append(Modifier.toString(mod)).append(' ');
392 TypeVariable<?>[] typeparms = getTypeParameters();
393 if (typeparms.length > 0) {
394 boolean first = true;
396 for(TypeVariable<?> typeparm: typeparms) {
399 // Class objects can't occur here; no need to test
400 // and call Class.getName().
401 sb.append(typeparm.toString());
407 Type genRetType = getGenericReturnType();
408 sb.append( ((genRetType instanceof Class<?>)?
409 Field.getTypeName((Class<?>)genRetType):genRetType.toString()))
412 sb.append(Field.getTypeName(getDeclaringClass())).append('.');
413 sb.append(getName()).append('(');
414 Type[] params = getGenericParameterTypes();
415 for (int j = 0; j < params.length; j++) {
416 String param = (params[j] instanceof Class)?
417 Field.getTypeName((Class)params[j]):
418 (params[j].toString());
419 if (isVarArgs() && (j == params.length - 1)) // replace T[] with T...
420 param = param.replaceFirst("\\[\\]$", "...");
422 if (j < (params.length - 1))
426 Type[] exceptions = getGenericExceptionTypes();
427 if (exceptions.length > 0) {
428 sb.append(" throws ");
429 for (int k = 0; k < exceptions.length; k++) {
430 sb.append((exceptions[k] instanceof Class)?
431 ((Class)exceptions[k]).getName():
432 exceptions[k].toString());
433 if (k < (exceptions.length - 1))
437 return sb.toString();
438 } catch (Exception e) {
439 return "<" + e + ">";
444 * Invokes the underlying method represented by this {@code Method}
445 * object, on the specified object with the specified parameters.
446 * Individual parameters are automatically unwrapped to match
447 * primitive formal parameters, and both primitive and reference
448 * parameters are subject to method invocation conversions as
451 * <p>If the underlying method is static, then the specified {@code obj}
452 * argument is ignored. It may be null.
454 * <p>If the number of formal parameters required by the underlying method is
455 * 0, the supplied {@code args} array may be of length 0 or null.
457 * <p>If the underlying method is an instance method, it is invoked
458 * using dynamic method lookup as documented in The Java Language
459 * Specification, Second Edition, section 15.12.4.4; in particular,
460 * overriding based on the runtime type of the target object will occur.
462 * <p>If the underlying method is static, the class that declared
463 * the method is initialized if it has not already been initialized.
465 * <p>If the method completes normally, the value it returns is
466 * returned to the caller of invoke; if the value has a primitive
467 * type, it is first appropriately wrapped in an object. However,
468 * if the value has the type of an array of a primitive type, the
469 * elements of the array are <i>not</i> wrapped in objects; in
470 * other words, an array of primitive type is returned. If the
471 * underlying method return type is void, the invocation returns
474 * @param obj the object the underlying method is invoked from
475 * @param args the arguments used for the method call
476 * @return the result of dispatching the method represented by
477 * this object on {@code obj} with parameters
480 * @exception IllegalAccessException if this {@code Method} object
481 * is enforcing Java language access control and the underlying
482 * method is inaccessible.
483 * @exception IllegalArgumentException if the method is an
484 * instance method and the specified object argument
485 * is not an instance of the class or interface
486 * declaring the underlying method (or of a subclass
487 * or implementor thereof); if the number of actual
488 * and formal parameters differ; if an unwrapping
489 * conversion for primitive arguments fails; or if,
490 * after possible unwrapping, a parameter value
491 * cannot be converted to the corresponding formal
492 * parameter type by a method invocation conversion.
493 * @exception InvocationTargetException if the underlying method
494 * throws an exception.
495 * @exception NullPointerException if the specified object is null
496 * and the method is an instance method.
497 * @exception ExceptionInInitializerError if the initialization
498 * provoked by this method fails.
500 public Object invoke(Object obj, Object... args)
501 throws IllegalAccessException, IllegalArgumentException,
502 InvocationTargetException
504 final boolean isStatic = (getModifiers() & Modifier.STATIC) == 0;
505 if (isStatic && obj == null) {
506 throw new NullPointerException();
508 Class[] types = getParameterTypes();
509 if (types.length != args.length) {
510 throw new IllegalArgumentException("Types len " + types.length + " args: " + args.length);
513 for (int i = 0; i < types.length; i++) {
515 if (c.isPrimitive()) {
516 args[i] = toPrimitive(c, args[i]);
520 Object res = invoke0(isStatic, this, obj, args);
521 if (getReturnType().isPrimitive()) {
522 res = fromPrimitive(getReturnType(), res);
527 @JavaScriptBody(args = { "st", "method", "self", "args" }, body =
530 + " p = new Array(1);\n"
532 + " p = p.concat(args);\n"
536 + "return method._data().apply(self, p);\n"
538 private static native Object invoke0(boolean isStatic, Method m, Object self, Object[] args);
540 static Object fromPrimitive(Class<?> type, Object o) {
541 if (type == Integer.TYPE) {
542 return fromRaw(Integer.class, "valueOf__Ljava_lang_Integer_2I", o);
544 if (type == Long.TYPE) {
545 return fromRaw(Long.class, "valueOf__Ljava_lang_Long_2J", o);
547 if (type == Double.TYPE) {
548 return fromRaw(Double.class, "valueOf__Ljava_lang_Double_2D", o);
550 if (type == Float.TYPE) {
551 return fromRaw(Float.class, "valueOf__Ljava_lang_Float_2F", o);
553 if (type == Byte.TYPE) {
554 return fromRaw(Byte.class, "valueOf__Ljava_lang_Byte_2B", o);
556 if (type == Boolean.TYPE) {
557 return fromRaw(Boolean.class, "valueOf__Ljava_lang_Boolean_2Z", o);
559 if (type == Short.TYPE) {
560 return fromRaw(Short.class, "valueOf__Ljava_lang_Short_2S", o);
562 if (type == Character.TYPE) {
563 return fromRaw(Character.class, "valueOf__Ljava_lang_Character_2C", o);
565 if (type.getName().equals("void")) {
568 throw new IllegalStateException("Can't convert " + o);
571 @JavaScriptBody(args = { "cls", "m", "o" },
572 body = "return cls.cnstr(false)[m](o);"
574 private static native Integer fromRaw(Class<?> cls, String m, Object o);
576 private static Object toPrimitive(Class<?> type, Object o) {
577 if (type == Integer.TYPE) {
578 return toRaw("intValue__I", o);
580 if (type == Long.TYPE) {
581 return toRaw("longValue__J", o);
583 if (type == Double.TYPE) {
584 return toRaw("doubleValue__D", o);
586 if (type == Float.TYPE) {
587 return toRaw("floatValue__F", o);
589 if (type == Byte.TYPE) {
590 return toRaw("byteValue__B", o);
592 if (type == Boolean.TYPE) {
593 return toRaw("booleanValue__Z", o);
595 if (type == Short.TYPE) {
596 return toRaw("shortValue__S", o);
598 if (type == Character.TYPE) {
599 return toRaw("charValue__C", o);
601 if (type.getName().equals("void")) {
604 throw new IllegalStateException("Can't convert " + o);
607 @JavaScriptBody(args = { "m", "o" },
608 body = "return o[m](o);"
610 private static native Object toRaw(String m, Object o);
613 * Returns {@code true} if this method is a bridge
614 * method; returns {@code false} otherwise.
616 * @return true if and only if this method is a bridge
617 * method as defined by the Java Language Specification.
620 public boolean isBridge() {
621 return (getModifiers() & Modifier.BRIDGE) != 0;
625 * Returns {@code true} if this method was declared to take
626 * a variable number of arguments; returns {@code false}
629 * @return {@code true} if an only if this method was declared to
630 * take a variable number of arguments.
633 public boolean isVarArgs() {
634 return (getModifiers() & Modifier.VARARGS) != 0;
638 * Returns {@code true} if this method is a synthetic
639 * method; returns {@code false} otherwise.
641 * @return true if and only if this method is a synthetic
642 * method as defined by the Java Language Specification.
645 public boolean isSynthetic() {
646 return Modifier.isSynthetic(getModifiers());
649 @JavaScriptBody(args = { "ac" },
651 "var a = this._data().anno;"
653 + " return a['L' + ac.jvmName + ';'];"
654 + "} else return null;"
656 private Object getAnnotationData(Class<?> annotationClass) {
657 throw new UnsupportedOperationException();
661 * @throws NullPointerException {@inheritDoc}
664 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
665 Object data = getAnnotationData(annotationClass);
666 return data == null ? null : AnnotationImpl.create(annotationClass, data);
672 public Annotation[] getDeclaredAnnotations() {
673 throw new UnsupportedOperationException();
677 * Returns the default value for the annotation member represented by
678 * this {@code Method} instance. If the member is of a primitive type,
679 * an instance of the corresponding wrapper type is returned. Returns
680 * null if no default is associated with the member, or if the method
681 * instance does not represent a declared member of an annotation type.
683 * @return the default value for the annotation member represented
684 * by this {@code Method} instance.
685 * @throws TypeNotPresentException if the annotation is of type
686 * {@link Class} and no definition can be found for the
687 * default class value.
690 public Object getDefaultValue() {
691 throw new UnsupportedOperationException();
695 * Returns an array of arrays that represent the annotations on the formal
696 * parameters, in declaration order, of the method represented by
697 * this {@code Method} object. (Returns an array of length zero if the
698 * underlying method is parameterless. If the method has one or more
699 * parameters, a nested array of length zero is returned for each parameter
700 * with no annotations.) The annotation objects contained in the returned
701 * arrays are serializable. The caller of this method is free to modify
702 * the returned arrays; it will have no effect on the arrays returned to
705 * @return an array of arrays that represent the annotations on the formal
706 * parameters, in declaration order, of the method represented by this
710 public Annotation[][] getParameterAnnotations() {
711 throw new UnsupportedOperationException();
715 MethodImpl.INSTANCE = new MethodImpl() {
716 protected Method create(Class<?> declaringClass, String name, Object data, String sig) {
717 return new Method(declaringClass, name, data, sig);