package com.googlecode.gwt.test.gxt3.internal.handlers;
import japa.parser.JavaParser;
import japa.parser.ParseException;
import japa.parser.ast.CompilationUnit;
import japa.parser.ast.PackageDeclaration;
import japa.parser.ast.body.ClassOrInterfaceDeclaration;
import japa.parser.ast.body.MethodDeclaration;
import japa.parser.ast.body.Parameter;
import japa.parser.ast.visitor.GenericVisitorAdapter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.thoughtworks.paranamer.ParameterNamesNotFoundException;
import com.thoughtworks.paranamer.Paranamer;
public class JavaFileParanamer implements Paranamer {
private static class MethodParametersVisitor extends
GenericVisitorAdapter<Void, Map<Method, String[]>> {
private final StringBuilder currentClassName = new StringBuilder();
private String packageName;
@Override
public Void visit(ClassOrInterfaceDeclaration n,
java.util.Map<Method, String[]> arg) {
currentClassName.append("$").append(n.getName());
super.visit(n, arg);
currentClassName.delete(currentClassName.length() - n.getName().length()
- 1, currentClassName.length());
return null;
}
@Override
public Void visit(MethodDeclaration n, Map<Method, String[]> arg) {
Method m = findMethod(n);
int length = (n.getParameters() == null) ? 0 : n.getParameters().size();
String[] params = new String[length];
for (int i = 0; i < params.length; i++) {
params[i] = n.getParameters().get(i).getId().getName();
}
arg.put(m, params);
return super.visit(n, arg);
}
@Override
public Void visit(PackageDeclaration n, Map<Method, String[]> arg) {
packageName = n.getName().toString();
return super.visit(n, arg);
}
private boolean argsMatch(Class<?>[] parameterTypes,
List<Parameter> parameters) {
if (parameters == null) {
return parameterTypes.length == 0;
}
for (int i = 0; i < parameterTypes.length; i++) {
Class<?> paramType = parameterTypes[i];
Parameter param = parameters.get(i);
if (!paramType.getSimpleName().equals(param.getType().toString())) {
return false;
}
}
return true;
}
private Method findMethod(MethodDeclaration n) {
Class<?> currentVisitedClass = getCurrentVisitedClass();
for (Method method : currentVisitedClass.getMethods()) {
if (!method.getName().equals(n.getName())) {
continue;
} else if (argsMatch(method.getParameterTypes(), n.getParameters())) {
return method;
}
}
return null;
}
private Class<?> getCurrentVisitedClass() {
String className = packageName + "." + currentClassName.substring(1);
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new ParameterNamesNotFoundException(
"Error while trying to retrieve class " + className + " :", e);
}
};
}
private static JavaFileParanamer instance;
public static JavaFileParanamer get() {
if (instance == null) {
instance = new JavaFileParanamer();
}
return instance;
}
private final Map<Method, String[]> cache;
private JavaFileParanamer() {
this.cache = new HashMap<Method, String[]>();
}
/*
* (non-Javadoc)
*
* @see
* com.thoughtworks.paranamer.Paranamer#lookupParameterNames(java.lang.reflect
* .AccessibleObject)
*/
public String[] lookupParameterNames(AccessibleObject methodOrConstructor) {
return lookupParameterNames(methodOrConstructor, true);
}
/*
* (non-Javadoc)
*
* @see
* com.thoughtworks.paranamer.Paranamer#lookupParameterNames(java.lang.reflect
* .AccessibleObject, boolean)
*/
public String[] lookupParameterNames(AccessibleObject methodOrConstructor,
boolean throwExceptionIfMissing) {
if (methodOrConstructor == null) {
throw new NullPointerException(
"method or constructor to inspect cannot be null");
}
String[] result = cache.get(methodOrConstructor);
if (result == null) {
if (methodOrConstructor instanceof Method) {
Class<?> declaringClass = ((Method) methodOrConstructor).getDeclaringClass();
try {
visitJavaFile(declaringClass);
} catch (Exception e) {
throw new ParameterNamesNotFoundException(
"Error while trying to read parameter names from the Java file which contains the declaration of "
+ declaringClass.getName(), e);
}
result = cache.get(methodOrConstructor);
if (result == null && throwExceptionIfMissing) {
throw new ParameterNamesNotFoundException(
"Cannot retrieve parameter names for method "
+ methodOrConstructor.toString());
}
} else {
throw new UnsupportedOperationException("Not managed type : "
+ methodOrConstructor.getClass().getSimpleName());
}
}
return result;
}
private InputStream getJavaFile(Class<?> declaringClass) {
if (declaringClass.isMemberClass() || declaringClass.isLocalClass()) {
declaringClass = declaringClass.getDeclaringClass();
}
String javaPath = declaringClass.getCanonicalName().replaceAll("\\.", "/")
+ ".java";
return declaringClass.getClassLoader().getResourceAsStream(javaPath);
}
private void visitJavaFile(Class<?> declaringClass) throws ParseException,
IOException {
InputStream is = getJavaFile(declaringClass);
if (is == null) {
return;
}
CompilationUnit cu;
try {
// parse the file
cu = JavaParser.parse(is);
} finally {
is.close();
}
MethodParametersVisitor visitor = new MethodParametersVisitor();
cu.accept(visitor, cache);
}
}