/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.lang.reflect;
import java.lang.annotation.Annotation;
import java.lang.reflect.VMCommonLibrarySupport;
import org.jikesrvm.classloader.RVMClass;
import org.jikesrvm.classloader.RVMMember;
import org.jikesrvm.classloader.RVMMethod;
import org.jikesrvm.runtime.Reflection;
import org.jikesrvm.runtime.ReflectionBase;
/**
* This class must be implemented by the VM vendor. This class models a method.
* Information about the method can be accessed, and the method can be invoked
* dynamically.
*
*/
public final class Method extends AccessibleObject implements GenericDeclaration, Member {
private final RVMMethod vmMethod;
private final ReflectionBase invoker;
/**
* Constructor
*/
Method(RVMMethod vmMethod){
this.vmMethod = vmMethod;
if (Reflection.cacheInvokerInJavaLangReflect) {
invoker = vmMethod.getInvoker();
} else {
invoker = null;
}
}
/**
* Prevent this class from being instantiated
*/
private Method(){
vmMethod = null;
invoker = null;
}
public TypeVariable<Method>[] getTypeParameters() {
throw new Error("TODO");
}
/**
* <p>
* Returns the String representation of the method's declaration, including
* the type parameters.
* </p>
*
* @return An instance of String.
* @since 1.5
*/
public String toGenericString() {
throw new Error("TODO");
}
/**
* <p>
* Gets the parameter types as an array of {@link Type} instances, in
* declaration order. If the method has no parameters, then an empty array
* is returned.
* </p>
*
* @return An array of {@link Type} instances.
* @throws GenericSignatureFormatError if the generic method signature is
* invalid.
* @throws TypeNotPresentException if the component type points to a missing
* type.
* @throws MalformedParameterizedTypeException if the component type points
* to a type that can't be instantiated for some reason.
* @since 1.5
*/
public Type[] getGenericParameterTypes() {
throw new Error("TODO");
}
/**
* <p>
* Gets the exception types as an array of {@link Type} instances. If the
* method has no declared exceptions, then an empty array is returned.
* </p>
*
* @return An array of {@link Type} instances.
* @throws GenericSignatureFormatError if the generic method signature is
* invalid.
* @throws TypeNotPresentException if the component type points to a missing
* type.
* @throws MalformedParameterizedTypeException if the component type points
* to a type that can't be instantiated for some reason.
* @since 1.5
*/
public Type[] getGenericExceptionTypes() {
throw new Error("TODO");
}
/**
* <p>
* Gets the return type as a {@link Type} instance.
* </p>
*
* @return A {@link Type} instance.
* @throws GenericSignatureFormatError if the generic method signature is
* invalid.
* @throws TypeNotPresentException if the component type points to a missing
* type.
* @throws MalformedParameterizedTypeException if the component type points
* to a type that can't be instantiated for some reason.
* @since 1.5
*/
public Type getGenericReturnType() {
throw new Error("TODO");
}
/**
* <p>
* Gets an array of arrays that represent the annotations of the formal
* parameters of this method. If there are no parameters on this method,
* then an empty array is returned. If there are no annotations set, then
* and array of empty arrays is returned.
* </p>
*
* @return An array of arrays of {@link Annotation} instances.
* @since 1.5
*/
public Annotation[][] getParameterAnnotations() {
return super.getParameterAnnotations();
}
/**
* <p>
* Indicates whether or not this method takes a variable number argument.
* </p>
*
* @return A value of <code>true</code> if a vararg is declare, otherwise
* <code>false</code>.
* @since 1.5
*/
public boolean isVarArgs() {
return super.isVarArgs();
}
/**
* <p>
* Indicates whether or not this method is a bridge.
* </p>
*
* @return A value of <code>true</code> if this method's a bridge,
* otherwise <code>false</code>.
* @since 1.5
*/
public boolean isBridge() {
return (vmMethod.getModifiers() & Modifier.BRIDGE) != 0;
}
public boolean isSynthetic() {
return super.isSynthetic();
}
/**
* <p>Gets the default value for the annotation member represented by
* this method.</p>
* @return The default value or <code>null</code> if none.
* @throws TypeNotPresentException if the annotation is of type {@link Class}
* and no definition can be found.
* @since 1.5
*/
public Object getDefaultValue() {
return vmMethod.getAnnotationDefault();
}
/**
* Compares the specified object to this Method and answer if they are
* equal. The object must be an instance of Method with the same defining
* class and parameter types.
*
* @param object
* the object to compare
* @return true if the specified object is equal to this Method, false
* otherwise
* @see #hashCode
*/
@Override
public boolean equals(Object object) {
if (object instanceof Method) {
Method that = (Method)object;
return this.vmMethod == that.vmMethod;
} else {
return false;
}
}
/**
* Return the {@link Class} associated with the class that defined this
* method.
*
* @return the declaring class
*/
public Class<?> getDeclaringClass() {
return (Class<?>)vmMethod.getDeclaringClass().getClassForType();
}
/**
* Return an array of the {@link Class} objects associated with the
* exceptions declared to be thrown by this method. If the method was not
* declared to throw any exceptions, the array returned will be empty.
*
* @return the declared exception classes
*/
public Class<?>[] getExceptionTypes() {
return super.getExceptionTypes();
}
/**
* Return the modifiers for the modeled method. The Modifier class
* should be used to decode the result.
*
* @return the modifiers
* @see java.lang.reflect.Modifier
*/
public int getModifiers() {
return super.getModifiers();
}
/**
* Return the name of the modeled method.
*
* @return the name
*/
public String getName() {
return vmMethod.getName().toString();
}
/**
* Return an array of the {@link Class} objects associated with the
* parameter types of this method. If the method was declared with no
* parameters, the array returned will be empty.
*
* @return the parameter types
*/
public Class<?>[] getParameterTypes() {
return VMCommonLibrarySupport.typesToClasses(vmMethod.getParameterTypes());
}
/**
* Return the {@link Class} associated with the return type of this
* method.
*
* @return the return type
*/
public Class<?> getReturnType() {
return vmMethod.getReturnType().resolve().getClassForType();
}
/**
* Answers an integer hash code for the receiver. Objects which are equal
* answer the same value for this method. The hash code for a Method is the
* hash code of the method's name.
*
* @return the receiver's hash
* @see #equals
*/
@Override
public int hashCode() {
return getName().hashCode();
}
/**
* Return the result of dynamically invoking the modeled method. This
* reproduces the effect of
* <code>receiver.methodName(arg1, arg2, ... , argN)</code> This method
* performs the following:
* <ul>
* <li>If the modeled method is static, the receiver argument is ignored.
* </li>
* <li>Otherwise, if the receiver is null, a NullPointerException is
* thrown.</li>
* If the receiver is not an instance of the declaring class of the method,
* an IllegalArgumentException is thrown.
* <li>If this Method object is enforcing access control (see
* AccessibleObject) and the modeled method is not accessible from the
* current context, an IllegalAccessException is thrown.</li>
* <li>If the number of arguments passed and the number of parameters do
* not match, an IllegalArgumentException is thrown.</li>
* <li>For each argument passed:
* <ul>
* <li>If the corresponding parameter type is a base type, the argument is
* unwrapped. If the unwrapping fails, an IllegalArgumentException is
* thrown.</li>
* <li>If the resulting argument cannot be converted to the parameter type
* via a widening conversion, an IllegalArgumentException is thrown.</li>
* </ul>
* <li>If the modeled method is static, it is invoked directly. If it is
* non-static, the modeled method and the receiver are then used to perform
* a standard dynamic method lookup. The resulting method is then invoked.
* </li>
* <li>If an exception is thrown during the invocation it is caught and
* wrapped in an InvocationTargetException. This exception is then thrown.
* </li>
* <li>If the invocation completes normally, the return value is itself
* returned. If the method is declared to return a base type, the return
* value is first wrapped. If the return type is void, null is returned.
* </li>
* </ul>
*
* @param receiver
* The object on which to call the modeled method
* @param args
* the arguments to the method
* @return the new, initialized, object
* @throws java.lang.NullPointerException
* if the receiver is null for a non-static method
* @throws java.lang.IllegalAccessException
* if the modeled method is not accessible
* @throws java.lang.IllegalArgumentException
* if an incorrect number of arguments are passed, the
* receiver is incompatible with the declaring class, or an
* argument could not be converted by a widening conversion
* @throws java.lang.reflect.InvocationTargetException
* if an exception was thrown by the invoked method
* @see java.lang.reflect.AccessibleObject
*/
public Object invoke(Object receiver, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
return VMCommonLibrarySupport.invoke(receiver, args, vmMethod, this, RVMClass.getClassFromStackFrame(1), invoker);
}
/**
* Answers a string containing a concise, human-readable description of the
* receiver. The format of the string is modifiers (if any) return type
* declaring class name '.' method name '(' parameter types, separated by
* ',' ')' If the method throws exceptions, ' throws ' exception types,
* separated by ',' For example:
* <code>public native Object java.lang.Method.invoke(Object,Object) throws IllegalAccessException,IllegalArgumentException,InvocationTargetException</code>
*
* @return a printable representation for the receiver
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder(80);
// append modifiers if any
int modifier = getModifiers();
if (modifier != 0) {
// BRIDGE & VARARGS recognized incorrectly
final int MASK = ~(Modifier.BRIDGE | Modifier.VARARGS);
sb.append(Modifier.toString(modifier & MASK)).append(' ');
}
// append return type
appendArrayType(sb, getReturnType());
sb.append(' ');
// append full method name
sb.append(getDeclaringClass().getName()).append('.').append(getName());
// append parameters
sb.append('(');
appendArrayType(sb, getParameterTypes());
sb.append(')');
// append exeptions if any
Class[] exn = getExceptionTypes();
if (exn.length > 0) {
sb.append(" throws ");
appendSimpleType(sb, exn);
}
return sb.toString();
}
/* ---- Non-API methods ---- */
/**
* Get the VM member implementation. Package protected to stop outside use.
*/
@Override
RVMMember getVMMember() {
return vmMethod;
}
/**
* Get the VM method implementation, invalid for fields. Package protected to
* stop outside use.
*/
@Override
RVMMethod getVMMethod() {
return vmMethod;
}
}