/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package java.lang.reflect;
import java.lang.annotation.Annotation;
import org.jikesrvm.classloader.*;
import org.jikesrvm.runtime.VM_Reflection;
import org.jikesrvm.runtime.VM_Magic;
import org.jikesrvm.runtime.VM_Runtime;
/**
* Implementation of java.lang.reflect.Field for JikesRVM.
*
* By convention, order methods in the same order
* as they appear in the method summary list of Sun's 1.4 Javadoc API.
*/
public final class Method extends AccessibleObject implements Member {
final VM_Method method;
// Prevent this class from being instantiated.
@SuppressWarnings("unused")
private Method() {
method = null;
}
// For use by JikesRVMSupport
Method(VM_Method m) {
method = m;
}
public boolean equals(Object other) {
if (other instanceof Method) {
return method == ((Method)other).method;
} else {
return false;
}
}
public Class<?> getDeclaringClass() {
return method.getDeclaringClass().getClassForType();
}
public Class<?>[] getExceptionTypes() {
VM_TypeReference[] exceptionTypes = method.getExceptionTypes();
if (exceptionTypes == null) {
return new Class[0];
} else {
return JikesRVMSupport.typesToClasses(exceptionTypes);
}
}
public int getModifiers() {
return method.getModifiers();
}
public String getName() {
return method.getName().toString();
}
public Class<?>[] getParameterTypes() {
return JikesRVMSupport.typesToClasses(method.getParameterTypes());
}
public boolean isSynthetic() {
return method.isSynthetic();
}
public Class<?> getReturnType() {
return method.getReturnType().resolve(false).getClassForType();
}
public int hashCode() {
int code1 = getName().hashCode();
int code2 = method.getDeclaringClass().toString().hashCode();
return code1 ^ code2;
}
public Object invoke(Object receiver, Object[] args) throws IllegalAccessException,
IllegalArgumentException,
ExceptionInInitializerError,
InvocationTargetException {
VM_Method method = this.method;
VM_Class declaringClass = method.getDeclaringClass();
// validate "this" argument
if (!method.isStatic()) {
if (receiver == null) throw new NullPointerException();
receiver = JikesRVMSupport.makeArgumentCompatible(declaringClass, receiver);
}
// validate number and types of remaining arguments
VM_TypeReference[] parameterTypes = method.getParameterTypes();
if (args == null) {
if (parameterTypes.length != 0) {
throw new IllegalArgumentException("argument count mismatch");
}
} else if (args.length != parameterTypes.length) {
throw new IllegalArgumentException("argument count mismatch");
}
for (int i = 0, n = parameterTypes.length; i < n; ++i) {
args[i] = JikesRVMSupport.makeArgumentCompatible(parameterTypes[i].resolve(false), args[i]);
}
// Accessibility checks
if (!method.isPublic() && !isAccessible()) {
VM_Class accessingClass = VM_Class.getClassFromStackFrame(1);
JikesRVMSupport.checkAccess(method, accessingClass);
}
// find the right method to call
if (! method.isStatic()) {
VM_Class C = VM_Magic.getObjectType(receiver).asClass();
method = C.findVirtualMethod(method.getName(), method.getDescriptor());
}
// Forces initialization of declaring class
if (method.isStatic() && !declaringClass.isInitialized(false)) {
try {
VM_Runtime.initializeClassForDynamicLink(declaringClass);
} catch (Throwable e) {
ExceptionInInitializerError ex = new ExceptionInInitializerError();
ex.initCause(e);
throw ex;
}
}
// Invoke method
try {
return VM_Reflection.invoke(method, receiver, args);
} catch (Throwable t) {
throw new InvocationTargetException(t,
"While invoking the method:\n\t\"" + method + "\"\n" +
" on the object:\n\t\"" + receiver + "\"\n" +
" it threw the exception:\n\t\"" + t + "\"");
}
}
public String toString() {
StringBuilder sb = new StringBuilder(128);
Modifier.toString(getModifiers(), sb).append(' ');
sb.append(JikesRVMHelpers.getUserName(getReturnType())).append(' ');
sb.append(getDeclaringClass().getName()).append('.');
sb.append(getName()).append('(');
Class<?>[] c = getParameterTypes();
if (c.length > 0) {
sb.append(JikesRVMHelpers.getUserName(c[0]));
for (int i = 1; i < c.length; i++) {
sb.append(',').append(JikesRVMHelpers.getUserName(c[i]));
}
}
sb.append(')');
c = getExceptionTypes();
if (c.length > 0) {
sb.append(" throws ").append(c[0].getName());
for (int i = 1; i < c.length; i++)
sb.append(',').append(c[i].getName());
}
return sb.toString();
}
// AnnotatedElement interface
public Annotation[] getDeclaredAnnotations() {
return method.getDeclaredAnnotations();
}
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
return method.getAnnotation(annotationClass);
}
// Generics support
public TypeVariable<?>[] getTypeParameters() {
VM_Atom sig = method.getSignature();
if (sig == null) {
return new TypeVariable[0];
} else {
return JikesRVMHelpers.getTypeParameters(this, sig);
}
}
public Type[] getGenericExceptionTypes() {
VM_Atom sig = method.getSignature();
if (sig == null) {
return getExceptionTypes();
} else {
return JikesRVMHelpers.getGenericExceptionTypes(this, sig);
}
}
public Type[] getGenericParameterTypes() {
VM_Atom sig = method.getSignature();
if (sig == null) {
return getParameterTypes();
} else {
return JikesRVMHelpers.getGenericParameterTypes(this, sig);
}
}
public Type getGenericReturnType() {
VM_Atom sig = method.getSignature();
if (sig == null) {
return getReturnType();
} else {
return JikesRVMHelpers.getGenericReturnType(this, sig);
}
}
public String toGenericString() {
StringBuilder sb = new StringBuilder(128);
Modifier.toString(getModifiers(), sb).append(' ');
Constructor.addTypeParameters(sb, getTypeParameters());
sb.append(getGenericReturnType()).append(' ');
sb.append(getDeclaringClass().getName()).append('.');
sb.append(getName()).append('(');
Type[] types = getGenericParameterTypes();
if (types.length > 0) {
sb.append(types[0]);
for (int i = 1; i < types.length; i++) {
sb.append(',').append(types[i]);
}
}
sb.append(')');
types = getGenericExceptionTypes();
if (types.length > 0) {
sb.append(" throws ").append(types[0]);
for (int i = 1; i < types.length; i++) {
sb.append(',').append(types[i]);
}
}
return sb.toString();
}
}