blob: 5dd073ee1e199b79658c83617e9d23170ec2749e [file] [log] [blame]
/*
* 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.
*/
/**
* @author Evgueni Brevnov, Serguei S. Zapreyev, Alexey V. Varlamov
*/
package java.lang.reflect;
import static org.apache.harmony.vm.ClassFormat.ACC_BRIDGE;
import static org.apache.harmony.vm.ClassFormat.ACC_SYNTHETIC;
import static org.apache.harmony.vm.ClassFormat.ACC_VARARGS;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import org.apache.harmony.lang.reflect.parser.Parser;
import org.apache.harmony.vm.VMGenericsAndAnnotations;
import org.apache.harmony.vm.VMStack;
/**
* @com.intel.drl.spec_ref
*/
public final class Method extends AccessibleObject implements Member, GenericDeclaration {
/**
* @com.intel.drl.spec_ref
*/
public boolean isBridge() {
return (getModifiers() & ACC_BRIDGE) != 0;
}
/**
* @com.intel.drl.spec_ref
*/
public boolean isVarArgs() {
return (getModifiers() & ACC_VARARGS) != 0;
}
/**
* @com.intel.drl.spec_ref
*/
public Annotation[][] getParameterAnnotations() {
Annotation a[][] = data.getParameterAnnotations();
Annotation aa[][] = new Annotation[a.length][];
for (int i = 0; i < a.length; i++ ) {
aa[i] = new Annotation[a[i].length];
System.arraycopy(a[i], 0, aa[i], 0, a[i].length);
}
return aa;
}
/**
* @com.intel.drl.spec_ref
*/
public Annotation[] getDeclaredAnnotations() {
Annotation a[] = data.getDeclaredAnnotations();
Annotation aa[] = new Annotation[a.length];
System.arraycopy(a, 0, aa, 0, a.length);
return aa;
}
/**
* @com.intel.drl.spec_ref
*/
@SuppressWarnings("unchecked")
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
if(annotationClass == null) {
throw new NullPointerException();
}
for (Annotation aa : data.getDeclaredAnnotations()) {
if(aa.annotationType() == annotationClass) {
return (A) aa;
}
}
return null;
}
/**
* @com.intel.drl.spec_ref
*/
public Type[] getGenericExceptionTypes() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException {
if (data.genericExceptionTypes == null) {
data.genericExceptionTypes = Parser.getGenericExceptionTypes(this, VMGenericsAndAnnotations.getSignature(data.vm_member_id));
}
return (Type[])data.genericExceptionTypes.clone();
}
/**
* @com.intel.drl.spec_ref
*/
public Type[] getGenericParameterTypes() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException {
if (data.genericParameterTypes == null) {
data.genericParameterTypes = Parser.getGenericParameterTypes(this, VMGenericsAndAnnotations.getSignature(data.vm_member_id));
}
return (Type[])data.genericParameterTypes.clone();
}
/**
* @com.intel.drl.spec_ref
*/
public Type getGenericReturnType() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException {
if (data.genericReturnType == null) {
data.genericReturnType = Parser.getGenericReturnTypeImpl(this, VMGenericsAndAnnotations
.getSignature(data.vm_member_id));
}
return data.genericReturnType;
}
/**
* @com.intel.drl.spec_ref
*/
@SuppressWarnings("unchecked")
public TypeVariable<Method>[] getTypeParameters() throws GenericSignatureFormatError {
if (data.typeParameters == null) {
data.typeParameters = Parser.getTypeParameters(this,
VMGenericsAndAnnotations.getSignature(data.vm_member_id));
}
return (TypeVariable<Method>[]) data.typeParameters.clone();
}
/**
* @com.intel.drl.spec_ref
*/
public String toGenericString() {
StringBuilder sb = new StringBuilder(80);
// data initialization
if (data.genericParameterTypes == null) {
data.genericParameterTypes = Parser.getGenericParameterTypes(this, VMGenericsAndAnnotations.getSignature(data.vm_member_id));
}
if (data.genericExceptionTypes == null) {
data.genericExceptionTypes = Parser.getGenericExceptionTypes(this, VMGenericsAndAnnotations.getSignature(data.vm_member_id));
}
// append modifiers if any
int modifier = getModifiers();
if (modifier != 0) {
sb.append(Modifier.toString(modifier & ~(ACC_BRIDGE + ACC_VARARGS))).append(' ');
}
// append type parameters
if (data.typeParameters != null && data.typeParameters.length > 0) {
sb.append('<');
for (int i = 0; i < data.typeParameters.length; i++) {
appendGenericType(sb, data.typeParameters[i]);
if (i < data.typeParameters.length - 1) {
sb.append(", ");
}
}
sb.append("> ");
}
// append return type
appendGenericType(sb, getGenericReturnType());
sb.append(' ');
// append method name
appendArrayType(sb, getDeclaringClass());
sb.append("."+getName());
// append parameters
sb.append('(');
appendArrayGenericType(sb, data.genericParameterTypes);
sb.append(')');
// append exeptions if any
if (data.genericExceptionTypes.length > 0) {
sb.append(" throws ");
appendArrayGenericType(sb, data.genericExceptionTypes);
}
return sb.toString();
}
/**
* @com.intel.drl.spec_ref
*/
public boolean isSynthetic() {
return (getModifiers() & ACC_SYNTHETIC) != 0;
}
/**
* @com.intel.drl.spec_ref
*/
public Object getDefaultValue() {
return VMGenericsAndAnnotations.getDefaultValue(data.vm_member_id);
}
/**
* cache of the method data
*/
private final MethodData data;
/**
* Copy constructor
*
* @param m original method
*/
Method(Method m) {
data = m.data;
isAccessible = m.isAccessible;
}
/**
* Only VM should call this constructor.
* String parameters must be interned.
* @api2vm
*/
Method(long id, Class clss, String name, String desc, int m) {
data = new MethodData(id, clss, name, desc, m);
}
/**
* Called by VM to obtain this method's handle.
*
* @return handle for this method
* @api2vm
*/
long getId() {
return data.vm_member_id;
}
/**
* @com.intel.drl.spec_ref
*/
public boolean equals(Object obj) {
if (obj instanceof Method) {
Method another = (Method)obj;
if (data.vm_member_id == another.data.vm_member_id){
assert getDeclaringClass() == another.getDeclaringClass()
&& getName() == another.getName()
&& getReturnType() == another.getReturnType()
&& Arrays.equals(getParameterTypes(), another.getParameterTypes());
return true;
}
}
return false;
}
/**
* @com.intel.drl.spec_ref
*/
public Class<?> getDeclaringClass() {
return data.declaringClass;
}
/**
* @com.intel.drl.spec_ref
*/
public Class<?>[] getExceptionTypes() {
return (Class[])data.getExceptionTypes().clone();
}
/**
* @com.intel.drl.spec_ref
*/
public int getModifiers() {
return data.modifiers;
}
/**
* @com.intel.drl.spec_ref
*/
public String getName() {
return data.name;
}
/**
* @com.intel.drl.spec_ref
*/
public Class<?>[] getParameterTypes() {
return (Class[])data.getParameterTypes().clone();
}
/**
* @com.intel.drl.spec_ref
*/
public Class<?> getReturnType() {
return data.getReturnType();
}
/**
* @com.intel.drl.spec_ref
*/
public int hashCode() {
return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
}
/**
* @com.intel.drl.spec_ref
*/
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
obj = checkObject(getDeclaringClass(), getModifiers(), obj);
// check parameter validity
checkInvokationArguments(data.getParameterTypes(), args);
if (!isAccessible) {
reflectExporter.checkMemberAccess(
VMStack.getCallerClass(0), getDeclaringClass(),
obj == null ? getDeclaringClass() : obj.getClass(),
getModifiers()
);
}
return VMReflection.invokeMethod(data.vm_member_id, obj, args);
}
/**
* @com.intel.drl.spec_ref
*/
public String toString() {
StringBuilder sb = new StringBuilder();
// append modifiers if any
int modifier = getModifiers();
if (modifier != 0) {
// BRIDGE & VARARGS recognized incorrectly
final int MASK = ~(ACC_BRIDGE + ACC_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, data.getParameterTypes());
sb.append(')');
// append exeptions if any
Class[] exn = data.getExceptionTypes();
if (exn.length > 0) {
sb.append(" throws ");
appendSimpleType(sb, exn);
}
return sb.toString();
}
/* NON API SECTION */
/**
* This method is required by serialization mechanism.
*
* @return the signature of the method
*/
String getSignature() {
return data.descriptor;
}
/**
* Keeps an information about this method
*/
private class MethodData {
/**
* method handle which is used to retrieve all necessary information
* about this method object
*/
final long vm_member_id;
Annotation[] declaredAnnotations;
final Class<?> declaringClass;
private Class<?>[] exceptionTypes;
Type[] genericExceptionTypes;
Type[] genericParameterTypes;
Type genericReturnType;
String methSignature;
final int modifiers;
final String name;
final String descriptor;
/**
* declared method annotations
*/
Annotation[][] parameterAnnotations;
/**
* method parameters
*/
Class<?>[] parameterTypes;
/**
* method return type
*/
private Class<?> returnType;
/**
* method type parameters
*/
TypeVariable<Method>[] typeParameters;
/**
* @param obj method handler
*/
public MethodData(long vm_id, Class clss, String name, String desc, int mods) {
vm_member_id = vm_id;
declaringClass = clss;
this.name = name;
modifiers = mods;
descriptor = desc;
}
public Annotation[] getDeclaredAnnotations() {
if (declaredAnnotations == null) {
declaredAnnotations = VMGenericsAndAnnotations
.getDeclaredAnnotations(vm_member_id);
}
return declaredAnnotations;
}
/**
* initializes exeptions
*/
public Class<?>[] getExceptionTypes() {
if (exceptionTypes == null) {
exceptionTypes = VMReflection.getExceptionTypes(vm_member_id);
}
return exceptionTypes;
}
public Annotation[][] getParameterAnnotations() {
if (parameterAnnotations == null) {
parameterAnnotations = VMGenericsAndAnnotations
.getParameterAnnotations(vm_member_id);
}
return parameterAnnotations;
}
/**
* initializes parameters
*/
public Class[] getParameterTypes() {
if (parameterTypes == null) {
parameterTypes = VMReflection.getParameterTypes(vm_member_id);
}
return parameterTypes;
}
/**
* initializes return type
*/
public Class<?> getReturnType() {
if (returnType == null) {
returnType = VMReflection.getMethodReturnType(vm_member_id);
}
return returnType;
}
}
}