
org.walkmod.override.visitors.OverrideVisitor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of walkmod-override-plugin Show documentation
Show all versions of walkmod-override-plugin Show documentation
Visitor to apply the override Java annotations on methods whenever it is necessary.
/*
Copyright (C) 2015 Raquel Pau
Walkmod is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Walkmod is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Walkmod. If not, see .*/
package org.walkmod.override.visitors;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.walkmod.javalang.ast.MethodSymbolData;
import org.walkmod.javalang.ast.SymbolData;
import org.walkmod.javalang.ast.body.MethodDeclaration;
import org.walkmod.javalang.ast.body.ModifierSet;
import org.walkmod.javalang.ast.body.Parameter;
import org.walkmod.javalang.ast.expr.AnnotationExpr;
import org.walkmod.javalang.ast.expr.MarkerAnnotationExpr;
import org.walkmod.javalang.ast.expr.NameExpr;
import org.walkmod.javalang.compiler.reflection.ClassInspector;
import org.walkmod.javalang.compiler.reflection.MethodInspector;
import org.walkmod.javalang.compiler.symbols.RequiresSemanticAnalysis;
import org.walkmod.javalang.visitors.VoidVisitorAdapter;
import org.walkmod.walkers.VisitorContext;
@RequiresSemanticAnalysis
public class OverrideVisitor extends VoidVisitorAdapter {
private boolean containsOverrideAsAnnotationExpr(MethodDeclaration md) {
List mAnnotations = md.getAnnotations();
boolean containsOverride = false;
if (mAnnotations != null) {
// To avoid a JDK8 bug
// (http://stackoverflow.com/questions/26515016/annotations-on-an-overridden-method-are-ignored-in-java-8-propertydescriptor)
Iterator it = mAnnotations.iterator();
while (it.hasNext() && !containsOverride) {
AnnotationExpr ae = it.next();
SymbolData sd = ae.getSymbolData();
if (sd != null) {
Class> clazz = sd.getClazz();
containsOverride = clazz.equals(Override.class);
}
}
}
return containsOverride;
}
private boolean containsOverrideInByteCode(MethodDeclaration md) {
boolean isAnnotationPresent = true;
MethodSymbolData sdata = md.getSymbolData();
Method method = sdata.getMethod();
try {
isAnnotationPresent = method.isAnnotationPresent(Override.class);
} catch (Throwable t) {
//maybe there are private classes that cannot be accessed by reflection
//http://stackoverflow.com/questions/8512207/jetty-guice-illegalaccesserror
}
return isAnnotationPresent;
}
private boolean containsAnEquivalentParentMethod(MethodDeclaration md) {
MethodSymbolData sdata = md.getSymbolData();
boolean result = false;
if (sdata != null) {
Method method = sdata.getMethod();
if (!containsOverrideAsAnnotationExpr(md) && !containsOverrideInByteCode(md)) {
Class> declaringClass = method.getDeclaringClass();
Class> parentClass = declaringClass.getSuperclass();
if (parentClass != null) {
// it should be initialized after resolving the method
List params = md.getParameters();
SymbolData[] args = null;
if (params != null) {
args = new SymbolData[params.size()];
int i = 0;
for (Parameter param : params) {
args[i] = param.getType().getSymbolData();
i++;
}
} else {
args = new SymbolData[0];
}
List> scopesToCheck = new LinkedList>();
scopesToCheck.add(parentClass);
Class>[] interfaces = declaringClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
scopesToCheck.add(interfaces[i]);
}
Iterator> it = scopesToCheck.iterator();
Method foundMethod = null;
while (it.hasNext() && foundMethod == null) {
Class> currentClass = it.next();
foundMethod = MethodInspector.findMethod(currentClass, args, md.getName());
if (foundMethod != null) {
Type[] parameterTypes = foundMethod.getGenericParameterTypes();
int modifiers = foundMethod.getModifiers();
boolean valid = ModifierSet.isPublic(modifiers) || ModifierSet.isProtected(modifiers);
for (int i = 0; i < parameterTypes.length && valid; i++) {
if (parameterTypes[i] instanceof Class) {
valid = (args[i].getClazz().getName().equals(((Class) parameterTypes[i]).getName()));
}
}
if (!valid) {
foundMethod = null;
}
}
}
result = foundMethod != null;
}
}
}
return result;
}
@Override
public void visit(MethodDeclaration md, VisitorContext arg) {
if (!ModifierSet.isStatic(md.getModifiers()) && !ModifierSet.isPrivate(md.getModifiers())) {
if (containsAnEquivalentParentMethod(md)) {
List annotations = md.getAnnotations();
if (annotations == null) {
annotations = new LinkedList();
md.setAnnotations(annotations);
}
annotations.add(new MarkerAnnotationExpr(new NameExpr("Override")));
}
}
super.visit(md, arg);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy