take content and accept types into account for annotation-defined request mapping symbols

This commit is contained in:
Martin Lippert
2018-03-12 14:35:04 +01:00
parent 62f975d74c
commit 36ddd52f82
6 changed files with 167 additions and 46 deletions

View File

@@ -47,10 +47,8 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
String[] path = getPath(node);
String[] parentPath = getParentPath(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[] contentTypes = getContentTypes(node);
String[] acceptTypes = getAcceptTypes(node);
return (parentPath == null ? Stream.of("") : Arrays.stream(parentPath)).filter(Objects::nonNull)
.flatMap(parent -> (path == null ? Stream.<String>empty() : Arrays.stream(path))
@@ -175,6 +173,44 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
}
return null;
}
private String[] getAcceptTypes(Annotation node) {
if (node.isNormalAnnotation()) {
NormalAnnotation normNode = (NormalAnnotation) node;
List<?> values = normNode.values();
for (Iterator<?> iterator = values.iterator(); iterator.hasNext();) {
Object object = iterator.next();
if (object instanceof MemberValuePair) {
MemberValuePair pair = (MemberValuePair) object;
String valueName = pair.getName().getIdentifier();
if (valueName != null && valueName.equals("consumes")) {
Expression expression = pair.getValue();
return ASTUtils.getExpressionValueAsArray(expression);
}
}
}
}
return new String[0];
}
private String[] getContentTypes(Annotation node) {
if (node.isNormalAnnotation()) {
NormalAnnotation normNode = (NormalAnnotation) node;
List<?> values = normNode.values();
for (Iterator<?> iterator = values.iterator(); iterator.hasNext();) {
Object object = iterator.next();
if (object instanceof MemberValuePair) {
MemberValuePair pair = (MemberValuePair) object;
String valueName = pair.getName().getIdentifier();
if (valueName != null && valueName.equals("produces")) {
Expression expression = pair.getValue();
return ASTUtils.getExpressionValueAsArray(expression);
}
}
}
}
return new String[0];
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc) {

View File

@@ -26,6 +26,12 @@ public class RouteUtils {
if (path != null && path.length() > 0) {
String label = "@" + (path.startsWith("/") ? path : ("/" + path));
label += (httpMethods == null || httpMethods.length == 0 ? "" : " -- " + WebfluxUtils.getStringRep(httpMethods, string -> string));
String acceptType = WebfluxUtils.getStringRep(acceptTypes, WebfluxUtils::getMediaType);
label += acceptType != null ? " - Accept: " + acceptType : "";
String contentType = WebfluxUtils.getStringRep(contentTypes, WebfluxUtils::getMediaType);
label += contentType != null ? " - Content-Type: " + contentType : "";
return new EnhancedSymbolInformation(new SymbolInformation(label, SymbolKind.Interface, location), enhancedInformation);
}

View File

@@ -104,6 +104,10 @@ public class WebfluxUtils {
}
try {
if (constantRep.endsWith("_VALUE")) {
constantRep = constantRep.substring(0, constantRep.lastIndexOf("_VALUE"));
}
MediaTypeMapping mediaType = MediaTypeMapping.valueOf(constantRep);
return mediaType.getMediaType();
}

View File

@@ -38,7 +38,6 @@ public class RequestMappingSymbolProviderTest {
@Test
public void testSimpleRequestMappingSymbol() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/SimpleMappingClass.java").toUri().toString();
@@ -50,7 +49,6 @@ public class RequestMappingSymbolProviderTest {
@Test
public void testParentRequestMappingSymbol() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/ParentMappingClass.java").toUri().toString();
@@ -62,7 +60,6 @@ public class RequestMappingSymbolProviderTest {
@Test
public void testEmptyPathWithParentRequestMappingSymbol() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/ParentMappingClass2.java").toUri().toString();
@@ -74,7 +71,6 @@ public class RequestMappingSymbolProviderTest {
@Test
public void testMultiRequestMappingSymbol() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/MultiRequestMappingClass.java").toUri().toString();
@@ -87,7 +83,6 @@ public class RequestMappingSymbolProviderTest {
@Test
public void testGetMappingSymbol() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString();
@@ -98,7 +93,6 @@ public class RequestMappingSymbolProviderTest {
@Test
public void testDeleteMappingSymbol() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString();
@@ -109,7 +103,6 @@ public class RequestMappingSymbolProviderTest {
@Test
public void testPostMappingSymbol() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString();
@@ -120,7 +113,6 @@ public class RequestMappingSymbolProviderTest {
@Test
public void testPutMappingSymbol() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString();
@@ -131,7 +123,6 @@ public class RequestMappingSymbolProviderTest {
@Test
public void testPatchMappingSymbol() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString();
@@ -142,7 +133,6 @@ public class RequestMappingSymbolProviderTest {
@Test
public void testGetRequestMappingSymbol() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString();
@@ -153,13 +143,31 @@ public class RequestMappingSymbolProviderTest {
@Test
public void testMultiRequestMethodMappingSymbol() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMethodClass.java").toUri().toString();
List<? extends SymbolInformation> symbols = getSymbols(docUri);
assertTrue(containsSymbol(symbols, "@/postAndPutHello -- POST,PUT", docUri, 36, 1, 36, 76));
}
@Test
public void testMediaTypes() throws Exception {
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI()));
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-request-mapping-symbols/").toURI());
String docUri = directory.toPath().resolve("src/main/java/org/test/RequestMappingMediaTypes.java").toUri().toString();
List<? extends SymbolInformation> symbols = getSymbols(docUri);
assertEquals(7, symbols.size());
assertTrue(containsSymbol(symbols, "@/consume1 -- HEAD - Accept: testconsume", docUri, 8, 1, 8, 90));
assertTrue(containsSymbol(symbols, "@/consume2 - Accept: text/plain", docUri, 13, 1, 13, 73));
assertTrue(containsSymbol(symbols, "@/consume3 - Accept: text/plain,testconsumetype", docUri, 18, 1, 18, 94));
assertTrue(containsSymbol(symbols, "@/produce1 - Content-Type: testproduce", docUri, 23, 1, 23, 60));
assertTrue(containsSymbol(symbols, "@/produce2 - Content-Type: text/plain", docUri, 28, 1, 28, 73));
assertTrue(containsSymbol(symbols, "@/produce3 - Content-Type: text/plain,testproducetype", docUri, 33, 1, 33, 94));
assertTrue(containsSymbol(symbols, "@/everything - Accept: application/json,text/plain,testconsume - Content-Type: application/json", docUri, 38, 1, 38, 170));
}
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();) {

View File

@@ -62,10 +62,10 @@ public class WebFluxMappingSymbolProviderTest {
String docUri = directory.toPath().resolve("src/main/java/org/test/QuoteRouter.java").toUri().toString();
List<? extends SymbolInformation> symbols = getSymbols(docUri);
assertEquals(6, symbols.size());
assertTrue(containsSymbol(symbols, "@/hello -- GET", docUri, 22, 5, 22, 70));
assertTrue(containsSymbol(symbols, "@/echo -- POST", docUri, 23, 5, 23, 101));
assertTrue(containsSymbol(symbols, "@/quotes -- GET", docUri, 24, 5, 24, 86));
assertTrue(containsSymbol(symbols, "@/quotes -- GET", docUri, 25, 5, 25, 94));
assertTrue(containsSymbol(symbols, "@/hello -- GET - Accept: text/plain", docUri, 22, 5, 22, 70));
assertTrue(containsSymbol(symbols, "@/echo -- POST - Accept: text/plain - Content-Type: text/plain", docUri, 23, 5, 23, 101));
assertTrue(containsSymbol(symbols, "@/quotes -- GET - Accept: application/json", docUri, 24, 5, 24, 86));
assertTrue(containsSymbol(symbols, "@/quotes -- GET - Accept: application/stream+json", docUri, 25, 5, 25, 94));
List<? extends Object> addons = getAdditionalInformation(docUri);
assertEquals(4, addons.size());
@@ -111,9 +111,9 @@ public class WebFluxMappingSymbolProviderTest {
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));
assertTrue(containsSymbol(symbols, "@/person/ -- POST", docUri, 29, 6, 29, 83));
assertTrue(containsSymbol(symbols, "@/person -- GET", docUri, 28, 7, 28, 60));
assertTrue(containsSymbol(symbols, "@/person/{id} -- GET - Accept: application/json", docUri, 27, 6, 27, 45));
assertTrue(containsSymbol(symbols, "@/person/ -- POST - Content-Type: application/json", docUri, 29, 6, 29, 83));
assertTrue(containsSymbol(symbols, "@/person -- GET - Accept: application/json", docUri, 28, 7, 28, 60));
List<? extends Object> addons = getAdditionalInformation(docUri);
assertEquals(3, addons.size());
@@ -151,9 +151,9 @@ public class WebFluxMappingSymbolProviderTest {
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));
assertTrue(containsSymbol(symbols, "@/person/{id} -- GET - Accept: application/json", docUri, 29, 6, 29, 45));
assertTrue(containsSymbol(symbols, "@/ -- POST - Accept: application/json - Content-Type: application/json,application/pdf", docUri, 31, 6, 31, 117));
assertTrue(containsSymbol(symbols, "@/person -- GET,HEAD - Accept: text/plain,application/json", docUri, 30, 7, 30, 113));
List<? extends Object> addons = getAdditionalInformation(docUri);
assertEquals(3, addons.size());
@@ -192,40 +192,63 @@ public class WebFluxMappingSymbolProviderTest {
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/{id} -- GET - Accept: application/json", docUri, 29, 7, 29, 46));
assertTrue(containsSymbol(symbols, "@/person/sub1/sub2 -- GET - Accept: application/json", 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, "@/person/ -- POST - Content-Type: application/json", 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());
assertEquals(6, addons.size());
WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "/person/{id}", "GET").get(0);
assertEquals("/person/{id}", handlerInfo1.getPath());
WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "/person/sub1/sub2/{id}", "GET").get(0);
assertEquals("/person/sub1/sub2/{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("org.test.PersonHandler3", 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()));
WebfluxHandlerInformation handlerInfo2 = getWebfluxHandler(addons, "/person/sub1/sub2", "GET").get(0);
assertEquals("/person/sub1/sub2", handlerInfo2.getPath());
assertEquals("[GET]", Arrays.toString(handlerInfo2.getHttpMethods()));
assertEquals(0, handlerInfo2.getContentTypes().length);
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());
assertEquals("org.test.PersonHandler3", handlerInfo1.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> listPeople(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()));
WebfluxHandlerInformation handlerInfo3 = getWebfluxHandler(addons, "/person/sub1/sub2/nestedGet", "GET").get(0);
assertEquals("/person/sub1/sub2/nestedGet", handlerInfo3.getPath());
assertEquals("[GET]", 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());
*/
assertEquals(0, handlerInfo3.getAcceptTypes().length);
assertEquals("org.test.PersonHandler3", handlerInfo1.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> getPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo3.getHandlerMethod());
WebfluxHandlerInformation handlerInfo4 = getWebfluxHandler(addons, "/person/sub1/andNestPath/andNestPathGET", "GET").get(0);
assertEquals("/person/sub1/andNestPath/andNestPathGET", handlerInfo4.getPath());
assertEquals("[GET]", Arrays.toString(handlerInfo4.getHttpMethods()));
assertEquals(0, handlerInfo4.getContentTypes().length);
assertEquals(0, handlerInfo4.getAcceptTypes().length);
assertEquals("org.test.PersonHandler3", handlerInfo4.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> getPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo4.getHandlerMethod());
WebfluxHandlerInformation handlerInfo5 = getWebfluxHandler(addons, "/person/", "POST").get(0);
assertEquals("/person/", handlerInfo5.getPath());
assertEquals("[POST]", Arrays.toString(handlerInfo5.getHttpMethods()));
assertEquals("[APPLICATION_JSON]", Arrays.toString(handlerInfo5.getContentTypes()));
assertEquals(0, handlerInfo5.getAcceptTypes().length);
assertEquals("org.test.PersonHandler3", handlerInfo5.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> createPerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo5.getHandlerMethod());
WebfluxHandlerInformation handlerInfo6 = getWebfluxHandler(addons, "/nestedDelete", "DELETE").get(0);
assertEquals("/nestedDelete", handlerInfo6.getPath());
assertEquals("[DELETE]", Arrays.toString(handlerInfo6.getHttpMethods()));
assertEquals(0, handlerInfo6.getContentTypes().length);
assertEquals(0, handlerInfo6.getAcceptTypes().length);
assertEquals("org.test.PersonHandler3", handlerInfo6.getHandlerClass());
assertEquals("public Mono<org.springframework.web.reactive.function.server.ServerResponse> deletePerson(org.springframework.web.reactive.function.server.ServerRequest)", handlerInfo6.getHandlerMethod());
}
private boolean containsSymbol(List<? extends SymbolInformation> symbols, String name, String uri, int startLine, int startCHaracter, int endLine, int endCharacter) {

View File

@@ -0,0 +1,44 @@
package org.test;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
public class RequestMappingMediaTypes {
@RequestMapping(path="/consume1", consumes = "testconsume", method= {RequestMethod.HEAD})
public String consume1() {
return "Hello";
}
@RequestMapping(path="/consume2", consumes = MediaType.TEXT_PLAIN_VALUE)
public String consume2() {
return "Hello";
}
@RequestMapping(path="/consume3", consumes = {MediaType.TEXT_PLAIN_VALUE, "testconsumetype"})
public String consume3() {
return "Hello";
}
@RequestMapping(path="/produce1", produces = "testproduce")
public String produce1() {
return "Hello";
}
@RequestMapping(path="/produce2", produces = MediaType.TEXT_PLAIN_VALUE)
public String produce2() {
return "Hello";
}
@RequestMapping(path="/produce3", produces = {MediaType.TEXT_PLAIN_VALUE, "testproducetype"})
public String produce3() {
return "Hello";
}
@RequestMapping(path="/everything", consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE, "testconsume"}, produces=MediaType.APPLICATION_JSON_VALUE)
public String everything() {
return "Hello";
}
}