diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java index a87210e0b..ab1d18c38 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java @@ -13,13 +13,16 @@ package org.springframework.ide.vscode.boot.java.requestmapping; import java.util.Iterator; import java.util.List; +import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.SymbolInformation; import org.eclipse.lsp4j.SymbolKind; @@ -35,8 +38,13 @@ public class RequestMappingSymbolProvider implements SymbolProvider { public SymbolInformation getSymbol(Annotation node, TextDocument doc) { try { String path = getPath(node); + String parentPath = getParentPath(node); String method = getMethod(node); + if (path != null && parentPath != null) { + String separator = !parentPath.endsWith("/") && !path.startsWith("/") ? "/" : ""; + path = parentPath + separator + path; + } if (path != null && !path.startsWith("/")) { path = "/" + path; } @@ -113,4 +121,29 @@ public class RequestMappingSymbolProvider implements SymbolProvider { return null; } + private String getParentPath(Annotation node) { + ASTNode parent = node.getParent(); + while (parent != null && !(parent instanceof TypeDeclaration)) { + parent = parent.getParent(); + } + + if (parent != null) { + TypeDeclaration type = (TypeDeclaration) parent; + List modifiers = type.modifiers(); + Iterator iterator = modifiers.iterator(); + while (iterator.hasNext()) { + Object modifier = iterator.next(); + if (modifier instanceof Annotation) { + Annotation annotation = (Annotation) modifier; + ITypeBinding resolvedType = annotation.resolveTypeBinding(); + String annotationType = resolvedType.getQualifiedName(); + if (annotationType != null && Constants.SPRING_REQUEST_MAPPING.equals(annotationType)) { + return getPath(annotation); + } + } + } + } + return null; + } + } diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/RequestMappingSymbolProviderTest.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/RequestMappingSymbolProviderTest.java index 631fcf09d..4346982e3 100644 --- a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/RequestMappingSymbolProviderTest.java +++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/requestmapping/test/RequestMappingSymbolProviderTest.java @@ -83,6 +83,20 @@ public class RequestMappingSymbolProviderTest { assertTrue(containsSymbol(symbols, "@/greeting -- (no method defined)", uriPrefix + "/src/main/java/org/test/SimpleMappingClass.java", 6, 1, 6, 29)); } + @Test + public void testParentRequestMappingSymbol() throws Exception { + harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI())); + + SpringIndexer indexer = new SpringIndexer(harness.getServer(), projectFinder, symbolProviders); + File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()); + indexer.scanFiles(directory); + + String uriPrefix = "file://" + directory.getAbsolutePath(); + List symbols = indexer.getSymbols(uriPrefix + "/src/main/java/org/test/ParentMappingClass.java"); + assertEquals(2, symbols.size()); + assertTrue(containsSymbol(symbols, "@/parent/greeting -- (no method defined)", uriPrefix + "/src/main/java/org/test/ParentMappingClass.java", 7, 1, 7, 29)); + } + private boolean containsSymbol(List symbols, String name, String uri, int startLine, int startCHaracter, int endLine, int endCharacter) { for (Iterator iterator = symbols.iterator(); iterator.hasNext();) { SymbolInformation symbol = iterator.next(); diff --git a/headless-services/boot-java-language-server/src/test/resources/test-projects/test-request-mapping-symbols/src/main/java/org/test/ParentMappingClass.java b/headless-services/boot-java-language-server/src/test/resources/test-projects/test-request-mapping-symbols/src/main/java/org/test/ParentMappingClass.java new file mode 100644 index 000000000..8b8ee78ca --- /dev/null +++ b/headless-services/boot-java-language-server/src/test/resources/test-projects/test-request-mapping-symbols/src/main/java/org/test/ParentMappingClass.java @@ -0,0 +1,13 @@ +package org.test; + +import org.springframework.web.bind.annotation.RequestMapping; + +@RequestMapping("parent") +public class ParentMappingClass { + + @RequestMapping("/greeting") + public String hello() { + return "Hello"; + } + +}