package com.laytonsmith.PureUtilities.ClassLoading.ClassMirror;
import com.laytonsmith.PureUtilities.Common.StringUtils;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* An {@link AbstractMethodMirror} encompasses both methods and constructors.
*/
public abstract class AbstractMethodMirror extends AbstractElementMirror {
private static final long serialVersionUID = 1L;
private final List<ClassReferenceMirror> params;
private boolean isVararg = false;
private boolean isSynthetic = false;
/**
* TODO: Once we switch to Java 1.8, this should be replaced by java.lang.reflect.Executable.
*/
private Member underlyingMethod = null;
public AbstractMethodMirror(ClassReferenceMirror parentClass, List<AnnotationMirror> annotations, ModifierMirror modifiers,
ClassReferenceMirror type, String name, List<ClassReferenceMirror> params, boolean isVararg, boolean isSynthetic){
super(parentClass, annotations, modifiers, type, name);
Objects.requireNonNull(params, "params cannot be null");
this.params = params;
this.isVararg = isVararg;
this.isSynthetic = isSynthetic;
}
public AbstractMethodMirror(Member method){
super(method);
this.underlyingMethod = method;
this.params = null;
}
/* package */ AbstractMethodMirror(ClassReferenceMirror parentClass, ModifierMirror modifiers, ClassReferenceMirror type,
String name, List<ClassReferenceMirror> params, boolean isVararg, boolean isSynthetic){
super(parentClass, null, modifiers, type, name);
annotations = new ArrayList<>();
Objects.requireNonNull(params, "params cannot be null");
this.params = params;
this.isVararg = isVararg;
this.isSynthetic = isSynthetic;
}
/**
* Returns a list of params in this method.
* @return
*/
public List<ClassReferenceMirror> getParams(){
if(underlyingMethod != null){
List<ClassReferenceMirror> list = new ArrayList<>();
for(Class p : ((Method)underlyingMethod).getParameterTypes()){
list.add(ClassReferenceMirror.fromClass(p));
}
return list;
}
return new ArrayList<>(params);
}
/**
* Returns true if this method is vararg.
* @return
*/
public boolean isVararg(){
if(underlyingMethod != null){
return ((Method)underlyingMethod).isVarArgs();
}
return isVararg;
}
/**
* Returns true if this method is synthetic.
* @return
*/
public boolean isSynthetic(){
if(underlyingMethod != null){
return underlyingMethod.isSynthetic();
}
return isSynthetic;
}
@Override
public String toString() {
if(underlyingMethod != null){
return underlyingMethod.toString();
}
List<String> sParams = new ArrayList<>();
for(int i = 0; i < params.size(); i++){
if(i == params.size() - 1 && isVararg){
sParams.add(params.get(i).getComponentType().toString() + "...");
} else {
sParams.add(params.get(i).toString());
}
}
return StringUtils.Join(annotations, "\n") + (annotations.isEmpty()?"":"\n") + (modifiers.toString()
+ " " + type).trim() + " " + name + "(" + StringUtils.Join(sParams, ", ") + "){}";
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof MethodMirror)){
return false;
}
if(!super.equals(obj)){
return false;
}
AbstractMethodMirror m = (AbstractMethodMirror)obj;
return
Objects.equals(this.params, m.params)
&& this.isVararg == m.isVararg
&& this.isSynthetic == m.isSynthetic;
}
@Override
public int hashCode() {
int hash = 5;
hash = 31 * hash + super.hashCode();
hash = 31 * hash + Objects.hashCode(this.params);
hash = 31 * hash + (this.isVararg ? 1 : 0);
hash = 31 * hash + (this.isSynthetic ? 1 : 0);
return hash;
}
/**
* Returns the underlying executable (or null, if it was constructed artificially).
* @return
*/
protected Member getExecutable(){
return (Member)underlyingMethod;
}
/**
* Loads the class that contains this method, using the default class loader.
* @return
* @throws java.lang.ClassNotFoundException
*/
public Class loadParentClass() throws ClassNotFoundException{
return loadParentClass(AbstractMethodMirror.class.getClassLoader(), true);
}
/**
* Loads the class that contains this method, using the default class loader.
* @param loader
* @param initialize
* @return
* @throws java.lang.ClassNotFoundException
*/
public Class loadParentClass(ClassLoader loader, boolean initialize) throws ClassNotFoundException{
ClassReferenceMirror p = getDeclaringClass();
Objects.requireNonNull(p, "Declaring class is null!");
return p.loadClass(loader, initialize);
}
}