/*
 
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
 
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
*
 
* This code is free software; you can redistribute it and/or modify it
 
* under the terms of the GNU General Public License version 2 only, as
 
* published by the Free Software Foundation.
  
Oracle designates this
 
* particular file as subject to the "Classpath" exception as provided
 
* by Oracle in the LICENSE file that accompanied this code.
 
*
 
* This code is distributed in the hope that it will be useful, but WITHOUT
 
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
* FITNESS FOR A PARTICULAR PURPOSE.
  
See the GNU General Public License
 
* version 2 for more details (a copy is included in the LICENSE file that
 
* accompanied this code).
 
*
 
* You should have received a copy of the GNU General Public License version
 
* 2 along with this work; if not, write to the Free Software Foundation,
 
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
*
 
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 
* or visit www.oracle.com if you need additional information or have any
 
* questions.
 
*/

package java.lang.reflect;

import sun.reflect.CallerSensitive;
import sun.reflect.MethodAccessor;
import sun.reflect.Reflection;
import sun.reflect.generics.repository.MethodRepository;
import sun.reflect.generics.factory.CoreReflectionFactory;
import sun.reflect.generics.factory.GenericsFactory;
import sun.reflect.generics.scope.MethodScope;
import sun.reflect.annotation.AnnotationType;
import sun.reflect.annotation.AnnotationParser;
import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
import java.nio.ByteBuffer;

/**
 
* A {@code Method} provides information about, and access to, a single method
 
* on a class or interface.
  
The reflected method may be a class method
 
* or an instance method (including an abstract method).
 
*
 
* <p>A {@code Method} permits widening conversions to occur when matching the
 
* actual parameters to invoke with the underlying method's formal
 
* parameters, but it throws an {@code IllegalArgumentException} if a
 
* narrowing conversion would occur.
 
*
 
* @see Member
 
*
 
* @see java.lang.Class#getMethods()
 
* @see java.lang.Class#getMethod(String, Class[])
 
* @see java.lang.Class#getDeclaredMethods()
 
* @see java.lang.Class#getDeclaredMethod(String, Class[])
 
*
 
* @author Kenneth Russell
 
* @author Nakul Saraiya
 
*/

public final class Method extends Executable {
    
private Class<?>
            
clazz;
    
private int
                 
slot;
    
// This is guaranteed to be interned by the VM in the 1.4
    
// reflection implementation
    
private String
              
name
;
    
private Class<?>
            
returnType;
    
private Class<?>[]
          
parameterTypes;
    
private Class<?>[]
          
exceptionTypes;
    
private int
                 
modifiers;
    
// Generics and annotations support
    
private transient String
              
signature
;
    
// generic info repository; lazily initialized
    
private transient MethodRepository genericInfo;
    
private byte[]
              
annotations;
    
private byte[]
              
parameterAnnotations;
    
private byte[]
              
annotationDefault;
    
private volatile MethodAccessor methodAccessor;
    
// For sharing of MethodAccessors. This branching structure is
    
// currently only two levels deep (i.e., one root Method and
    
// potentially many Method objects pointing to it.)
    
//
    
// If this branching structure would ever contain cycles, deadlocks can
    
// occur in annotation code.
    
private Method
              
root
;

    
// Generics infrastructure
    
private String getGenericSignature() {return signature;}

    
// Accessor for factory
    
private GenericsFactory getFactory() {
        
// create scope and factory
        
return CoreReflectionFactory.make(this, MethodScope.make(this));
    
}

    
// Accessor for generic info repository
    
@Override
    
MethodRepository getGenericInfo
() {
        
// lazily initialize repository if necessary
        
if (genericInfo == null) {
            
// create and cache generic info repository
            
genericInfo = MethodRepository.make(getGenericSignature(),
                                                
getFactory());
        
}
        
return genericInfo; //return cached repository
    
}

    
/**
     
* Package-private constructor used by ReflectAccess to enable
     
* instantiation of these objects in Java code from the java.lang
     
* package via sun.reflect.LangReflectAccess.
     
*/

    
Method(Class<?> declaringClass,
           
String name,
           
Class<?>[] parameterTypes,
           
Class<?> returnType,
           
Class<?>[] checkedExceptions,
           
int modifiers,
           
int slot,
           
String signature,
           
byte[] annotations,
           
byte[] parameterAnnotations,
           
byte[] annotationDefault) {
        
this.clazz = declaringClass;
        
this.name = name;
        
this.parameterTypes = parameterTypes;
        
this.returnType = returnType;
        
this.exceptionTypes = checkedExceptions;
        
this.modifiers = modifiers;
        
this.slot = slot;
        
this.signature = signature;
        
this.annotations = annotations;
        
this.parameterAnnotations = parameterAnnotations;
        
this.annotationDefault = annotationDefault;
    
}

    
/**
     
* Package-private routine (exposed to java.lang.Class via
     
* ReflectAccess) which returns a copy of this Method. The copy's
     
* "root" field points to this Method.
     
*/

    
Method copy() {
        
// This routine enables sharing of MethodAccessor objects
        
// among Method objects which refer to the same underlying
        
// method in the VM. (All of this contortion is only necessary
        
// because of the "accessibility" bit in AccessibleObject,
        
// which implicitly requires that new java.lang.reflect
        
// objects be fabricated for each reflective call on Class
        
// objects.)
        
if (this.root != null)
            
throw new IllegalArgumentException("Can not copy a non-root Method");

        
Method res = new Method(clazz, name, parameterTypes, returnType,
                                
exceptionTypes, modifiers, slot, signature,
                                
annotations, parameterAnnotations, annotationDefault);
        
res.root = this;
        
// Might as well eagerly propagate this if already present
        
res.methodAccessor = methodAccessor;
        
return res;
    
}

    
/**
     
* Used by Excecutable for annotation sharing.
     
*/
    
@Override
    
Executable getRoot
() {
        
return root;
    
}

    
@Override
    
boolean hasGenericInformation() {
        
return (getGenericSignature() != null);
    
}

    
@Override
    
byte[] getAnnotationBytes() {
        
return annotations;
    
}

    
/**
     
* {@inheritDoc}
     
*/
    
@Override
    
public Class<?> getDeclaringClass() {
        
return clazz;
    
}

    
/**
     
* Returns the name of the method represented by this {@code Method}
     
* object, as a {@code String}.
     
*/

    
@Override
    
public String getName() {
        
return name;
    
}

    
/**
     
* {@inheritDoc}
     
*/
    
@Override
    
public int getModifiers() {
        
return modifiers;
    
}

    
/**
     
* {@inheritDoc}
     
* @throws GenericSignatureFormatError {@inheritDoc}
     
* @since 1.5
     
*/

    
@Override
    
@SuppressWarnings({"rawtypes", "unchecked"})
    
public TypeVariable<Method>[] getTypeParameters() {
        
if (getGenericSignature() != null)
            
return (TypeVariable<Method>[])getGenericInfo().getTypeParameters();
        
else
            
return
(TypeVariable<Method>[])new TypeVariable[0];
    
}

    
/**
     
* Returns a {@code Class} object that represents the formal return type
     
* of the method represented by this {@code Method} object.
     
*
     
* @return the return type for the method this object represents
     
*/

    
public Class<?> getReturnType() {
        
return returnType;
    
}

    
/**
     
* Returns a {@code Type} object that represents the formal return
     
* type of the method represented by this {@code Method} object.
     
*
     
* <p>If the return type is a parameterized type,
     
* the {@code Type} object returned must accurately reflect
     
* the actual type parameters used in the source code.
     
*
     
* <p>If the return type is a type variable or a parameterized type, it
     
* is created. Otherwise, it is resolved.
     
*
     
* @return
  
a {@code Type} object that represents the formal return
     
*type of the underlying
  
method
     
* @throws GenericSignatureFormatError
     
*if the generic method signature does not conform to the format
     
*specified in
     
*<cite>The Java&trade; Virtual Machine Specification</cite>
     
* @throws TypeNotPresentException if the underlying method's
     
*return type refers to a non-existent type declaration
     
* @throws MalformedParameterizedTypeException if the
     
*underlying method's return typed refers to a parameterized
     
*type that cannot be instantiated for any reason
     
* @since 1.5
     
*/

    
public Type getGenericReturnType() {
      
if (getGenericSignature() != null) {
        
return getGenericInfo().getReturnType();
      
} else { return getReturnType();}
    
}

    
/**
     
* {@inheritDoc}
     
*/
    
@Override
    
public Class<?>[] getParameterTypes() {
        
return parameterTypes.clone();
    
}

    
/**
     
* {@inheritDoc}
     
* @since 1.8
     
*/
    
public int getParameterCount() { return parameterTypes.length; }


    
/**
     
* {@inheritDoc}
     
* @throws GenericSignatureFormatError {@inheritDoc}
     
* @throws TypeNotPresentException {@inheritDoc}
     
* @throws MalformedParameterizedTypeException {@inheritDoc}
     
* @since 1.5
     
*/

    
@Override
    
public Type[] getGenericParameterTypes() {
        
return super.getGenericParameterTypes();
    
}

    
/**
     
* {@inheritDoc}
     
*/
    
@Override
    
public Class<?>[] getExceptionTypes() {
        
return exceptionTypes.clone();
    
}

    
/**
     
* {@inheritDoc}
     
* @throws GenericSignatureFormatError {@inheritDoc}
     
* @throws TypeNotPresentException {@inheritDoc}
     
* @throws MalformedParameterizedTypeException {@inheritDoc}
     
* @since 1.5
     
*/

    
@Override
    
public Type[] getGenericExceptionTypes() {
        
return super.getGenericExceptionTypes();
    
}

    
/**
     
* Compares this {@code Method} against the specified object.
  
Returns
     
* true if the objects are the same.
  
Two {@code Methods} are the same if
     
* they were declared by the same class and have the same name
     
* and formal parameter types and return type.
     
*/

    
public boolean equals(Object obj) {
        
if (obj != null && obj instanceof Method) {
            
Method other = (Method)obj;
            
if ((getDeclaringClass() == other.getDeclaringClass())
                
&& (getName() == other.getName())) {
                
if (!returnType.equals(other.getReturnType()))
                    
return false;
                
return equalParamTypes(parameterTypes, other.parameterTypes);
            
}
        
}
        
return false;
    
}

    
/**
     
* Returns a hashcode for this {@code Method}.
  
The hashcode is computed
     
* as the exclusive-or of the hashcodes for the underlying
     
* method's declaring class name and the method's name.
     
*/

    
public int hashCode() {
        
return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
    
}

    
/**
     
* Returns a string describing this {@code Method}.
  
The string is
     
* formatted as the method access modifiers, if any, followed by
     
* the method return type, followed by a space, followed by the
     
* class declaring the method, followed by a period, followed by
     
* the method name, followed by a parenthesized, comma-separated
     
* list of the method's formal parameter types. If the method
     
* throws checked exceptions, the parameter list is followed by a
     
* space, followed by the word throws followed by a
     
* comma-separated list of the thrown exception types.
     
* For example:
     
* <pre>
     
*
    
public boolean java.lang.Object.equals(java.lang.Object)
     
* </pre>
     
*
     
* <p>The access modifiers are placed in canonical order as
     
* specified by "The Java Language Specification".
  
This is
     
* {@code public}, {@code protected} or {@code private} first,
     
* and then other modifiers in the following order:
     
* {@code abstract}, {@code default}, {@code static}, {@code final},
     
* {@code synchronized}, {@code native}, {@code strictfp}.
     
*
     
* @return a string describing this {@code Method}
     
*
     
* @jls 8.4.3 Method Modifiers
     
*/

    
public String toString() {
        
return sharedToString(Modifier.methodModifiers(),
                              
isDefault(),
                              
parameterTypes,
                              
exceptionTypes);
    
}

    
@Override
    
void specificToStringHeader(StringBuilder sb) {
        
sb.append(getReturnType().getTypeName()).append(' ');
        
sb.append(getDeclaringClass().getTypeName()).append('.');
        
sb.append(getName());
    
}

    
/**
     
* Returns a string describing this {@code Method}, including
     
* type parameters.
  
The string is formatted as the method access
     
* modifiers, if any, followed by an angle-bracketed
     
* comma-separated list of the method's type parameters, if any,
     
* followed by the method's generic return type, followed by a
     
* space, followed by the class declaring the method, followed by
     
* a period, followed by the method name, followed by a
     
* parenthesized, comma-separated list of the method's generic
     
* formal parameter types.
     
*
     
* If this method was declared to take a variable number of
     
* arguments, instead of denoting the last parameter as
     
* "<tt><i>Type</i>[]</tt>", it is denoted as
     
* "<tt><i>Type</i>...</tt>".
     
*
     
* A space is used to separate access modifiers from one another
     
* and from the type parameters or return type.
  
If there are no
     
* type parameters, the type parameter list is elided; if the type
     
* parameter list is present, a space separates the list from the
     
* class name.
  
If the method is declared to throw exceptions, the
     
* parameter list is followed by a space, followed by the word
     
* throws followed by a comma-separated list of the generic thrown
     
* exception types.
     
*
     
* <p>The access modifiers are placed in canonical order as
     
* specified by "The Java Language Specification".
  
This is
     
* {@code public}, {@code protected} or {@code private} first,
     
* and then other modifiers in the following order:
     
* {@code abstract}, {@code default}, {@code static}, {@code final},
     
* {@code synchronized}, {@code native}, {@code strictfp}.
     
*
     
* @return a string describing this {@code Method},
     
* include type parameters
     
*
     
* @since 1.5
     
*
     
* @jls 8.4.3 Method Modifiers
     
*/

    
@Override
    
public String toGenericString() {
        
return sharedToGenericString(Modifier.methodModifiers(), isDefault());
    
}

    
@Override
    
void specificToGenericStringHeader(StringBuilder sb) {
        
Type genRetType = getGenericReturnType();
        
sb.append(genRetType.getTypeName()).append(' ');
        
sb.append(getDeclaringClass().getTypeName()).append('.');
        
sb.append(getName());
    
}

    
/**
     
* Invokes the underlying method represented by this {@code Method}
     
* object, on the specified object with the specified parameters.
     
* Individual parameters are automatically unwrapped to match
     
* primitive formal parameters, and both primitive and reference
     
* parameters are subject to method invocation conversions as
     
* necessary.
     
*
     
* <p>If the underlying method is static, then the specified {@code obj}
     
* argument is ignored. It may be null.
     
*
     
* <p>If the number of formal parameters required by the underlying method is
     
* 0, the supplied {@code args} array may be of length 0 or null.
     
*
     
* <p>If the underlying method is an instance method, it is invoked
     
* using dynamic method lookup as documented in The Java Language
     
* Specification, Second Edition, section 15.12.4.4; in particular,
     
* overriding based on the runtime type of the target object will occur.
     
*
     
* <p>If the underlying method is static, the class that declared
     
* the method is initialized if it has not already been initialized.
     
*
     
* <p>If the method completes normally, the value it returns is
     
* returned to the caller of invoke; if the value has a primitive
     
* type, it is first appropriately wrapped in an object. However,
     
* if the value has the type of an array of a primitive type, the
     
* elements of the array are <i>not</i> wrapped in objects; in
     
* other words, an array of primitive type is returned.
  
If the
     
* underlying method return type is void, the invocation returns
     
* null.
     
*
     
* @param obj
  
the object the underlying method is invoked from
     
* @param args the arguments used for the method call
     
* @return the result of dispatching the method represented by
     
* this object on {@code obj} with parameters
     
* {@code args}
     
*
     
* @exception IllegalAccessException
    
if this {@code Method} object
     
*
              
is enforcing Java language access control and the underlying
     
*
              
method is inaccessible.
     
* @exception IllegalArgumentException
  
if the method is an
     
*
              
instance method and the specified object argument
     
*
              
is not an instance of the class or interface
     
*
              
declaring the underlying method (or of a subclass
     
*
              
or implementor thereof); if the number of actual
     
*
              
and formal parameters differ; if an unwrapping
     
*
              
conversion for primitive arguments fails; or if,
     
*
              
after possible unwrapping, a parameter value
     
*
              
cannot be converted to the corresponding formal
     
*
              
parameter type by a method invocation conversion.
     
* @exception InvocationTargetException if the underlying method
     
*
              
throws an exception.
     
* @exception NullPointerException
      
if the specified object is null
     
*
              
and the method is an instance method.
     
* @exception ExceptionInInitializerError if the initialization
     
* provoked by this method fails.
     
*/

    
@CallerSensitive
    
public Object invoke(Object obj, Object... args)
        
throws IllegalAccessException, IllegalArgumentException,
           
InvocationTargetException
    
{
        
if (!override) {
            
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                
Class<?> caller = Reflection.getCallerClass();
                
checkAccess(caller, clazz, obj, modifiers);
            
}
        
}
        
MethodAccessor ma = methodAccessor;
             
// read volatile
        
if (ma == null) {
            
ma = acquireMethodAccessor();
        
}
        
return ma.invoke(obj, args);
    
}

    
/**
     
* Returns {@code true} if this method is a bridge
     
* method; returns {@code false} otherwise.
     
*
     
* @return true if and only if this method is a bridge
     
* method as defined by the Java Language Specification.
     
* @since 1.5
     
*/

    
public boolean isBridge() {
        
return (getModifiers() & Modifier.BRIDGE) != 0;
    
}

    
/**
     
* {@inheritDoc}
     
* @since 1.5
     
*/
    
@Override
    
public boolean isVarArgs() {
        
return super.isVarArgs();
    
}

    
/**
     
* {@inheritDoc}
     
* @jls 13.1 The Form of a Binary
     
* @since 1.5
     
*/
    
@Override
    
public boolean isSynthetic() {
        
return super.isSynthetic();
    
}

    
/**
     
* Returns {@code true} if this method is a default
     
* method; returns {@code false} otherwise.
     
*
     
* A default method is a public non-abstract instance method, that
     
* is, a non-static method with a body, declared in an interface
     
* type.
     
*
     
* @return true if and only if this method is a default
     
* method as defined by the Java Language Specification.
     
* @since 1.8
     
*/

    
public boolean isDefault() {
        
// Default methods are public non-abstract instance methods
        
// declared in an interface.
        
return ((getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
                
Modifier.PUBLIC) && getDeclaringClass().isInterface();
    
}

    
// NOTE that there is no synchronization used here. It is correct
    
// (though not efficient) to generate more than one MethodAccessor
    
// for a given Method. However, avoiding synchronization will
    
// probably make the implementation more scalable.
    
private MethodAccessor acquireMethodAccessor() {
        
// First check to see if one has been created yet, and take it
        
// if so
        
MethodAccessor tmp = null;
        
if (root != null) tmp = root.getMethodAccessor();
        
if (tmp != null) {
            
methodAccessor = tmp;
        
} else {
            
// Otherwise fabricate one and propagate it up to the root
            
tmp = reflectionFactory.newMethodAccessor(this);
            
setMethodAccessor(tmp);
        
}

        
return tmp;
    
}

    
// Returns MethodAccessor for this Method object, not looking up
    
// the chain to the root
    
MethodAccessor getMethodAccessor() {
        
return methodAccessor;
    
}

    
// Sets the MethodAccessor for this Method object and
    
// (recursively) its root
    
void setMethodAccessor(MethodAccessor accessor) {
        
methodAccessor = accessor;
        
// Propagate up
        
if (root != null) {
            
root.setMethodAccessor(accessor);
        
}
    
}

    
/**
     
* Returns the default value for the annotation member represented by
     
* this {@code Method} instance.
  
If the member is of a primitive type,
     
* an instance of the corresponding wrapper type is returned. Returns
     
* null if no default is associated with the member, or if the method
     
* instance does not represent a declared member of an annotation type.
     
*
     
* @return the default value for the annotation member represented
     
*by this {@code Method} instance.
     
* @throws TypeNotPresentException if the annotation is of type
     
*{@link Class} and no definition can be found for the
     
*default class value.
     
* @since
  
1.5
     
*/

    
public Object getDefaultValue() {
        
if
  
(annotationDefault == null)
            
return null;
        
Class<?> memberType = AnnotationType.invocationHandlerReturnType(
            
getReturnType());
        
Object result = AnnotationParser.parseMemberValue(
            
memberType, ByteBuffer.wrap(annotationDefault),
            
sun.misc.SharedSecrets.getJavaLangAccess().
                
getConstantPool(getDeclaringClass()),
            
getDeclaringClass());
        
if (result instanceof sun.reflect.annotation.ExceptionProxy)
            
throw new AnnotationFormatError("Invalid default: " + this);
        
return result;
    
}

    
/**
     
* {@inheritDoc}
     
* @throws NullPointerException
  
{@inheritDoc}
     
* @since 1.5
     
*/

    
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
        
return super.getAnnotation(annotationClass);
    
}

    
/**
     
* {@inheritDoc}
     
* @since 1.5
     
*/
    
public Annotation[] getDeclaredAnnotations()
  
{
        
return super.getDeclaredAnnotations();
    
}

    
/**
     
* {@inheritDoc}
     
* @since 1.5
     
*/
    
@Override
    
public Annotation[][] getParameterAnnotations() {
        
return sharedGetParameterAnnotations(parameterTypes, parameterAnnotations);
    
}

    
/**
     
* {@inheritDoc}
     
* @since 1.8
     
*/
    
@Override
    
public AnnotatedType getAnnotatedReturnType() {
        
return getAnnotatedReturnType0(getGenericReturnType());
    
}

    
@Override
    
void handleParameterNumberMismatch(int resultLength, int numParameters) {
        
throw new AnnotationFormatError("Parameter annotations don't match number of parameters");
    
}
}