package com.laytonsmith.PureUtilities.ClassLoading.ClassMirror;
import com.laytonsmith.PureUtilities.Common.StringUtils;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* This class gathers information about a method, without actually loading
* the containing class into memory. Most of the methods in {@link java.lang.reflect.Method} are
* available in this class (or have an equivalent Mirror version).
*/
public class MethodMirror extends AbstractElementMirror {
private static final long serialVersionUID = 1L;
private final List<ClassReferenceMirror> params;
private boolean isVararg = false;
private boolean isSynthetic = false;
private Method underlyingMethod = null;
public MethodMirror(ClassReferenceMirror parentClass, List<AnnotationMirror> annotations, ModifierMirror modifiers,
ClassReferenceMirror type, String name, List<ClassReferenceMirror> params, boolean isVararg, boolean isSynthetic){
super(parentClass, annotations, modifiers, type, name);
this.params = params;
this.isVararg = isVararg;
this.isSynthetic = isSynthetic;
}
public MethodMirror(Method method){
super(method);
this.underlyingMethod = method;
this.params = null;
}
/* package */ MethodMirror(ClassReferenceMirror parentClass, ModifierMirror modifiers, ClassReferenceMirror type,
String name, List<ClassReferenceMirror> params, boolean isVararg, boolean isSynthetic){
super(parentClass, null, modifiers, type, name);
annotations = new ArrayList<>();
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 : 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 underlyingMethod.isVarArgs();
}
return isVararg;
}
/**
* Returns true if this method is synthetic.
* @return
*/
public boolean isSynthetic(){
if(underlyingMethod != null){
return underlyingMethod.isSynthetic();
}
return isSynthetic;
}
/**
* This loads the parent class, and returns the {@link Method} object.
* This also loads all parameter type's classes as well.
* <p>
* If this class was created with an actual Method, then that is simply returned.
* @return
* @throws java.lang.ClassNotFoundException
*/
public Method loadMethod() throws ClassNotFoundException{
if(underlyingMethod != null){
return underlyingMethod;
}
return loadMethod(MethodMirror.class.getClassLoader(), true);
}
/**
* This loads the parent class, and returns the {@link Method} object.
* This also loads all parameter type's classes as well.
* <p>
* If this class was created with an actual Method, then that is simply returned.
* @param loader
* @param initialize
* @return
* @throws ClassNotFoundException
*/
public Method loadMethod(ClassLoader loader, boolean initialize) throws ClassNotFoundException{
if(underlyingMethod != null){
return underlyingMethod;
}
ClassReferenceMirror p = getDeclaringClass();
Objects.requireNonNull(p, "Declaring class is null!");
Class parent = p.loadClass(loader, initialize);
List<Class> cParams = new ArrayList<>();
for(ClassReferenceMirror c : params){
cParams.add(c.loadClass(loader, initialize));
}
try {
return parent.getMethod(name, cParams.toArray(new Class[cParams.size()]));
} catch (Exception ex) {
//There's really no way for any exception to happen here, so just rethrow
throw new RuntimeException(ex);
}
}
@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, ", ") + "){}";
}
}