further improvements to webflux symbol and code lens analysis, including content and accept type identification

This commit is contained in:
Martin Lippert
2018-03-11 08:24:26 +01:00
parent 1adbab0ac0
commit 3023bc22e8
15 changed files with 354 additions and 158 deletions

View File

@@ -10,6 +10,9 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.requestmapping;
import java.util.LinkedHashSet;
import java.util.Set;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;
@@ -19,32 +22,31 @@ import org.eclipse.jdt.core.dom.MethodInvocation;
*/
public class WebfluxAcceptTypeFinder extends ASTVisitor {
private String acceptType;
private Set<String> acceptTypes;
public WebfluxAcceptTypeFinder() {
this.acceptTypes = new LinkedHashSet<>();
}
public String getAcceptType() {
return acceptType;
public Set<String> getAcceptTypes() {
return acceptTypes;
}
@Override
public boolean visit(MethodInvocation node) {
boolean visitChildren = true;
IMethodBinding methodBinding = node.resolveMethodBinding();
if (WebfluxUtils.REQUEST_PREDICATES_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) {
String name = methodBinding.getName();
if (name != null && WebfluxUtils.REQUEST_PREDICATE_ACCEPT_TYPE_METHOD.equals(name)) {
acceptType = WebfluxUtils.extractSimpleNameArgument(node);
String acceptType = WebfluxUtils.extractSimpleNameArgument(node);
if (acceptType != null) {
acceptTypes.add(acceptType);
}
}
}
if (WebfluxUtils.isRouteMethodInvocation(methodBinding)) {
visitChildren = false;
}
return visitChildren;
return !WebfluxUtils.isRouteMethodInvocation(methodBinding);
}
}

View File

@@ -10,6 +10,9 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.requestmapping;
import java.util.LinkedHashSet;
import java.util.Set;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.IMethodBinding;
@@ -20,15 +23,16 @@ import org.eclipse.jdt.core.dom.MethodInvocation;
*/
public class WebfluxContentTypeFinder extends ASTVisitor {
private String contentType;
private Set<String> contentTypes;
private ASTNode root;
public WebfluxContentTypeFinder(ASTNode root) {
this.root = root;
this.contentTypes = new LinkedHashSet<>();
}
public String getContentType() {
return contentType;
public Set<String> getContentTypes() {
return contentTypes;
}
@Override
@@ -41,7 +45,10 @@ public class WebfluxContentTypeFinder extends ASTVisitor {
if (WebfluxUtils.REQUEST_PREDICATES_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) {
String name = methodBinding.getName();
if (name != null && WebfluxUtils.REQUEST_PREDICATE_CONTENT_TYPE_METHOD.equals(name)) {
contentType = WebfluxUtils.extractSimpleNameArgument(node);
String contentType = WebfluxUtils.extractSimpleNameArgument(node);
if (contentType != null) {
contentTypes.add(contentType);
}
}
}

View File

@@ -72,11 +72,16 @@ public class WebfluxHandlerCodeLensProvider implements CodeLensProvider {
CodeLens codeLens = new CodeLens();
codeLens.setRange(document.toRange(node.getName().getStartPosition(), node.getName().getLength()));
String codeLensCommand = handlerInfo.getHttpMethod() != null ? handlerInfo.getHttpMethod() + " " : "";
String httpMethod = WebfluxUtils.getStringRep(handlerInfo.getHttpMethods(), string -> string);
String codeLensCommand = httpMethod != null ? httpMethod + " " : "";
codeLensCommand += handlerInfo.getPath();
String acceptType = WebfluxUtils.getStringRep(handlerInfo.getAcceptTypes(), WebfluxUtils::getMediaType);
codeLensCommand += acceptType != null ? " - Accept: " + acceptType : "";
codeLensCommand += handlerInfo.getAcceptType() != null ? " - Accept: " + getMediaType(handlerInfo.getAcceptType()) : "";
codeLensCommand += handlerInfo.getContentType() != null ? " - Content-Type: " + getMediaType(handlerInfo.getContentType()) : "";
String contentType = WebfluxUtils.getStringRep(handlerInfo.getContentTypes(), WebfluxUtils::getMediaType);
codeLensCommand += contentType != null ? " - Content-Type: " + contentType : "";
codeLens.setCommand(new Command(codeLensCommand, null));
@@ -89,18 +94,4 @@ public class WebfluxHandlerCodeLensProvider implements CodeLensProvider {
}
}
protected String getMediaType(String handlerInfo) {
if (handlerInfo == null) {
return null;
}
try {
MediaTypeMapping mediaType = MediaTypeMapping.valueOf(handlerInfo);
return mediaType.getMediaType();
}
catch (IllegalArgumentException e) {
return handlerInfo;
}
}
}

View File

@@ -19,18 +19,18 @@ public class WebfluxHandlerInformation {
private final String handlerMethod;
private final String path;
private final String httpMethod;
private final String contentType;
private final String acceptType;
private final String[] httpMethods;
private final String[] contentTypes;
private final String[] acceptTypes;
public WebfluxHandlerInformation(String handlerClass, String handlerMethod, String path, String httpMethod, String contentType, String acceptType) {
public WebfluxHandlerInformation(String handlerClass, String handlerMethod, String path, String[] httpMethods, String[] contentTypes, String[] acceptTypes) {
this.handlerClass = handlerClass;
this.handlerMethod = handlerMethod;
this.path = path;
this.httpMethod = httpMethod;
this.contentType = contentType;
this.acceptType = acceptType;
this.httpMethods = httpMethods;
this.contentTypes = contentTypes;
this.acceptTypes = acceptTypes;
}
public String getHandlerClass() {
@@ -45,16 +45,16 @@ public class WebfluxHandlerInformation {
return path;
}
public String getHttpMethod() {
return httpMethod;
public String[] getHttpMethods() {
return httpMethods;
}
public String getContentType() {
return contentType;
public String[] getContentTypes() {
return contentTypes;
}
public String getAcceptType() {
return acceptType;
public String[] getAcceptTypes() {
return acceptTypes;
}
}

View File

@@ -10,6 +10,9 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.requestmapping;
import java.util.LinkedHashSet;
import java.util.Set;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.IMethodBinding;
@@ -20,15 +23,16 @@ import org.eclipse.jdt.core.dom.MethodInvocation;
*/
public class WebfluxMethodFinder extends ASTVisitor {
private String method;
private Set<String> methods;
private ASTNode root;
public WebfluxMethodFinder(ASTNode root) {
this.root = root;
this.methods = new LinkedHashSet<>();
}
public String getMethod() {
return method;
public Set<String> getMethods() {
return methods;
}
@Override
@@ -41,10 +45,10 @@ public class WebfluxMethodFinder extends ASTVisitor {
if (WebfluxUtils.REQUEST_PREDICATES_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) {
String name = methodBinding.getName();
if (name != null && WebfluxUtils.REQUEST_PREDICATE_HTTPMETHOD_METHODS.contains(name)) {
method = name;
methods.add(name);
}
else if (name != null && WebfluxUtils.REQUEST_PREDICATE_METHOD_METHOD.equals(name)) {
method = WebfluxUtils.extractQualifiedNameArgument(node);
methods.add(WebfluxUtils.extractQualifiedNameArgument(node));
}
}

View File

@@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.java.requestmapping;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import org.eclipse.jdt.core.dom.ASTNode;
@@ -34,9 +35,6 @@ import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
/**
* @author Martin Lippert
*/
@@ -92,10 +90,10 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider {
protected void extractMappingSymbol(MethodInvocation node, TextDocument doc, List<EnhancedSymbolInformation> result) {
String path = extractPath(node);
String httpMethod = extractMethod(node);
String contentType = extractContentType(node);
String acceptType = extractAcceptType(node);
String[] httpMethods = extractMethods(node);
String[] contentTypes = extractContentTypes(node);
String[] acceptTypes = extractAcceptTypes(node);
int methodNameStart = node.getName().getStartPosition();
int invocationStart = node.getStartPosition();
@@ -103,9 +101,10 @@ 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)) + (httpMethod == null || httpMethod.isEmpty() ? "" : " -- " + httpMethod);
String label = "@" + (path.startsWith("/") ? path : ("/" + path));
label += (httpMethods == null || httpMethods.length == 0 ? "" : " -- " + WebfluxUtils.getStringRep(httpMethods, string -> string));
WebfluxHandlerInformation handler = extractHandlerInformation(node, path, httpMethod, contentType, acceptType);
WebfluxHandlerInformation handler = extractHandlerInformation(node, path, httpMethods, contentTypes, acceptTypes);
result.add(new EnhancedSymbolInformation(new SymbolInformation(label, SymbolKind.Interface, location), handler));
} catch (BadLocationException e) {
@@ -118,98 +117,107 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider {
WebfluxPathFinder pathFinder = new WebfluxPathFinder(routerInvocation);
routerInvocation.accept(pathFinder);
String path = pathFinder.getPath();
if (path == null) path = "";
List<String> path = new ArrayList<>();
String firstPath = pathFinder.getPath();
if (firstPath != null) {
path.add(firstPath);
}
return extractNestedValue(routerInvocation, path, (methodInvocationPathPrefix) -> {
IMethodBinding methodBinding = methodInvocationPathPrefix.getT1().resolveMethodBinding();
extractNestedValue(routerInvocation, path, (methodInvocation) -> {
IMethodBinding methodBinding = methodInvocation.resolveMethodBinding();
String methodName = methodBinding.getName();
if (WebfluxUtils.REQUEST_PREDICATE_PATH_METHOD.equals(methodName)) {
String additionalPath = WebfluxUtils.extractStringLiteralArgument(methodInvocationPathPrefix.getT1());
String additionalPath = WebfluxUtils.extractStringLiteralArgument(methodInvocation);
if (additionalPath != null && additionalPath.length() > 0) {
return additionalPath + methodInvocationPathPrefix.getT2();
return additionalPath;
}
}
return methodInvocationPathPrefix.getT2();
return null;
});
StringBuilder result = new StringBuilder();
path.stream().forEach(part -> result.insert(0, part));
return result.toString();
}
private String extractMethod(MethodInvocation routerInvocation) {
private String[] extractMethods(MethodInvocation routerInvocation) {
WebfluxMethodFinder methodFinder = new WebfluxMethodFinder(routerInvocation);
routerInvocation.accept(methodFinder);
String method = methodFinder.getMethod();
return extractNestedValue(routerInvocation, method, (methodInvocationPathPrefix) -> {
IMethodBinding methodBinding = methodInvocationPathPrefix.getT1().resolveMethodBinding();
String methodName = methodBinding.getName();
if (WebfluxUtils.REQUEST_PREDICATE_METHOD_METHOD.equals(methodName)) {
String newMethod = WebfluxUtils.extractStringLiteralArgument(methodInvocationPathPrefix.getT1());
if (method == null) {
return newMethod;
}
}
return methodInvocationPathPrefix.getT2();
});
}
private String extractAcceptType(MethodInvocation routerInvocation) {
String acceptType = null;
WebfluxAcceptTypeFinder acceptTypeFinder = new WebfluxAcceptTypeFinder();
List<?> arguments = routerInvocation.arguments();
for (Object argument : arguments) {
if (argument != null && argument instanceof ASTNode) {
((ASTNode)argument).accept(acceptTypeFinder);
if (acceptTypeFinder.getAcceptType() != null) {
acceptType = acceptTypeFinder.getAcceptType();
}
((ASTNode)argument).accept(methodFinder);
}
}
final Set<String> methods = methodFinder.getMethods();
extractNestedValue(routerInvocation, methods, (methodInvocation) -> {
IMethodBinding methodBinding = methodInvocation.resolveMethodBinding();
String methodName = methodBinding.getName();
if (WebfluxUtils.REQUEST_PREDICATE_METHOD_METHOD.equals(methodName)) {
return WebfluxUtils.extractStringLiteralArgument(methodInvocation);
}
return null;
});
return (String[]) methods.toArray(new String[methods.size()]);
}
private String[] extractAcceptTypes(MethodInvocation routerInvocation) {
WebfluxAcceptTypeFinder typeFinder = new WebfluxAcceptTypeFinder();
List<?> arguments = routerInvocation.arguments();
for (Object argument : arguments) {
if (argument != null && argument instanceof ASTNode) {
((ASTNode)argument).accept(typeFinder);
}
}
return extractNestedValue(routerInvocation, acceptType, (methodInvocationPathPrefix) -> {
IMethodBinding methodBinding = methodInvocationPathPrefix.getT1().resolveMethodBinding();
Set<String> acceptTypes = typeFinder.getAcceptTypes();
extractNestedValue(routerInvocation, acceptTypes, (methodInvocation) -> {
IMethodBinding methodBinding = methodInvocation.resolveMethodBinding();
String methodName = methodBinding.getName();
if (WebfluxUtils.REQUEST_PREDICATE_ACCEPT_TYPE_METHOD.equals(methodName)) {
String newAcceptType = WebfluxUtils.extractSimpleNameArgument(methodInvocationPathPrefix.getT1());
if (newAcceptType != null) {
return newAcceptType;
}
return WebfluxUtils.extractSimpleNameArgument(methodInvocation);
}
return methodInvocationPathPrefix.getT2();
return null;
});
return (String[]) acceptTypes.toArray(new String[acceptTypes.size()]);
}
private String extractContentType(MethodInvocation routerInvocation) {
private String[] extractContentTypes(MethodInvocation routerInvocation) {
WebfluxContentTypeFinder contentTypeFinder = new WebfluxContentTypeFinder(routerInvocation);
routerInvocation.accept(contentTypeFinder);
List<?> arguments = routerInvocation.arguments();
for (Object argument : arguments) {
if (argument != null && argument instanceof ASTNode) {
((ASTNode)argument).accept(contentTypeFinder);
}
}
String contentType = contentTypeFinder.getContentType();
Set<String> contentTypes = contentTypeFinder.getContentTypes();
return extractNestedValue(routerInvocation, contentType, (methodInvocationPathPrefix) -> {
IMethodBinding methodBinding = methodInvocationPathPrefix.getT1().resolveMethodBinding();
extractNestedValue(routerInvocation, contentTypes, (methodInvocation) -> {
IMethodBinding methodBinding = methodInvocation.resolveMethodBinding();
String methodName = methodBinding.getName();
if (WebfluxUtils.REQUEST_PREDICATE_CONTENT_TYPE_METHOD.equals(methodName)) {
String newContentType = WebfluxUtils.extractSimpleNameArgument(methodInvocationPathPrefix.getT1());
if (contentType == null) {
return newContentType;
}
return WebfluxUtils.extractSimpleNameArgument(methodInvocation);
}
return methodInvocationPathPrefix.getT2();
return null;
});
return (String[]) contentTypes.toArray(new String[contentTypes.size()]);
}
private String extractNestedValue(ASTNode node, String value, Function<Tuple2<MethodInvocation, String>, String> extractor) {
private void extractNestedValue(ASTNode node, Collection<String> values, Function<MethodInvocation, String> extractor) {
if (node == null || node instanceof TypeDeclaration) {
return value;
return;
}
if (node instanceof MethodInvocation) {
@@ -223,17 +231,20 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider {
for (Object argument : arguments) {
if (argument instanceof MethodInvocation) {
MethodInvocation nestedMethod = (MethodInvocation) argument;
value = extractor.apply(Tuples.of(nestedMethod, value));
String value = extractor.apply(nestedMethod);
if (value != null) {
values.add(value);
}
}
}
}
}
}
return extractNestedValue(node.getParent(), value, extractor);
extractNestedValue(node.getParent(), values, extractor);
}
private WebfluxHandlerInformation extractHandlerInformation(MethodInvocation node, String path, String httpMethod, String contentType, String acceptType) {
private WebfluxHandlerInformation extractHandlerInformation(MethodInvocation node, String path, String[] httpMethods, String[] contentTypes, String[] acceptTypes) {
List<?> arguments = node.arguments();
if (arguments != null) {
@@ -249,7 +260,7 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider {
String handlerMethod = methodBinding.getMethodDeclaration().toString();
if (handlerMethod != null) handlerMethod = handlerMethod.trim();
return new WebfluxHandlerInformation(handlerClass, handlerMethod, path, httpMethod, contentType, acceptType);
return new WebfluxHandlerInformation(handlerClass, handlerMethod, path, httpMethods, contentTypes, acceptTypes);
}
}
}

View File

@@ -14,6 +14,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;
@@ -80,8 +81,6 @@ public class WebfluxUtils {
return null;
}
public static boolean isRouteMethodInvocation(IMethodBinding methodBinding) {
if (ROUTER_FUNCTIONS_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) {
String name = methodBinding.getName();
@@ -97,8 +96,35 @@ public class WebfluxUtils {
}
return false;
}
public static String getMediaType(String constantRep) {
if (constantRep == null) {
return null;
}
try {
MediaTypeMapping mediaType = MediaTypeMapping.valueOf(constantRep);
return mediaType.getMediaType();
}
catch (IllegalArgumentException e) {
return constantRep;
}
}
public static String getStringRep(String[] multipleTypes, Function<String, String> valueConverter) {
if (multipleTypes == null || multipleTypes.length == 0) return null;
StringBuilder result = new StringBuilder(valueConverter.apply(multipleTypes[0]));
for (int i = 1; i < multipleTypes.length; i++) {
result.append(", ");
result.append(valueConverter.apply(multipleTypes[i]));
}
return result.toString();
}
}

View File

@@ -41,7 +41,7 @@ public class WebFluxCodeLensProviderTest {
}
@Test
public void testRoutesCodeLenses() throws Exception {
public void testRoutesCodeLensesSimpleCase() 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());
@@ -59,6 +59,42 @@ public class WebFluxCodeLensProviderTest {
assertTrue(containsCodeLens(codeLenses, "GET /quotes - Accept: application/json", 41, 29, 41, 40));
}
@Test
public void testRoutesCodeLensesNestedRoutes1() 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/PersonHandler1.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(3, codeLenses.size());
assertTrue(containsCodeLens(codeLenses, "GET /person/{id} - Accept: application/json", 9, 29, 9, 38));
assertTrue(containsCodeLens(codeLenses, "POST /person/ - Content-Type: application/json", 13, 29, 13, 41));
assertTrue(containsCodeLens(codeLenses, "GET /person - Accept: application/json", 17, 29, 17, 39));
}
@Test
public void testRoutesCodeLensesNestedRoutes2() 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/PersonHandler2.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(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));
}
private boolean containsCodeLens(List<? extends CodeLens> codeLenses, String commandTitle, int startLine, int startPosition, int endLine, int endPosition) {
for (CodeLens codeLens : codeLenses) {
Command command = codeLens.getCommand();

View File

@@ -15,6 +15,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
@@ -71,43 +72,43 @@ public class WebFluxMappingSymbolProviderTest {
WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "/hello", "GET").get(0);
assertEquals("/hello", handlerInfo1.getPath());
assertEquals("GET", handlerInfo1.getHttpMethod());
assertNull(handlerInfo1.getContentType());
assertEquals("TEXT_PLAIN", handlerInfo1.getAcceptType());
assertEquals("[GET]", Arrays.toString(handlerInfo1.getHttpMethods()));
assertEquals(0, handlerInfo1.getContentTypes().length);
assertEquals("[TEXT_PLAIN]", Arrays.toString(handlerInfo1.getAcceptTypes()));
assertEquals("org.test.QuoteHandler", handlerInfo1.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> hello(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo1.getHandlerMethod());
WebfluxHandlerInformation handlerInfo2 = getWebfluxHandler(addons, "/echo", "POST").get(0);
assertEquals("/echo", handlerInfo2.getPath());
assertEquals("POST", handlerInfo2.getHttpMethod());
assertEquals("TEXT_PLAIN", handlerInfo2.getContentType());
assertEquals("TEXT_PLAIN", handlerInfo2.getAcceptType());
assertEquals("[POST]", Arrays.toString(handlerInfo2.getHttpMethods()));
assertEquals("[TEXT_PLAIN]", Arrays.toString(handlerInfo2.getContentTypes()));
assertEquals("[TEXT_PLAIN]", Arrays.toString(handlerInfo2.getAcceptTypes()));
assertEquals("org.test.QuoteHandler", handlerInfo2.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> echo(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo2.getHandlerMethod());
WebfluxHandlerInformation handlerInfo3 = getWebfluxHandler(addons, "/quotes", "GET").get(0);
assertEquals("/quotes", handlerInfo3.getPath());
assertEquals("GET", handlerInfo3.getHttpMethod());
assertNull(handlerInfo3.getContentType());
assertEquals("APPLICATION_STREAM_JSON", handlerInfo3.getAcceptType());
assertEquals("[GET]", Arrays.toString(handlerInfo3.getHttpMethods()));
assertEquals(0, handlerInfo3.getContentTypes().length);
assertEquals("[APPLICATION_STREAM_JSON]", Arrays.toString(handlerInfo3.getAcceptTypes()));
assertEquals("org.test.QuoteHandler", handlerInfo3.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> streamQuotes(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo3.getHandlerMethod());
WebfluxHandlerInformation handlerInfo4 = getWebfluxHandler(addons, "/quotes", "GET").get(1);
assertEquals("/quotes", handlerInfo4.getPath());
assertEquals("GET", handlerInfo4.getHttpMethod());
assertNull(handlerInfo4.getContentType());
assertEquals("APPLICATION_JSON", handlerInfo4.getAcceptType());
assertEquals("[GET]", Arrays.toString(handlerInfo4.getHttpMethods()));
assertEquals(0, handlerInfo4.getContentTypes().length);
assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo4.getAcceptTypes()));
assertEquals("org.test.QuoteHandler", handlerInfo4.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> fetchQuotes(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo4.getHandlerMethod());
}
@Test
public void testNestedRoutesMappingSymbols() throws Exception {
public void testNestedRoutesMappingSymbols1() 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/NestedRouter.java").toUri().toString();
String docUri = directory.toPath().resolve("src/main/java/org/test/NestedRouter1.java").toUri().toString();
List<? extends SymbolInformation> symbols = getSymbols(docUri);
assertEquals(5, symbols.size());
assertTrue(containsSymbol(symbols, "@/person/{id} -- GET", docUri, 27, 6, 27, 45));
@@ -119,26 +120,66 @@ public class WebFluxMappingSymbolProviderTest {
WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "/person/{id}", "GET").get(0);
assertEquals("/person/{id}", handlerInfo1.getPath());
assertEquals("GET", handlerInfo1.getHttpMethod());
assertNull(handlerInfo1.getContentType());
assertEquals("APPLICATION_JSON", handlerInfo1.getAcceptType());
assertEquals("org.test.PersonHandler", handlerInfo1.getHandlerClass());
assertEquals("[GET]", Arrays.toString(handlerInfo1.getHttpMethods()));
assertEquals(0, handlerInfo1.getContentTypes().length);
assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo1.getAcceptTypes()));
assertEquals("org.test.PersonHandler1", 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, "/person/", "POST").get(0);
assertEquals("/person/", handlerInfo2.getPath());
assertEquals("POST", handlerInfo2.getHttpMethod());
assertEquals("APPLICATION_JSON", handlerInfo2.getContentType());
assertNull(handlerInfo2.getAcceptType());
assertEquals("org.test.PersonHandler", handlerInfo2.getHandlerClass());
assertEquals("[POST]", Arrays.toString(handlerInfo2.getHttpMethods()));
assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo2.getContentTypes()));
assertEquals(0, handlerInfo2.getAcceptTypes().length);
assertEquals("org.test.PersonHandler1", 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", "GET").get(0);
assertEquals("/person", handlerInfo3.getPath());
assertEquals("GET", handlerInfo3.getHttpMethod());
assertNull(handlerInfo3.getContentType());
assertEquals("APPLICATION_JSON", handlerInfo3.getAcceptType());
assertEquals("org.test.PersonHandler", handlerInfo3.getHandlerClass());
assertEquals("[GET]", Arrays.toString(handlerInfo3.getHttpMethods()));
assertEquals(0, handlerInfo3.getContentTypes().length);
assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo3.getAcceptTypes()));
assertEquals("org.test.PersonHandler1", handlerInfo3.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> listPeople(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo3.getHandlerMethod());
}
@Test
public void testNestedRoutesMappingSymbols2() 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/NestedRouter2.java").toUri().toString();
List<? extends SymbolInformation> symbols = getSymbols(docUri);
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));
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());
}
@@ -171,7 +212,7 @@ public class WebFluxMappingSymbolProviderTest {
return addons.stream()
.filter((obj) -> obj instanceof WebfluxHandlerInformation)
.map((obj -> (WebfluxHandlerInformation) obj))
.filter((addon) -> addon.getPath().equals(path) && addon.getHttpMethod().equals(httpMethod))
.filter((addon) -> addon.getPath().equals(path) && Arrays.asList(addon.getHttpMethods()).contains(httpMethod))
.collect(Collectors.toList());
}

View File

@@ -17,18 +17,17 @@ import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
@Configuration
public class RouterExperiments {
public class NestedRouter1 {
@Bean
public RouterFunction<ServerResponse> superRoutingFunction() {
PersonHandler handler = new PersonHandler();
public RouterFunction<ServerResponse> routingFunction1() {
PersonHandler1 handler = new PersonHandler1();
return nest(path("/super"),
nest(path("/something"),
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)));
).andRoute(POST("/").and(contentType(APPLICATION_JSON)), handler::createPerson));
}
}

View File

@@ -0,0 +1,35 @@
package org.test;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.http.MediaType.APPLICATION_PDF;
import static org.springframework.http.MediaType.TEXT_PLAIN;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import static org.springframework.web.reactive.function.server.RequestPredicates.contentType;
import static org.springframework.web.reactive.function.server.RequestPredicates.method;
import static org.springframework.web.reactive.function.server.RequestPredicates.path;
import static org.springframework.web.reactive.function.server.RouterFunctions.nest;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
@Configuration
public class NestedRouter2 {
@Bean
public RouterFunction<ServerResponse> routingFunction2() {
PersonHandler2 handler = new PersonHandler2();
return nest(accept(APPLICATION_JSON),
nest(path("/person"),
route(GET("/{id}"), handler::getPerson)
.andRoute(method(HttpMethod.GET).and(method(HttpMethod.HEAD)).and(accept(TEXT_PLAIN)), handler::listPeople)
).andRoute(POST("/").and(contentType(APPLICATION_JSON)).and(contentType(APPLICATION_PDF)), handler::createPerson));
}
}

View File

@@ -17,11 +17,11 @@ import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
@Configuration
public class NestedRouter {
public class NestedRouter3 {
@Bean
public RouterFunction<ServerResponse> routingFunction() {
PersonHandler handler = new PersonHandler();
PersonHandler3 handler = new PersonHandler3();
return nest(path("/person"),
nest(accept(APPLICATION_JSON),

View File

@@ -5,7 +5,7 @@ import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
public class PersonHandler {
public class PersonHandler1 {
public Mono<ServerResponse> getPerson(ServerRequest request) {
return ServerResponse.notFound().build();

View File

@@ -0,0 +1,22 @@
package org.test;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
public class PersonHandler2 {
public Mono<ServerResponse> getPerson(ServerRequest request) {
return ServerResponse.notFound().build();
}
public Mono<ServerResponse> createPerson(ServerRequest request) {
return ServerResponse.notFound().build();
}
public Mono<ServerResponse> listPeople(ServerRequest request) {
return ServerResponse.notFound().build();
}
}

View File

@@ -0,0 +1,22 @@
package org.test;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
public class PersonHandler3 {
public Mono<ServerResponse> getPerson(ServerRequest request) {
return ServerResponse.notFound().build();
}
public Mono<ServerResponse> createPerson(ServerRequest request) {
return ServerResponse.notFound().build();
}
public Mono<ServerResponse> listPeople(ServerRequest request) {
return ServerResponse.notFound().build();
}
}