added more complex nested webflux router case and extracted symbol generation logic for routes

This commit is contained in:
Martin Lippert
2018-03-11 20:08:46 +01:00
parent 3023bc22e8
commit 62f975d74c
8 changed files with 128 additions and 20 deletions

View File

@@ -28,8 +28,6 @@ import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.SymbolKind;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
@@ -48,9 +46,11 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
Location location = new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()));
String[] path = getPath(node);
String[] parentPath = getParentPath(node);
String[] method = getMethod(node);
String[] methods = getMethod(node);
String[] contentTypes = new String[0];
String[] acceptTypes = new String[0];
String methodStr = method == null || method.length == 0 ? "" : String.join(",", method);
// String methodStr = method == null || method.length == 0 ? "" : String.join(",", method);
return (parentPath == null ? Stream.of("") : Arrays.stream(parentPath)).filter(Objects::nonNull)
.flatMap(parent -> (path == null ? Stream.<String>empty() : Arrays.stream(path))
@@ -62,8 +62,7 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
}
return resultPath.startsWith("/") ? resultPath : "/" + resultPath;
}))
.map(p -> "@" + p + (methodStr.isEmpty() ? "" : " -- " + methodStr))
.map(symbolLabel -> new EnhancedSymbolInformation(new SymbolInformation(symbolLabel, SymbolKind.Interface, location), null))
.map(p -> RouteUtils.createRouteSymbol(location, p, methods, contentTypes, acceptTypes, null))
.collect(Collectors.toList());
} catch (Exception e) {
e.printStackTrace();

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.requestmapping;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.SymbolKind;
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
/**
* @author Martin Lippert
*/
public class RouteUtils {
public static EnhancedSymbolInformation createRouteSymbol(Location location, String path,
String[] httpMethods, String[] contentTypes, String[] acceptTypes, Object enhancedInformation) {
if (path != null && path.length() > 0) {
String label = "@" + (path.startsWith("/") ? path : ("/" + path));
label += (httpMethods == null || httpMethods.length == 0 ? "" : " -- " + WebfluxUtils.getStringRep(httpMethods, string -> string));
return new EnhancedSymbolInformation(new SymbolInformation(label, SymbolKind.Interface, location), enhancedInformation);
}
else {
return null;
}
}
}

View File

@@ -28,8 +28,6 @@ import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.SymbolKind;
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.commons.util.BadLocationException;
@@ -100,13 +98,12 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider {
if (path != null && path.length() > 0) {
try {
Location location = new Location(doc.getUri(), doc.toRange(methodNameStart, node.getLength() - (methodNameStart - invocationStart)));
String label = "@" + (path.startsWith("/") ? path : ("/" + path));
label += (httpMethods == null || httpMethods.length == 0 ? "" : " -- " + WebfluxUtils.getStringRep(httpMethods, string -> string));
Location location = new Location(doc.getUri(), doc.toRange(methodNameStart, node.getLength() - (methodNameStart - invocationStart)));
WebfluxHandlerInformation handler = extractHandlerInformation(node, path, httpMethods, contentTypes, acceptTypes);
result.add(new EnhancedSymbolInformation(new SymbolInformation(label, SymbolKind.Interface, location), handler));
result.add(RouteUtils.createRouteSymbol(location, path, httpMethods, contentTypes, acceptTypes, handler));
} catch (BadLocationException e) {
e.printStackTrace();
}
@@ -159,7 +156,7 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider {
String methodName = methodBinding.getName();
if (WebfluxUtils.REQUEST_PREDICATE_METHOD_METHOD.equals(methodName)) {
return WebfluxUtils.extractStringLiteralArgument(methodInvocation);
return WebfluxUtils.extractQualifiedNameArgument(methodInvocation);
}
return null;
});

View File

@@ -117,7 +117,7 @@ public class WebfluxUtils {
StringBuilder result = new StringBuilder(valueConverter.apply(multipleTypes[0]));
for (int i = 1; i < multipleTypes.length; i++) {
result.append(", ");
result.append(",");
result.append(valueConverter.apply(multipleTypes[i]));
}

View File

@@ -90,9 +90,28 @@ public class WebFluxCodeLensProviderTest {
assertEquals(3, codeLenses.size());
assertTrue(containsCodeLens(codeLenses, "GET /person/{id} - Accept: application/json", 9, 29, 9, 38));
assertTrue(containsCodeLens(codeLenses, "POST / - Accept: application/json - Content-Type: application/json,application/pdf", 13, 29, 13, 41));
assertTrue(containsCodeLens(codeLenses, "GET,HEAD /person - Accept: text/plain,application/json", 17, 29, 17, 39));
}
@Test
public void testRoutesCodeLensesNestedRoutes3() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/PersonHandler3.java").toUri().toString();
TextDocumentInfo doc = harness.getOrReadFile(new File(new URI(docUri)), LanguageId.JAVA.toString());
TextDocumentInfo openedDoc = harness.openDocument(doc);
List<? extends CodeLens> codeLenses = harness.getCodeLenses(openedDoc);
assertEquals(6, codeLenses.size());
/*
assertTrue(containsCodeLens(codeLenses, "GET /person/{id} - Accept: application/json", 9, 29, 9, 38));
assertTrue(containsCodeLens(codeLenses, "POST / - Accept: application/json - Content-Type: application/json, application/pdf", 13, 29, 13, 41));
assertTrue(containsCodeLens(codeLenses, "GET, HEAD /person - Accept: text/plain, application/json", 17, 29, 17, 39));
*/
}
private boolean containsCodeLens(List<? extends CodeLens> codeLenses, String commandTitle, int startLine, int startPosition, int endLine, int endPosition) {

View File

@@ -153,7 +153,7 @@ public class WebFluxMappingSymbolProviderTest {
assertEquals(5, symbols.size());
assertTrue(containsSymbol(symbols, "@/person/{id} -- GET", docUri, 29, 6, 29, 45));
assertTrue(containsSymbol(symbols, "@/ -- POST", docUri, 31, 6, 31, 117));
assertTrue(containsSymbol(symbols, "@/person -- GET, HEAD", docUri, 30, 7, 30, 113));
assertTrue(containsSymbol(symbols, "@/person -- GET,HEAD", docUri, 30, 7, 30, 113));
List<? extends Object> addons = getAdditionalInformation(docUri);
assertEquals(3, addons.size());
@@ -183,6 +183,51 @@ public class WebFluxMappingSymbolProviderTest {
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> listPeople(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo3.getHandlerMethod());
}
@Test
public void testNestedRoutesMappingSymbols3() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/NestedRouter3.java").toUri().toString();
List<? extends SymbolInformation> symbols = getSymbols(docUri);
assertEquals(8, symbols.size());
assertTrue(containsSymbol(symbols, "@/person/sub1/sub2/{id} -- GET", docUri, 29, 7, 29, 46));
assertTrue(containsSymbol(symbols, "@/person/sub1/sub2 -- GET", docUri, 30, 8, 30, 61));
assertTrue(containsSymbol(symbols, "@/person/sub1/sub2/nestedGet -- GET", docUri, 31, 9, 31, 56));
assertTrue(containsSymbol(symbols, "@/person/sub1/andNestPath/andNestPathGET -- GET", docUri, 33, 5, 33, 54));
assertTrue(containsSymbol(symbols, "@/person/ -- POST", docUri, 34, 5, 34, 82));
assertTrue(containsSymbol(symbols, "@/nestedDelete -- DELETE", docUri, 35, 42, 35, 93));
/*
List<? extends Object> addons = getAdditionalInformation(docUri);
assertEquals(3, addons.size());
WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "/person/{id}", "GET").get(0);
assertEquals("/person/{id}", handlerInfo1.getPath());
assertEquals("[GET]", Arrays.toString(handlerInfo1.getHttpMethods()));
assertEquals(0, handlerInfo1.getContentTypes().length);
assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo1.getAcceptTypes()));
assertEquals("org.test.PersonHandler2", handlerInfo1.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> getPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo1.getHandlerMethod());
WebfluxHandlerInformation handlerInfo2 = getWebfluxHandler(addons, "/", "POST").get(0);
assertEquals("/", handlerInfo2.getPath());
assertEquals("[POST]", Arrays.toString(handlerInfo2.getHttpMethods()));
assertEquals("[APPLICATION_JSON, APPLICATION_PDF]", Arrays.toString(handlerInfo2.getContentTypes()));
assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo2.getAcceptTypes()));
assertEquals("org.test.PersonHandler2", handlerInfo2.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> createPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo2.getHandlerMethod());
WebfluxHandlerInformation handlerInfo3 = getWebfluxHandler(addons, "/person", "HEAD").get(0);
assertEquals("/person", handlerInfo3.getPath());
assertEquals("[GET, HEAD]", Arrays.toString(handlerInfo3.getHttpMethods()));
assertEquals(0, handlerInfo3.getContentTypes().length);
assertEquals("[TEXT_PLAIN, APPLICATION_JSON]", Arrays.toString(handlerInfo3.getAcceptTypes()));
assertEquals("org.test.PersonHandler2", handlerInfo3.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> listPeople(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo3.getHandlerMethod());
*/
}
private boolean containsSymbol(List<? extends SymbolInformation> symbols, String name, String uri, int startLine, int startCHaracter, int endLine, int endCharacter) {
for (Iterator<? extends SymbolInformation> iterator = symbols.iterator(); iterator.hasNext();) {
SymbolInformation symbol = iterator.next();

View File

@@ -24,10 +24,16 @@ public class NestedRouter3 {
PersonHandler3 handler = new PersonHandler3();
return nest(path("/person"),
nest(accept(APPLICATION_JSON),
route(GET("/{id}"), handler::getPerson)
.andRoute(method(HttpMethod.GET), handler::listPeople)
).andRoute(POST("/").and(contentType(APPLICATION_JSON)), handler::createPerson));
nest(path("/sub1"),
nest(path("/sub2"),
nest(accept(APPLICATION_JSON),
route(GET("/{id}"), handler::getPerson)
.andRoute(method(HttpMethod.GET), handler::listPeople))
.andRoute(GET("/nestedGet"), handler::getPerson))
.and(nest(path("/andNestPath"),
route(GET("/andNestPathGET"), handler::getPerson))))
.andRoute(POST("/").and(contentType(APPLICATION_JSON)), handler::createPerson))
.and(nest(method(HttpMethod.DELETE), route(path("/nestedDelete"), handler::deletePerson)));
}
}

View File

@@ -19,4 +19,8 @@ public class PersonHandler3 {
return ServerResponse.notFound().build();
}
public Mono<ServerResponse> deletePerson(ServerRequest request) {
return ServerResponse.notFound().build();
}
}