Merge branch 'master' into jdt-classpath

This commit is contained in:
Kris De Volder
2018-03-13 10:06:42 -07:00
125 changed files with 1910 additions and 838 deletions

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../commons/pom.xml</relativePath>
</parent>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -76,8 +76,8 @@ public class GradleCore {
*/
((DefaultGradleConnector) gradleConnector).daemonMaxIdleTime(1, TimeUnit.SECONDS);
configuration.configure(gradleConnector);
// Use patched Gradle 4.3 distribution as a workaround for https://github.com/gradle/gradle/issues/2483
gradleConnector.useDistribution(URI.create("http://s3-test.spring.io/sts4/custom-gradle-builds/gradle-4.3-build.zip"));
// Use patched Gradle 4.4 distribution or higher as a workaround for https://github.com/gradle/gradle/issues/2483
gradleConnector.useGradleVersion("4.6");
connection = gradleConnector.connect();
return connection.getModel(modelType);
} catch (GradleConnectionException e) {

View File

@@ -83,7 +83,7 @@ public class GradleProjectTest {
@Test
public void outputFolder() throws Exception {
GradleJavaProject project = getGradleProject("test-app-1");
assertTrue(project.getClasspath().getOutputFolder().endsWith("bin"));
assertTrue(project.getClasspath().getOutputFolder().toString().contains("/bin"));
}
@Test

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016-2018 Pivotal, Inc.
* Copyright (c) 2016, 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
@@ -31,12 +31,14 @@ import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguage
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
import org.springframework.ide.vscode.commons.languageserver.util.SortKeys;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.Renderable;
import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonPrimitive;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
@@ -46,6 +48,8 @@ import reactor.core.scheduler.Schedulers;
*/
public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
private static final Supplier<Logger> LOG = Suppliers.memoize(() -> LoggerFactory.getLogger(VscodeCompletionEngineAdapter.class));
public static class LazyCompletionResolver {
private int nextId = 0; //Used to assign unique id to completion items.
@@ -64,7 +68,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
try {
resolveItem(doc, completion, unresolved);
} catch (Exception e) {
Log.log(e);
LOG.get().error("{}", e);
}
});
return id;
@@ -73,12 +77,12 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
public synchronized void resolveNow(CompletionItem unresolved) {
Object id = unresolved.getData();
if (id!=null) {
Consumer<CompletionItem> resolver = resolvers.get(id);
Consumer<CompletionItem> resolver = resolvers.get(id instanceof JsonPrimitive ? ((JsonPrimitive)id).getAsString() : id);
if (resolver!=null) {
resolver.accept(unresolved);
unresolved.setData(null); //No longer needed after item is resolved.
} else {
Log.warn("Couldn't resolve completion item. Did it already get flushed from the resolver's cache? "+unresolved.getLabel());
LOG.get().warn("Couldn't resolve completion item. Did it already get flushed from the resolver's cache? "+unresolved.getLabel());
}
}
}
@@ -225,7 +229,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
return Optional.of(vscodeEdit);
}
} catch (Exception e) {
Log.log(e);
LOG.get().error("{}", e);
return Optional.empty();
}
}
@@ -241,7 +245,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
return StringUtil.stripIndentation(refIndent, newText);
}
} catch (BadLocationException e) {
Log.log(e);
LOG.get().error("{}", e);
}
return newText;
}

View File

@@ -238,7 +238,6 @@ public class SimpleLanguageServer implements Sts4LanguageServer, LanguageClientA
if (ih!=null){
ih.accept(params);
}
Log.info("IntializeResult = {}");
return CompletableFuture.completedFuture(result);
}

View File

@@ -10,7 +10,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -6,7 +6,7 @@
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<packaging>pom</packaging>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<name>commons-parent</name>
<modules>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../commons/pom.xml</relativePath>
</parent>

View File

@@ -401,8 +401,11 @@ public class PipelineYmlSchema implements YamlSchema {
addProp(resourceType, "source", resourceSource);
addProp(resourceType, "privileged", t_boolean);
YType t_group_name_def= f.yatomic("Group Name")
.parseWith(ValueParsers.NE_STRING);
AbstractType group = f.ybean("Group");
addProp(group, "name", t_ne_string).isPrimary(true);
addProp(group, "name", t_group_name_def).isPrimary(true);
addProp(group, "resources", f.yseq(t_resource_name));
addProp(group, "jobs", f.yseq(t_job_name));
@@ -414,7 +417,8 @@ public class PipelineYmlSchema implements YamlSchema {
definitionTypes = ImmutableList.of(
jobNameDef,
resourceTypeNameDef,
t_resource_name_def
t_resource_name_def,
t_group_name_def
);
initializeDefaultResourceTypes();

View File

@@ -17,5 +17,5 @@ plan:
get: string
```
*Required.* The logical name of the resource being fetched. This name satisfies logical inputs to a [Task](https://concourse.ci/concepts.html#tasks), and may be referenced within the plan itself (e.g. in the `file` attribute of a `task` step).
*Required.* The logical name of the resource being fetched. This name satisfies logical inputs to a [Task](https://concourse-ci.org/concepts.html#tasks), and may be referenced within the plan itself (e.g. in the `file` attribute of a `task` step).

View File

@@ -4,4 +4,4 @@ If set to `latest`, scheduling will just find the latest available version of a
If set to `every`, builds will walk through all available versions of the resource. Note that if `passed` is also configured, it will only step through the versions satisfying the constraints.
If set to a specific version (e.g. `{ref: abcdef123}`), only that version will be used. Note that the version must be available and detected by the resource, otherwise the input will never be satisfied. You may want to use [check-resource](https://concourse.ci/fly-check-resource.html) to force detection of resource versions, if you need to use an older one that was never detected (as all newly configured resources start from the latest version).
If set to a specific version (e.g. `{ref: abcdef123}`), only that version will be used. Note that the version must be available and detected by the resource, otherwise the input will never be satisfied. You may want to use [check-resource](https://concourse-ci.org/fly-check-resource.html) to force detection of resource versions, if you need to use an older one that was never detected (as all newly configured resources start from the latest version).

View File

@@ -3,8 +3,8 @@ to the specified files are ignored.
Note that if you want to push commits that change these files via a `put`,
the commit will still be "detected", as [`check` and `put` both introduce
versions](https://concourse.ci/pipeline-mechanics.html#collecting-versions).
versions](https://concourse-ci.org/pipeline-mechanics.html#collecting-versions).
To avoid this you should define a second resource that you use for commits
that change files that you don't want to feed back into your pipeline - think
of one as read-only (with `ignore_paths`) and one as write-only (which
shouldn't need it).
shouldn't need it).

View File

@@ -1,3 +1,3 @@
*Optional.* Password for HTTP(S) auth when pulling/pushing.
Note: You can also use pipeline templating to hide this password in source control. (For more information: https://concourse.ci/fly-set-pipeline.html)
Note: You can also use pipeline templating to hide this password in source control. (For more information: https://concourse-ci.org/fly-set-pipeline.html)

View File

@@ -9,4 +9,4 @@ Example:
DWiJL+OFeg9kawcUL6hQ8JeXPhlImG6RTUffma9+iGQyyBMCGd1l
-----END RSA PRIVATE KEY-----
Note: You can also use pipeline templating to hide this private key in source control. (For more information: https://concourse.ci/fly-set-pipeline.html)
Note: You can also use pipeline templating to hide this private key in source control. (For more information: https://concourse-ci.org/fly-set-pipeline.html)

View File

@@ -17,5 +17,5 @@ A simple grouping for the pipeline above may look like:
This would display two tabs at the top of the home page: "tests" and "deploy". Once you have added groups to your pipeline then all jobs must be in a group otherwise they will not be visible.
For a real world example of how groups can be used to simplify navigation and provide logical grouping, see the groups used at the top of the page in the [Concourse pipeline](https://ci.concourse.ci/).
For a real world example of how groups can be used to simplify navigation and provide logical grouping, see the groups used at the top of the page in the [Concourse pipeline](https://ci.concourse-ci.org/).

View File

@@ -1,7 +1,7 @@
Pushes to the given [Resource](https://concourse.ci/concepts.html#resources).
Pushes to the given [Resource](https://concourse-ci.org/concepts.html#resources).
All artifacts collected during the plan's execution will be available in the working directory.
For example, the following plan fetches a repo using [get](https://concourse.ci/get-step.html) and pushes it to another repo (assuming `repo-develop` and `repo-master` are defined as `git` resources):
For example, the following plan fetches a repo using [get](https://concourse-ci.org/get-step.html) and pushes it to another repo (assuming `repo-develop` and `repo-master` are defined as `git` resources):
```
plan:
@@ -34,4 +34,4 @@ plan:
put: string
```
Required. The logical name of the resource being pushed. The pushed resource will be available under this name after the push succeeds.
Required. The logical name of the resource being pushed. The pushed resource will be available under this name after the push succeeds.

View File

@@ -1,3 +1,3 @@
*Optional.* Defaults to `name`.
The resource to update, as configured in [resources](https://concourse.ci/configuring-resources.html).
The resource to update, as configured in [resources](https://concourse-ci.org/configuring-resources.html).

View File

@@ -1 +1 @@
*Required.* The name of the resource. This should be short and simple. This name will be referenced by [build plans](https://concourse.ci/build-plans.html) of jobs in the pipeline.
*Required.* The name of the resource. This should be short and simple. This name will be referenced by [build plans](https://concourse-ci.org/build-plans.html) of jobs in the pipeline.

View File

@@ -19,4 +19,4 @@ The following example configures the task to use the `golang:1.6` Docker image:
You can use any resource that returns a filesystem in the correct format (a `/rootfs` directory and a `metadata.json` file in the top level) but normally this will be the [Docker Image resource](https://github.com/concourse/docker-image-resource). If you'd like to make a resource of your own that supports this please use that as a reference implementation for now.
If you want to use an artifact source within the plan containing an image, you must set the [image](https://concourse.ci/task-step.html#task-image) in the plan step instead.
If you want to use an artifact source within the plan containing an image, you must set the [image](https://concourse-ci.org/task-step.html#task-image) in the plan step instead.

View File

@@ -1,3 +1,3 @@
*Required.* The expected set of inputs for the task.
This determines which artifacts will propagate into the task, as the [build plan](https://concourse.ci/build-plans.html) executes. If any specified inputs are not present, the task will end with an error, without running.
This determines which artifacts will propagate into the task, as the [build plan](https://concourse-ci.org/build-plans.html) executes. If any specified inputs are not present, the task will end with an error, without running.

View File

@@ -1,6 +1,6 @@
*Optional.* The artifacts produced by the task.
Each output configures a directory to make available to later steps in the [build plan](https://concourse.ci/build-plans.html). The directory will be automatically created before the task runs, and the task should place any artifacts it wants to export in the directory.
Each output configures a directory to make available to later steps in the [build plan](https://concourse-ci.org/build-plans.html). The directory will be automatically created before the task runs, and the task should place any artifacts it wants to export in the directory.
For example, the following task and script would be used to propagate a built binary to later steps:

View File

@@ -1,4 +1,4 @@
Executes a [Task](https://concourse.ci/concepts.html#tasks), either from a file fetched via the preceding steps, or with inlined configuration.
Executes a [Task](https://concourse-ci.org/concepts.html#tasks), either from a file fetched via the preceding steps, or with inlined configuration.
task: string

View File

@@ -3458,15 +3458,20 @@ public class ConcourseEditorTest {
"- name: bar-resource\n" +
"jobs:\n" +
"- name: do-some-stuff\n" +
"- name: do-more-stuff\n"
"- name: do-more-stuff\n" +
"groups:\n" +
"- name: group-one\n" +
"- name: group-two\n"
);
editor.assertDocumentSymbols(
editor.assertDocumentSymbols(
"some-resource-type|ResourceType",
"foo-resource|Resource",
"bar-resource|Resource",
"do-some-stuff|Job",
"do-more-stuff|Job"
"do-more-stuff|Job",
"group-one|Group",
"group-two|Group"
);
}

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../commons/pom.xml</relativePath>
</parent>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.1.5-SNAPSHOT</version>
<version>0.1.6-SNAPSHOT</version>
<relativePath>../commons/pom.xml</relativePath>
</parent>

View File

@@ -0,0 +1,52 @@
/*******************************************************************************
* 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;
/**
* @author Martin Lippert
*/
public enum MediaTypeMapping {
ALL("*/*"),
APPLICATION_ATOM_XML("application/atom+xml"),
APPLICATION_FORM_URLENCODED("application/x-www-form-urlencoded"),
APPLICATION_JSON("application/json"),
APPLICATION_JSON_UTF8("application/json;charset=UTF-8"),
APPLICATION_OCTET_STREAM("application/octet-stream"),
APPLICATION_PDF("application/pdf"),
APPLICATION_PROBLEM_JSON("application/problem+json"),
APPLICATION_PROBLEM_JSON_UTF8("application/problem+json;charset=UTF-8"),
APPLICATION_PROBLEM_XML("application/problem+xml"),
APPLICATION_RSS_XML("application/rss+xml"),
APPLICATION_STREAM_JSON("application/stream+json"),
APPLICATION_XHTML_XML("application/xhtml+xml"),
APPLICATION_XML("application/xml"),
IMAGE_GIF("image/gif"),
IMAGE_JPEG("image/jpeg"),
IMAGE_PNG("image/png"),
MULTIPART_FORM_DATA("multipart/form-data"),
TEXT_EVENT_STREAM("text/event-stream"),
TEXT_HTML("text/html"),
TEXT_MARKDOWN("text/markdown"),
TEXT_PLAIN("text/plain"),
TEXT_XML("text/xml");
private String mediaType;
private MediaTypeMapping(String mediaType) {
this.mediaType = mediaType;
}
public String getMediaType() {
return mediaType;
}
}

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,9 @@ 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 methodStr = method == null || method.length == 0 ? "" : String.join(",", method);
String[] methods = getMethod(node);
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))
@@ -62,8 +60,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();
@@ -176,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

@@ -0,0 +1,44 @@
/*******************************************************************************
* 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));
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);
}
else {
return null;
}
}
}

View File

@@ -0,0 +1,52 @@
/*******************************************************************************
* 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 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;
/**
* @author Martin Lippert
*/
public class WebfluxAcceptTypeFinder extends ASTVisitor {
private Set<String> acceptTypes;
public WebfluxAcceptTypeFinder() {
this.acceptTypes = new LinkedHashSet<>();
}
public Set<String> getAcceptTypes() {
return acceptTypes;
}
@Override
public boolean visit(MethodInvocation node) {
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)) {
String acceptType = WebfluxUtils.extractSimpleNameArgument(node);
if (acceptType != null) {
acceptTypes.add(acceptType);
}
}
}
return !WebfluxUtils.isRouteMethodInvocation(methodBinding);
}
}

View File

@@ -0,0 +1,62 @@
/*******************************************************************************
* 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 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;
import org.eclipse.jdt.core.dom.MethodInvocation;
/**
* @author Martin Lippert
*/
public class WebfluxContentTypeFinder extends ASTVisitor {
private Set<String> contentTypes;
private ASTNode root;
public WebfluxContentTypeFinder(ASTNode root) {
this.root = root;
this.contentTypes = new LinkedHashSet<>();
}
public Set<String> getContentTypes() {
return contentTypes;
}
@Override
public boolean visit(MethodInvocation node) {
boolean visitChildren = true;
if (node != this.root) {
IMethodBinding methodBinding = node.resolveMethodBinding();
if (WebfluxUtils.REQUEST_PREDICATES_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) {
String name = methodBinding.getName();
if (name != null && WebfluxUtils.REQUEST_PREDICATE_CONTENT_TYPE_METHOD.equals(name)) {
String contentType = WebfluxUtils.extractSimpleNameArgument(node);
if (contentType != null) {
contentTypes.add(contentType);
}
}
}
if (WebfluxUtils.isRouteMethodInvocation(methodBinding)) {
visitChildren = false;
}
}
return visitChildren;
}
}

View File

@@ -71,7 +71,19 @@ public class WebfluxHandlerCodeLensProvider implements CodeLensProvider {
CodeLens codeLens = new CodeLens();
codeLens.setRange(document.toRange(node.getName().getStartPosition(), node.getName().getLength()));
codeLens.setCommand(new Command(handlerInfo.getSymbol(), null));
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 : "";
String contentType = WebfluxUtils.getStringRep(handlerInfo.getContentTypes(), WebfluxUtils::getMediaType);
codeLensCommand += contentType != null ? " - Content-Type: " + contentType : "";
codeLens.setCommand(new Command(codeLensCommand, null));
resultAccumulator.add(codeLens);
} catch (BadLocationException e) {
@@ -81,5 +93,5 @@ public class WebfluxHandlerCodeLensProvider implements CodeLensProvider {
}
}
}
}

View File

@@ -15,18 +15,22 @@ package org.springframework.ide.vscode.boot.java.requestmapping;
*/
public class WebfluxHandlerInformation {
private final String symbol;
private String handlerClass;
private String handlerMethod;
private final String handlerClass;
private final String handlerMethod;
public WebfluxHandlerInformation(String symbol, String handlerClass, String handlerMethod) {
this.symbol = symbol;
private final String path;
private final String[] httpMethods;
private final String[] contentTypes;
private final String[] acceptTypes;
public WebfluxHandlerInformation(String handlerClass, String handlerMethod, String path, String[] httpMethods, String[] contentTypes, String[] acceptTypes) {
this.handlerClass = handlerClass;
this.handlerMethod = handlerMethod;
}
public String getSymbol() {
return symbol;
this.path = path;
this.httpMethods = httpMethods;
this.contentTypes = contentTypes;
this.acceptTypes = acceptTypes;
}
public String getHandlerClass() {
@@ -36,5 +40,21 @@ public class WebfluxHandlerInformation {
public String getHandlerMethod() {
return handlerMethod;
}
public String getPath() {
return path;
}
public String[] getHttpMethods() {
return httpMethods;
}
public String[] getContentTypes() {
return contentTypes;
}
public String[] getAcceptTypes() {
return acceptTypes;
}
}

View File

@@ -10,28 +10,29 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.requestmapping;
import java.util.List;
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;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.QualifiedName;
/**
* @author Martin Lippert
*/
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
@@ -44,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 = extractMethodValue(node);
methods.add(WebfluxUtils.extractQualifiedNameArgument(node));
}
}
@@ -58,18 +59,4 @@ public class WebfluxMethodFinder extends ASTVisitor {
return visitChildren;
}
private String extractMethodValue(MethodInvocation node) {
List<?> arguments = node.arguments();
if (arguments != null && arguments.size() > 0) {
Object object = arguments.get(0);
if (object instanceof QualifiedName) {
QualifiedName qualifiedName = (QualifiedName) object;
if (qualifiedName.getName() != null) {
return qualifiedName.getName().toString();
}
}
}
return null;
}
}

View File

@@ -41,7 +41,7 @@ public class WebfluxPathFinder extends ASTVisitor {
if (WebfluxUtils.REQUEST_PREDICATES_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) {
String name = methodBinding.getName();
if (name != null && WebfluxUtils.REQUEST_PREDICATE_ALL_PATH_METHODS.contains(name)) {
path = WebfluxUtils.extractPath(node);
path = WebfluxUtils.extractStringLiteralArgument(node);
}
}

View File

@@ -13,6 +13,8 @@ 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;
import org.eclipse.jdt.core.dom.ASTVisitor;
@@ -26,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;
@@ -87,40 +87,134 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider {
}
protected void extractMappingSymbol(MethodInvocation node, TextDocument doc, List<EnhancedSymbolInformation> result) {
String foundPath = extractPathFromRouterFunction(node);
String path = extractPath(node, foundPath);
String httpMethod = extractMethod(node);
String path = extractPath(node);
String[] httpMethods = extractMethods(node);
String[] contentTypes = extractContentTypes(node);
String[] acceptTypes = extractAcceptTypes(node);
int methodNameStart = node.getName().getStartPosition();
int invocationStart = node.getStartPosition();
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);
WebfluxHandlerInformation handler = extractHandlerInformation(node, label);
result.add(new EnhancedSymbolInformation(new SymbolInformation(label, SymbolKind.Interface, location), handler));
Location location = new Location(doc.getUri(), doc.toRange(methodNameStart, node.getLength() - (methodNameStart - invocationStart)));
WebfluxHandlerInformation handler = extractHandlerInformation(node, path, httpMethods, contentTypes, acceptTypes);
result.add(RouteUtils.createRouteSymbol(location, path, httpMethods, contentTypes, acceptTypes, handler));
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
private String extractPathFromRouterFunction(MethodInvocation routerInvocation) {
private String extractPath(MethodInvocation routerInvocation) {
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);
}
extractNestedValue(routerInvocation, path, (methodInvocation) -> {
IMethodBinding methodBinding = methodInvocation.resolveMethodBinding();
String methodName = methodBinding.getName();
if (WebfluxUtils.REQUEST_PREDICATE_PATH_METHOD.equals(methodName)) {
String additionalPath = WebfluxUtils.extractStringLiteralArgument(methodInvocation);
if (additionalPath != null && additionalPath.length() > 0) {
return additionalPath;
}
}
return null;
});
StringBuilder result = new StringBuilder();
path.stream().forEach(part -> result.insert(0, part));
return result.toString();
return path;
}
private String extractPath(ASTNode node, String path) {
private String[] extractMethods(MethodInvocation routerInvocation) {
WebfluxMethodFinder methodFinder = new WebfluxMethodFinder(routerInvocation);
List<?> arguments = routerInvocation.arguments();
for (Object argument : arguments) {
if (argument != null && argument instanceof ASTNode) {
((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.extractQualifiedNameArgument(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);
}
}
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)) {
return WebfluxUtils.extractSimpleNameArgument(methodInvocation);
}
return null;
});
return (String[]) acceptTypes.toArray(new String[acceptTypes.size()]);
}
private String[] extractContentTypes(MethodInvocation routerInvocation) {
WebfluxContentTypeFinder contentTypeFinder = new WebfluxContentTypeFinder(routerInvocation);
List<?> arguments = routerInvocation.arguments();
for (Object argument : arguments) {
if (argument != null && argument instanceof ASTNode) {
((ASTNode)argument).accept(contentTypeFinder);
}
}
Set<String> contentTypes = contentTypeFinder.getContentTypes();
extractNestedValue(routerInvocation, contentTypes, (methodInvocation) -> {
IMethodBinding methodBinding = methodInvocation.resolveMethodBinding();
String methodName = methodBinding.getName();
if (WebfluxUtils.REQUEST_PREDICATE_CONTENT_TYPE_METHOD.equals(methodName)) {
return WebfluxUtils.extractSimpleNameArgument(methodInvocation);
}
return null;
});
return (String[]) contentTypes.toArray(new String[contentTypes.size()]);
}
private void extractNestedValue(ASTNode node, Collection<String> values, Function<MethodInvocation, String> extractor) {
if (node == null || node instanceof TypeDeclaration) {
return path;
return;
}
if (node instanceof MethodInvocation) {
@@ -129,39 +223,25 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider {
if (WebfluxUtils.ROUTER_FUNCTIONS_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) {
String name = methodBinding.getName();
if ("nest".equals(name)) {
if (WebfluxUtils.REQUEST_PREDICATE_NEST_METHOD.equals(name)) {
List<?> arguments = methodInvocation.arguments();
for (Object argument : arguments) {
if (argument instanceof MethodInvocation) {
MethodInvocation nestedMethod = (MethodInvocation) argument;
IMethodBinding nestedMethodBinding = nestedMethod.resolveMethodBinding();
String nestedMethodName = nestedMethodBinding.getName();
if ("path".equals(nestedMethodName)) {
String additionalPath = WebfluxUtils.extractPath(nestedMethod);
if (additionalPath != null && additionalPath.length() > 0) {
path = additionalPath + path;
}
String value = extractor.apply(nestedMethod);
if (value != null) {
values.add(value);
}
}
}
}
}
}
return extractPath(node.getParent(), path);
extractNestedValue(node.getParent(), values, extractor);
}
private String extractMethod(MethodInvocation routerInvocation) {
WebfluxMethodFinder methodFinder = new WebfluxMethodFinder(routerInvocation);
routerInvocation.accept(methodFinder);
String method = methodFinder.getMethod();
return method;
}
private WebfluxHandlerInformation extractHandlerInformation(MethodInvocation node, String symbol) {
private WebfluxHandlerInformation extractHandlerInformation(MethodInvocation node, String path, String[] httpMethods, String[] contentTypes, String[] acceptTypes) {
List<?> arguments = node.arguments();
if (arguments != null) {
@@ -177,7 +257,7 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider {
String handlerMethod = methodBinding.getMethodDeclaration().toString();
if (handlerMethod != null) handlerMethod = handlerMethod.trim();
return new WebfluxHandlerInformation(symbol, handlerClass, handlerMethod);
return new WebfluxHandlerInformation(handlerClass, handlerMethod, path, httpMethods, contentTypes, acceptTypes);
}
}
}

View File

@@ -14,9 +14,12 @@ 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;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.StringLiteral;
/**
@@ -30,12 +33,15 @@ public class WebfluxUtils {
public static final String REQUEST_PREDICATE_PATH_METHOD = "path";
public static final String REQUEST_PREDICATE_METHOD_METHOD = "method";
public static final String REQUEST_PREDICATE_ACCEPT_TYPE_METHOD = "accept";
public static final String REQUEST_PREDICATE_CONTENT_TYPE_METHOD = "contentType";
public static final String REQUEST_PREDICATE_NEST_METHOD = "nest";
public static final Set<String> REQUEST_PREDICATE_HTTPMETHOD_METHODS = new HashSet<>(Arrays.asList("GET", "POST", "DELETE", "PUT", "PATCH", "HEAD", "OPTIONS"));
public static final Set<String> REQUEST_PREDICATE_ALL_PATH_METHODS = new HashSet<>(Arrays.asList(REQUEST_PREDICATE_PATH_METHOD, "GET", "POST", "DELETE", "PUT", "PATCH", "HEAD", "OPTIONS"));
public static String extractPath(MethodInvocation node) {
public static String extractStringLiteralArgument(MethodInvocation node) {
List<?> arguments = node.arguments();
if (arguments != null && arguments.size() > 0) {
Object object = arguments.get(0);
@@ -47,6 +53,34 @@ public class WebfluxUtils {
return null;
}
public static String extractQualifiedNameArgument(MethodInvocation node) {
List<?> arguments = node.arguments();
if (arguments != null && arguments.size() > 0) {
Object object = arguments.get(0);
if (object instanceof QualifiedName) {
QualifiedName qualifiedName = (QualifiedName) object;
if (qualifiedName.getName() != null) {
return qualifiedName.getName().toString();
}
}
}
return null;
}
public static String extractSimpleNameArgument(MethodInvocation node) {
List<?> arguments = node.arguments();
if (arguments != null && arguments.size() > 0) {
Object object = arguments.get(0);
if (object instanceof SimpleName) {
SimpleName name = (SimpleName) object;
if (name.getFullyQualifiedName() != null) {
return name.getFullyQualifiedName().toString();
}
}
}
return null;
}
public static boolean isRouteMethodInvocation(IMethodBinding methodBinding) {
if (ROUTER_FUNCTIONS_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())) {
String name = methodBinding.getName();
@@ -62,8 +96,39 @@ public class WebfluxUtils {
}
return false;
}
public static String getMediaType(String constantRep) {
if (constantRep == null) {
return null;
}
try {
if (constantRep.endsWith("_VALUE")) {
constantRep = constantRep.substring(0, constantRep.lastIndexOf("_VALUE"));
}
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

@@ -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

@@ -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());
@@ -53,10 +53,65 @@ public class WebFluxCodeLensProviderTest {
assertEquals(4, codeLenses.size());
assertTrue(containsCodeLens(codeLenses, "@/hello -- GET", 25, 29, 25, 34));
assertTrue(containsCodeLens(codeLenses, "@/echo -- POST", 30, 29, 30, 33));
assertTrue(containsCodeLens(codeLenses, "@/quotes -- GET", 35, 29, 35, 41));
assertTrue(containsCodeLens(codeLenses, "@/quotes -- GET", 41, 29, 41, 40));
assertTrue(containsCodeLens(codeLenses, "GET /hello - Accept: text/plain", 25, 29, 25, 34));
assertTrue(containsCodeLens(codeLenses, "POST /echo - Accept: text/plain - Content-Type: text/plain", 30, 29, 30, 33));
assertTrue(containsCodeLens(codeLenses, "GET /quotes - Accept: application/stream+json", 35, 29, 35, 41));
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));
}
@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

@@ -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;
@@ -46,8 +47,8 @@ public class WebFluxMappingSymbolProviderTest {
String docUri = directory.toPath().resolve("src/main/java/org/test/UserController.java").toUri().toString();
List<? extends SymbolInformation> symbols = getSymbols(docUri);
assertEquals(4, symbols.size());
assertTrue(containsSymbol(symbols, "@/users", docUri, 19, 1, 19, 74));
assertTrue(containsSymbol(symbols, "@/users/{username}", docUri, 24, 1, 24, 85));
assertTrue(containsSymbol(symbols, "@/users - Content-Type: application/json", docUri, 13, 1, 13, 74));
assertTrue(containsSymbol(symbols, "@/users/{username} - Content-Type: application/json", docUri, 18, 1, 18, 85));
List<? extends Object> addons = getAdditionalInformation(docUri);
assertNull(addons);
@@ -61,66 +62,195 @@ 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());
WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "@/hello -- GET").get(0);
assertEquals("@/hello -- GET", handlerInfo1.getSymbol());
WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "/hello", "GET").get(0);
assertEquals("/hello", handlerInfo1.getPath());
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 -- POST", handlerInfo2.getSymbol());
WebfluxHandlerInformation handlerInfo2 = getWebfluxHandler(addons, "/echo", "POST").get(0);
assertEquals("/echo", handlerInfo2.getPath());
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 -- GET", handlerInfo3.getSymbol());
WebfluxHandlerInformation handlerInfo3 = getWebfluxHandler(addons, "/quotes", "GET").get(0);
assertEquals("/quotes", handlerInfo3.getPath());
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 -- GET", handlerInfo4.getSymbol());
WebfluxHandlerInformation handlerInfo4 = getWebfluxHandler(addons, "/quotes", "GET").get(1);
assertEquals("/quotes", handlerInfo4.getPath());
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));
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());
WebfluxHandlerInformation handlerInfo1 = getWebfluxHandler(addons, "@/person/{id} -- GET").get(0);
assertEquals("@/person/{id} -- GET", handlerInfo1.getSymbol());
assertEquals("org.test.PersonHandler", handlerInfo1.getHandlerClass());
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.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/ -- POST", handlerInfo2.getSymbol());
assertEquals("org.test.PersonHandler", handlerInfo2.getHandlerClass());
WebfluxHandlerInformation handlerInfo2 = getWebfluxHandler(addons, "/person/", "POST").get(0);
assertEquals("/person/", handlerInfo2.getPath());
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 -- GET", handlerInfo3.getSymbol());
assertEquals("org.test.PersonHandler", handlerInfo3.getHandlerClass());
WebfluxHandlerInformation handlerInfo3 = getWebfluxHandler(addons, "/person", "GET").get(0);
assertEquals("/person", handlerInfo3.getPath());
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 - 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());
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());
}
@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 - 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 - 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(6, addons.size());
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.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, "/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.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/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(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) {
for (Iterator<? extends SymbolInformation> iterator = symbols.iterator(); iterator.hasNext();) {
SymbolInformation symbol = iterator.next();
@@ -146,11 +276,11 @@ public class WebFluxMappingSymbolProviderTest {
return harness.getServerWrapper().getComponents().getSpringIndexer().getAdditonalInformation(docUri);
}
private List<WebfluxHandlerInformation> getWebfluxHandler(List<? extends Object> addons, String symbol) {
private List<WebfluxHandlerInformation> getWebfluxHandler(List<? extends Object> addons, String path, String httpMethod) {
return addons.stream()
.filter((obj) -> obj instanceof WebfluxHandlerInformation)
.map((obj -> (WebfluxHandlerInformation) obj))
.filter((addon) -> addon.getSymbol().equals(symbol))
.filter((addon) -> addon.getPath().equals(path) && Arrays.asList(addon.getHttpMethods()).contains(httpMethod))
.collect(Collectors.toList());
}

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";
}
}

View File

@@ -11,7 +11,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.M1</version>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
@@ -35,10 +35,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
</dependencies>
<build>
@@ -50,42 +46,4 @@
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

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 NestedRouter1 {
@Bean
public RouterFunction<ServerResponse> routingFunction() {
PersonHandler handler = new PersonHandler();
public RouterFunction<ServerResponse> routingFunction1() {
PersonHandler1 handler = new PersonHandler1();
return nest(path("/person"),
nest(accept(APPLICATION_JSON),

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

@@ -0,0 +1,39 @@
package org.test;
import static org.springframework.http.MediaType.APPLICATION_JSON;
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 NestedRouter3 {
@Bean
public RouterFunction<ServerResponse> routingFunction() {
PersonHandler3 handler = new PersonHandler3();
return nest(path("/person"),
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

@@ -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,26 @@
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();
}
public Mono<ServerResponse> deletePerson(ServerRequest request) {
return ServerResponse.notFound().build();
}
}

View File

@@ -1,72 +0,0 @@
package org.test;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class TradingUser {
@Id
private String id;
private String userName;
private String fullName;
public TradingUser() {
}
public TradingUser(String id, String userName, String fullName) {
this.id = id;
this.userName = userName;
this.fullName = fullName;
}
public TradingUser(String userName, String fullName) {
this.userName = userName;
this.fullName = fullName;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TradingUser that = (TradingUser) o;
if (!id.equals(that.id)) return false;
return userName.equals(that.userName);
}
@Override
public int hashCode() {
int result = id.hashCode();
result = 31 * result + userName.hashCode();
return result;
}
}

View File

@@ -1,11 +0,0 @@
package org.test;
import reactor.core.publisher.Mono;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
public interface TradingUserRepository extends ReactiveMongoRepository<TradingUser, String> {
Mono<TradingUser> findByUserName(String userName);
}

View File

@@ -1,30 +1,24 @@
package org.test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
public class UserController {
private final TradingUserRepository tradingUserRepository;
public UserController(TradingUserRepository tradingUserRepository) {
this.tradingUserRepository = tradingUserRepository;
}
@GetMapping(path = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
public Flux<TradingUser> listUsers() {
return this.tradingUserRepository.findAll();
public Flux<Object> listUsers() {
return null;
}
@GetMapping(path = "/users/{username}", produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<TradingUser> showUsers(@PathVariable String username) {
return this.tradingUserRepository.findByUserName(username);
public Mono<Object> showUsers(@PathVariable String username) {
return null;
}
}