package org.andork.japa;
import japa.parser.ast.CompilationUnit;
import japa.parser.ast.Node;
import japa.parser.ast.body.AnnotationDeclaration;
import japa.parser.ast.body.AnnotationMemberDeclaration;
import japa.parser.ast.body.BodyDeclaration;
import japa.parser.ast.body.ClassOrInterfaceDeclaration;
import japa.parser.ast.body.ConstructorDeclaration;
import japa.parser.ast.body.EnumConstantDeclaration;
import japa.parser.ast.body.EnumDeclaration;
import japa.parser.ast.body.FieldDeclaration;
import japa.parser.ast.body.MethodDeclaration;
import japa.parser.ast.body.Parameter;
import japa.parser.ast.body.TypeDeclaration;
import japa.parser.ast.body.VariableDeclarator;
import japa.parser.ast.expr.AnnotationExpr;
import japa.parser.ast.expr.NameExpr;
import japa.parser.ast.expr.QualifiedNameExpr;
import japa.parser.ast.type.ClassOrInterfaceType;
import japa.parser.ast.type.PrimitiveType;
import japa.parser.ast.type.ReferenceType;
import japa.parser.ast.type.Type;
import japa.parser.ast.type.VoidType;
import japa.parser.ast.type.WildcardType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.andork.util.StringUtils;
public class JavaParserUtils {
private static final Pattern parameterPattern = Pattern.compile("([a-zA-Z_][a-zA-Z_0-9]*(\\.[a-zA-Z_][a-zA-Z_0-9]*)*)(\\[\\])*");
private static final Pattern parameterListPattern = Pattern.compile("\\s*\\(\\s*(" + parameterPattern + "(\\s*,\\s*" + parameterPattern + ")*\\s*)?\\)\\s*");
public static String getQualifiedName(Field field) {
StringBuffer sb = new StringBuffer();
sb.append(field.getDeclaringClass().getName()).append('.').append(field.getName());
return sb.toString();
}
public static String getQualifiedName(Constructor<?> constructor) {
StringBuffer sb = new StringBuffer();
sb.append(constructor.getDeclaringClass().getName()).append('.').append(constructor.getName()).append('(');
Class<?>[] parameters = constructor.getParameterTypes();
for (int i = 0; i < parameters.length; i++) {
if (i > 0) {
sb.append(",");
}
sb.append(formatParameterType(parameters[i]));
}
return sb.append(')').toString();
}
public static String getQualifiedName(Method method) {
StringBuffer sb = new StringBuffer();
sb.append(method.getDeclaringClass().getName()).append('.').append(method.getName()).append('(');
Class<?>[] parameters = method.getParameterTypes();
for (int i = 0; i < parameters.length; i++) {
if (i > 0) {
sb.append(",");
}
sb.append(formatParameterType(parameters[i]));
}
return sb.append(')').toString();
}
public static Node getNode(CompilationUnit unit, String fqName) {
String pkg = getQualifiedName(unit.getPackage().getName());
if (!fqName.startsWith(pkg)) {
return null;
}
if (fqName.equals(pkg)) {
return unit.getPackage();
}
String name = fqName.substring(pkg.length() + 1);
for (TypeDeclaration typeDecl : unit.getTypes()) {
if (name.startsWith(typeDecl.getName())) {
if (name.length() == typeDecl.getName().length()) {
return typeDecl;
} else {
return getNode(typeDecl, name.substring(typeDecl.getName().length() + 1));
}
}
}
return null;
}
public static TypeDeclaration getDeclaration(CompilationUnit unit, Class<?> cls) {
if (cls.getDeclaringClass() != null) {
Node node = getDeclaration(unit, cls.getDeclaringClass());
if (node instanceof TypeDeclaration) {
for (BodyDeclaration decl : ((TypeDeclaration) node).getMembers()) {
if (decl instanceof TypeDeclaration) {
TypeDeclaration typeDecl = (TypeDeclaration) decl;
if (typeDecl.getName().equals(cls.getSimpleName())) {
return typeDecl;
}
}
}
}
} else {
for (TypeDeclaration typeDecl : unit.getTypes()) {
if (cls.getName().equals(getQualifiedName(unit.getPackage().getName()) + "." + typeDecl.getName())) {
return typeDecl;
}
}
}
return null;
}
public static FieldDeclaration getDeclaration(CompilationUnit unit, Field field) {
TypeDeclaration typeDecl = getDeclaration(unit, field.getDeclaringClass());
if (typeDecl == null) {
return null;
}
for (BodyDeclaration decl : typeDecl.getMembers()) {
if (decl instanceof FieldDeclaration) {
FieldDeclaration fieldDecl = (FieldDeclaration) decl;
List<VariableDeclarator> variables = fieldDecl.getVariables();
if (variables.size() != 1) {
continue;
}
if (field.getName().equals(variables.get(0).getId().getName())) {
return fieldDecl;
}
}
}
return null;
}
public static ConstructorDeclaration getDeclaration(CompilationUnit unit, Constructor<?> constructor) {
TypeDeclaration typeDecl = getDeclaration(unit, constructor.getDeclaringClass());
if (typeDecl == null) {
return null;
}
for (BodyDeclaration decl : typeDecl.getMembers()) {
if (decl instanceof ConstructorDeclaration) {
ConstructorDeclaration constructorDecl = (ConstructorDeclaration) decl;
if (constructorDeclMatches(constructorDecl, constructor)) {
return constructorDecl;
}
}
}
return null;
}
public static MethodDeclaration getDeclaration(CompilationUnit unit, Method method) {
TypeDeclaration typeDecl = getDeclaration(unit, method.getDeclaringClass());
if (typeDecl == null) {
return null;
}
for (BodyDeclaration decl : typeDecl.getMembers()) {
if (decl instanceof MethodDeclaration) {
MethodDeclaration methodDecl = (MethodDeclaration) decl;
if (methodDeclMatches(methodDecl, method)) {
return methodDecl;
}
}
}
return null;
}
public static AnnotationExpr getAnnotation(BodyDeclaration decl, Class<?> annotationClass) {
for (AnnotationExpr annotation : decl.getAnnotations()) {
if (annotation.getName().equals(annotationClass.getSimpleName()) ||
annotation.getName().equals(annotationClass.getName())) {
return annotation;
}
}
return null;
}
public static Object formatParameterType(Class<?> cls) {
return formatParameterType(cls, true);
}
public static Object formatParameterType(Class<?> cls, boolean fullyQualified) {
if (cls.isArray()) {
return formatParameterType(cls.getComponentType(), fullyQualified) + "[]";
}
if (fullyQualified) {
return cls.getName().replace('$', '.');
}
return cls.getSimpleName();
}
private static String getQualifiedName(NameExpr name) {
if (name instanceof QualifiedNameExpr) {
return getQualifiedName(((QualifiedNameExpr) name).getQualifier()) + '.' + name.getName();
}
return name.getName();
}
public static Node getNode(TypeDeclaration typeDecl, String name) {
if (typeDecl.getMembers() == null) {
return null;
}
for (BodyDeclaration bodyDecl : typeDecl.getMembers()) {
String bodyDeclName = getName(bodyDecl);
if (bodyDeclName != null && name.startsWith(bodyDeclName)) {
if (name.length() == bodyDeclName.length()) {
return bodyDecl;
}
else if (bodyDecl instanceof MethodDeclaration || bodyDecl instanceof ConstructorDeclaration) {
if (signatureMatches(bodyDecl, name.substring(bodyDeclName.length()))) {
return bodyDecl;
}
}
else if (bodyDecl instanceof TypeDeclaration) {
return getNode((TypeDeclaration) bodyDecl, name.substring(bodyDeclName.length() + 1));
}
}
}
return null;
}
private static boolean signatureMatches(BodyDeclaration decl, String signature) {
if (!parameterListPattern.matcher(signature).matches()) {
return false;
}
Matcher m = parameterPattern.matcher(signature);
List<Parameter> parameters = null;
if (decl instanceof ConstructorDeclaration) {
parameters = ((ConstructorDeclaration) decl).getParameters();
} else if (decl instanceof MethodDeclaration) {
parameters = ((MethodDeclaration) decl).getParameters();
} else {
throw new IllegalArgumentException("decl must be a ConstructorDeclaration or a MethodDeclaration");
}
if (parameters == null)
{
parameters = Collections.emptyList();
}
int i = 0;
while (m.find()) {
if (i >= parameters.size()) {
return false;
}
Parameter parameter = parameters.get(i);
String typeName = getRawTypeName(parameter.getType());
if (!m.group().endsWith(typeName)) {
return false;
}
i++;
}
return i == parameters.size();
}
private static String getRawTypeName(Type type) {
if (type instanceof ClassOrInterfaceType) {
return getQualifiedName((ClassOrInterfaceType) type);
}
if (type instanceof ReferenceType) {
ReferenceType refType = (ReferenceType) type;
return getRawTypeName(refType.getType()) + StringUtils.multiply("[]", refType.getArrayCount());
}
if (type instanceof PrimitiveType) {
return ((PrimitiveType) type).getType().name().toLowerCase();
}
if (type instanceof VoidType) {
return "void";
}
if (type instanceof WildcardType) {
return "java.lang.Object";
}
return type.toString();
}
private static String getQualifiedName(ClassOrInterfaceType type) {
if (type.getScope() != null) {
return getQualifiedName(type.getScope()) + "." + type.getName();
}
return type.getName();
}
private static String getName(BodyDeclaration decl) {
if (decl instanceof AnnotationMemberDeclaration) {
return ((AnnotationMemberDeclaration) decl).getName();
}
if (decl instanceof ConstructorDeclaration) {
return ((ConstructorDeclaration) decl).getName();
}
if (decl instanceof EnumConstantDeclaration) {
return ((EnumConstantDeclaration) decl).getName();
}
if (decl instanceof FieldDeclaration) {
List<VariableDeclarator> variables = ((FieldDeclaration) decl).getVariables();
if (variables.size() == 1) {
return variables.get(0).getId().getName();
} else {
return null;
}
}
if (decl instanceof MethodDeclaration) {
return ((MethodDeclaration) decl).getName();
}
if (decl instanceof AnnotationDeclaration) {
return ((AnnotationDeclaration) decl).getName();
}
if (decl instanceof ClassOrInterfaceDeclaration) {
return ((ClassOrInterfaceDeclaration) decl).getName();
}
if (decl instanceof EnumDeclaration) {
return ((EnumDeclaration) decl).getName();
}
return null;
}
private static boolean methodDeclMatches(MethodDeclaration methodDecl, Method method) {
if (!method.getName().equals(methodDecl.getName())) {
return false;
}
if (!typeMatches(getRawTypeName(methodDecl.getType()), method.getReturnType())) {
return false;
}
List<Parameter> declParams = methodDecl.getParameters();
Class<?>[] methodParams = method.getParameterTypes();
if (declParams.size() != methodParams.length) {
return false;
}
for (int i = 0; i < declParams.size(); i++) {
if (!typeMatches(getRawTypeName(declParams.get(i).getType()), methodParams[i])) {
return false;
}
}
return true;
}
private static boolean constructorDeclMatches(ConstructorDeclaration constructorDecl, Constructor<?> constructor) {
if (!constructor.getName().equals(constructorDecl.getName())) {
return false;
}
List<Parameter> declParams = constructorDecl.getParameters();
Class<?>[] constructorParams = constructor.getParameterTypes();
if (declParams.size() != constructorParams.length) {
return false;
}
for (int i = 0; i < declParams.size(); i++) {
if (!typeMatches(getRawTypeName(declParams.get(i).getType()), constructorParams[i])) {
return false;
}
}
return true;
}
private static boolean typeMatches(String rawTypeName, Class<?> returnType) {
return rawTypeName.equals(formatParameterType(returnType, true)) || rawTypeName.equals(formatParameterType(returnType, false));
}
}