/*
* Copyright 2013. Guidewire Software, Inc.
*/
package gw.lang.reflect.java.asm;
import gw.internal.ext.org.objectweb.asm.Type;
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
*/
public class AsmMethod implements IGeneric {
private AsmType _methodType;
private int _modifiers;
private AsmType _returnType;
private AsmType _genericReturnType;
private List<AsmType> _parameters;
private List<AsmType> _genericParameters;
private List<AsmType> _exceptions;
private List<AsmType> _genericExceptions;
private List<AsmAnnotation> _annotations;
private List<AsmAnnotation>[] _paramAnnotations;
private AsmClass _owner;
private boolean _bGeneric;
private Object _defaultAnnoValue;
public AsmMethod( AsmClass owner, int access, String name, String desc, String[] exceptions ) {
_owner = owner;
_modifiers = access;
_methodType = new AsmType( name );
_annotations = Collections.emptyList();
_exceptions = Collections.emptyList();
_parameters = Collections.emptyList();
_genericExceptions = Collections.emptyList();
_genericParameters = Collections.emptyList();
assignTypeFromDesc( desc );
//noinspection unchecked
_paramAnnotations = new List[_parameters.size()];
assignExceptions( exceptions );
}
public String getName() {
return _methodType.getName();
}
public AsmType getMethodType() {
return _methodType;
}
public int getModifiers() {
return _modifiers;
}
public List<AsmType> getParameters() {
return _parameters;
}
public List<AsmType> getGenericParameters() {
return _genericParameters.isEmpty() ? _parameters : _genericParameters;
}
void initGenericParameters() {
int iOffset = 0;
if( isConstructor() ) {
if( _owner.isEnum() ) {
iOffset = 2;
}
else if( _owner.getEnclosingType() != null && !Modifier.isStatic( _owner.getModifiers() ) ) {
iOffset = 1;
}
}
int iParamCount = _parameters.size() - iOffset;
if( iParamCount < 0 ) {
throw new IllegalStateException();
}
_genericParameters = new ArrayList<AsmType>( iParamCount );
for( int i = iOffset; i < _parameters.size(); i++ ) {
_genericParameters.add( _parameters.get( i ).copyNoArrayOrParameters() );
}
}
public AsmType getReturnType() {
return _returnType;
}
void setReturnType( AsmType returnType ) {
_returnType = returnType;
}
public AsmType getGenericReturnType() {
return _genericReturnType == null ? _returnType : _genericReturnType;
}
void initGenericReturnType() {
_genericReturnType = _returnType.copyNoArrayOrParameters();
}
public AsmClass getDeclaringClass() {
return _owner;
}
public boolean isGeneric() {
return _bGeneric;
}
public void setGeneric() {
_bGeneric = true;
}
public boolean isSynthetic() {
return (_modifiers & 0x00001000) != 0;
}
public boolean isBridge() {
return (_modifiers & 0x00000040) != 0;
}
public boolean isConstructor() {
return getName().equals( "<init>" );
}
public List<AsmType> getExceptions() {
return _exceptions;
}
public List<AsmType> getGenericExceptions() {
return _genericExceptions.isEmpty() ? _exceptions : _genericExceptions;
}
void initGenericExceptions() {
_genericExceptions = new ArrayList<AsmType>( _exceptions.size() );
for( AsmType exception : _exceptions ) {
_genericExceptions.add( exception.copyNoArrayOrParameters() );
}
}
public List<AsmAnnotation> getAnnotations() {
return _annotations;
}
public List<AsmAnnotation>[] getParameterAnnotations() {
return _paramAnnotations;
}
public Object getAnnotationDefaultValue() {
return _defaultAnnoValue;
}
public void setAnnotationDefaultValue( Object value ) {
value = AsmAnnotation.makeAppropriateValue( value );
_defaultAnnoValue = value;
}
public boolean isAnnotationPresent( Class<? extends Annotation> annotationClass ) {
return getAnnotation( annotationClass ) != null;
}
public AsmAnnotation getAnnotation( Class annotationClass ) {
for( AsmAnnotation anno: getAnnotations() ) {
if( annotationClass.getName().equals( anno.getType().getName() ) ) {
return anno;
}
}
return null;
}
private void assignExceptions( String[] exceptions ) {
if( exceptions == null ) {
return;
}
for( String exception : exceptions ) {
if( _exceptions.isEmpty() ) {
_exceptions = new ArrayList<AsmType>( exceptions.length );
}
_exceptions.add( AsmUtil.makeType( exception ) );
}
}
private void assignTypeFromDesc( String desc ) {
Type returnType = Type.getReturnType( desc );
_returnType = AsmUtil.makeType( returnType );
Type[] params = Type.getArgumentTypes( desc );
for( Type param : params ) {
if( _parameters.isEmpty() ) {
_parameters = new ArrayList<AsmType>( params.length );
}
_parameters.add( AsmUtil.makeType( param ) );
}
}
public void addAnnotation( AsmAnnotation asmAnnotation ) {
if( _annotations.isEmpty() ) {
_annotations = new ArrayList<AsmAnnotation>( 2 );
}
_annotations.add( asmAnnotation );
}
public void addParameterAnnotation( int iParam, AsmAnnotation asmAnnotation ) {
if( _paramAnnotations[iParam] == null ) {
_paramAnnotations[iParam] = new ArrayList<AsmAnnotation>( 2 );
}
_paramAnnotations[iParam].add( asmAnnotation );
}
public String toString() {
int mod = getModifiers();
return ((mod == 0) ? "" : (Modifier.toString( mod ) + " "))
+ makeTypeVarsString()
+ (getGenericReturnType() == null ? getReturnType().getFqn() : getGenericReturnType().getFqn()) + " "
+ getName()
+ makeParameterString();
}
private String makeParameterString() {
String paramString = "(";
for( AsmType param : _genericParameters.isEmpty() ? _parameters : _genericParameters ) {
if( paramString.length() > 1 ) {
paramString += ", ";
}
paramString += param.getFqn();
}
paramString += ")";
return paramString;
}
private String makeTypeVarsString() {
String tvString = "";
if( isGeneric() ) {
tvString = "<";
for( AsmType tv : getMethodType().getTypeParameters() ) {
if( tvString.length() > 1 ) {
tvString += ", ";
}
tvString += tv.getFqn();
}
tvString += ">";
}
return tvString;
}
@Override
public boolean equals( Object o ) {
if( this == o ) {
return true;
}
if( o == null || getClass() != o.getClass() ) {
return false;
}
AsmMethod asmMethod = (AsmMethod)o;
if( _bGeneric != asmMethod._bGeneric ) {
return false;
}
if( _modifiers != asmMethod._modifiers ) {
return false;
}
if( !_annotations.equals( asmMethod._annotations ) ) {
return false;
}
if( _defaultAnnoValue != null ? !_defaultAnnoValue.equals( asmMethod._defaultAnnoValue ) : asmMethod._defaultAnnoValue != null ) {
return false;
}
if( !_exceptions.equals( asmMethod._exceptions ) ) {
return false;
}
if( !_genericExceptions.equals( asmMethod._genericExceptions ) ) {
return false;
}
if( !_genericParameters.equals( asmMethod._genericParameters ) ) {
return false;
}
if( !_genericReturnType.equals( asmMethod._genericReturnType ) ) {
return false;
}
if( !_methodType.equals( asmMethod._methodType ) ) {
return false;
}
if( !_owner.equals( asmMethod._owner ) ) {
return false;
}
if( !Arrays.equals( _paramAnnotations, asmMethod._paramAnnotations ) ) {
return false;
}
if( !_parameters.equals( asmMethod._parameters ) ) {
return false;
}
if( !_returnType.equals( asmMethod._returnType ) ) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = _methodType.hashCode();
result = 31 * result + _modifiers;
result = 31 * result + _returnType.hashCode();
result = 31 * result + _genericReturnType.hashCode();
result = 31 * result + _parameters.hashCode();
result = 31 * result + _genericParameters.hashCode();
result = 31 * result + _exceptions.hashCode();
result = 31 * result + _genericExceptions.hashCode();
result = 31 * result + _annotations.hashCode();
result = 31 * result + Arrays.hashCode( _paramAnnotations );
result = 31 * result + _owner.hashCode();
result = 31 * result + (_bGeneric ? 1 : 0);
result = 31 * result + (_defaultAnnoValue != null ? _defaultAnnoValue.hashCode() : 0);
return result;
}
}