diff --git a/extensions/wisdom-raml/wisdom-source-watcher/src/main/java/org/wisdom/source/ast/util/ExtractUtil.java b/extensions/wisdom-raml/wisdom-source-watcher/src/main/java/org/wisdom/source/ast/util/ExtractUtil.java index a6414993b..932ae098e 100644 --- a/extensions/wisdom-raml/wisdom-source-watcher/src/main/java/org/wisdom/source/ast/util/ExtractUtil.java +++ b/extensions/wisdom-raml/wisdom-source-watcher/src/main/java/org/wisdom/source/ast/util/ExtractUtil.java @@ -19,15 +19,26 @@ */ package org.wisdom.source.ast.util; -import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.comments.JavadocComment; -import com.github.javaparser.ast.expr.MemberValuePair; +import static java.util.Collections.singleton; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import static java.util.Collections.singleton; +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; /** * A set of function that helps to extract various entity from the javaparser AST. @@ -36,7 +47,89 @@ */ public class ExtractUtil implements NameConstant { - /** + private static final class StringExtractor extends GenericVisitorAdapter { + @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(){ @@ -50,13 +143,7 @@ private ExtractUtil(){ * @return string version of the node value. */ public static String asString(Node node){ - String string = node.toString(); - - if("\"\"".equals(string)){ - return ""; - } - - return string.substring(1,string.length()-1); + return node.accept(new StringExtractor(), ""); } /** diff --git a/extensions/wisdom-raml/wisdom-source-watcher/src/test/java/controller/ControllerReferencingConstant.java b/extensions/wisdom-raml/wisdom-source-watcher/src/test/java/controller/ControllerReferencingConstant.java new file mode 100644 index 000000000..17b43c9c9 --- /dev/null +++ b/extensions/wisdom-raml/wisdom-source-watcher/src/test/java/controller/ControllerReferencingConstant.java @@ -0,0 +1,53 @@ +/* + * #%L + * Wisdom-Framework + * %% + * Copyright (C) 2013 - 2015 Wisdom Framework + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package controller; + +import org.wisdom.api.DefaultController; +import org.wisdom.api.annotations.Route; +import org.wisdom.api.http.HttpMethod; +import org.wisdom.api.http.Result; + +/** + * 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(); + } +} diff --git a/extensions/wisdom-raml/wisdom-source-watcher/src/test/java/org/wisdom/source/ast/visitor/ControllerSourceVisitorTest.java b/extensions/wisdom-raml/wisdom-source-watcher/src/test/java/org/wisdom/source/ast/visitor/ControllerSourceVisitorTest.java index ce57e2549..83b25b653 100644 --- a/extensions/wisdom-raml/wisdom-source-watcher/src/test/java/org/wisdom/source/ast/visitor/ControllerSourceVisitorTest.java +++ b/extensions/wisdom-raml/wisdom-source-watcher/src/test/java/org/wisdom/source/ast/visitor/ControllerSourceVisitorTest.java @@ -240,6 +240,24 @@ public void testControllerUsingPath() throws IOException, ParseException { } + @Test + public void testReferencingConstant() throws IOException, ParseException { + File file = new File("src/test/java/controller/ControllerReferencingConstant.java"); + final CompilationUnit declaration = JavaParser.parse(file); + ControllerModel model = new ControllerModel(); + visitor.visit(declaration, model); + + final Collection routes = (Collection) model.getRoutes().get("/constant"); + assertThat(routes).isNotNull(); + assertThat(routes).hasSize(3); + + for (ControllerRouteModel route : routes) { + assertThat(route.getHttpMethod().name()).isEqualToIgnoringCase(route.getMethodName()); + assertThat(route.getParams()).isEmpty(); + assertThat(route.getPath()).isEqualToIgnoringCase("/constant"); + } + } + private ControllerRouteModel getModelByPath(ControllerModel model, String name) { for (ControllerRouteModel route : (Collection) model.getRoutesAsMultiMap().values()) { if (route.getPath().equals(name)) {