Skip to content

Commit

Permalink
Fixes wisdom-framework#564 by allowing elements from inner classes to…
Browse files Browse the repository at this point in the history
… be referenced in annotation.

The following are supported :
 - direct field access
 - access to field declared in an inner class or interface
The following are not supported
 - access to field declared in another class, even if in the same package
 - access to a class defined from an expression (which can't happen, but is nevertheless considered as valid by javaparser)
  • Loading branch information
Riduidel committed Nov 16, 2016
1 parent 8dbb55b commit b7a36db
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,19 @@
import java.util.List;
import java.util.Set;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.BodyDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.TypeDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.comments.JavadocComment;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.FieldAccessExpr;
import com.github.javaparser.ast.expr.MemberValuePair;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.expr.StringLiteralExpr;
import com.github.javaparser.ast.visitor.GenericVisitorAdapter;

/**
Expand All @@ -37,7 +47,89 @@
*/
public class ExtractUtil implements NameConstant {

/**
private static final class StringExtractor extends GenericVisitorAdapter<String, String> {
@Override
public String visit(StringLiteralExpr n, String arg) {
String string = n.toString();

if("\"\"".equals(string)){
return "";
}

return string.substring(1,string.length()-1);
}

@Override
public String visit(FieldAccessExpr n, String arg) {
return visit(n.getFieldExpr(), findClassNamed(n.getScope(), getClassDeclarationOf(n)));
}

private ClassOrInterfaceDeclaration findClassNamed(Expression scope, ClassOrInterfaceDeclaration classDeclarationOf) {
for(BodyDeclaration b : classDeclarationOf.getMembers()) {
if (b instanceof ClassOrInterfaceDeclaration) {
ClassOrInterfaceDeclaration classDeclaration = (ClassOrInterfaceDeclaration) b;
if(classDeclaration.getName().equals(scope.toString())) {
return classDeclaration;
}
}
}
// Not found ? Damn, maybe it is declared in a damned local class
if(classDeclarationOf.getParentNode() instanceof ClassOrInterfaceDeclaration) {
return findClassNamed(scope, (ClassOrInterfaceDeclaration) classDeclarationOf.getParentNode());
} else {
Node node = classDeclarationOf;
while(node.getParentNode()!=null) {
node = node.getParentNode();
}
if (node instanceof CompilationUnit) {
CompilationUnit cu = (CompilationUnit) node;
for(TypeDeclaration d : cu.getTypes()) {
if (d instanceof ClassOrInterfaceDeclaration) {
ClassOrInterfaceDeclaration classDeclaration = (ClassOrInterfaceDeclaration) d;
if(classDeclaration.getName().equals(scope.toString())) {
return classDeclaration;
}
}
}
}
}
throw new UnsupportedOperationException(
String.format("Can't find declaration of %s in %s. String extraction from another file doesn't work. Sorry.",
scope.toString(), classDeclarationOf.getName()));
}

@Override
public String visit(NameExpr n, String arg) {
return visit(n, getClassDeclarationOf(n));
}

private String visit(NameExpr n, ClassOrInterfaceDeclaration classDeclarationOf) {
return evaluateFieldNamed(n.getName(), classDeclarationOf);
}

private String evaluateFieldNamed(String name, ClassOrInterfaceDeclaration classDeclarationOf) {
for(BodyDeclaration b : classDeclarationOf.getMembers()) {
if (b instanceof FieldDeclaration) {
FieldDeclaration fieldDeclaration = (FieldDeclaration) b;
for(VariableDeclarator variable : fieldDeclaration.getVariables()) {
if(variable.getId().getName().equals(name)) {
return variable.getInit().accept(this, "");
}
}
}
}
return "";
}

private ClassOrInterfaceDeclaration getClassDeclarationOf(Node n) {
while(!(n instanceof ClassOrInterfaceDeclaration)) {
n = n.getParentNode();
}
return (ClassOrInterfaceDeclaration) n;
}
}

/**
* Hide implicit public constructor.
*/
private ExtractUtil(){
Expand All @@ -51,15 +143,7 @@ private ExtractUtil(){
* @return string version of the node value.
*/
public static String asString(Node node){
// return node.accept(new GenericVisitorAdapter<String, String>() {
// }, "");
String string = node.toString();

if("\"\"".equals(string)){
return "";
}

return string.substring(1,string.length()-1);
return node.accept(new StringExtractor(), "");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,27 @@
/**
* A controller referencing uri through a constant
*/
class Constants_For_ControllerReferencingConstant {
public static final String URI = "/constant";
}
public class ControllerReferencingConstant extends DefaultController {
public static interface Constants {
public static final String URI = "/constant";
}
public static final String URI = "/constant";

@Route(method= HttpMethod.GET, uri=URI)
public Result get() {
return ok();
}

@Route(method= HttpMethod.POST, uri=Constants.URI)
public Result post() {
return ok();
}

@Route(method= HttpMethod.PUT, uri=Constants_For_ControllerReferencingConstant.URI)
public Result put() {
return ok();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ public void testReferencingConstant() throws IOException, ParseException {

final Collection<ControllerRouteModel> routes = (Collection<ControllerRouteModel>) model.getRoutes().get("/constant");
assertThat(routes).isNotNull();
assertThat(routes).hasSize(1);
assertThat(routes).hasSize(3);

for (ControllerRouteModel route : routes) {
assertThat(route.getHttpMethod().name()).isEqualToIgnoringCase(route.getMethodName());
Expand Down

0 comments on commit b7a36db

Please sign in to comment.