From adedf4d0f70889cb011f434e2d4725f17dd801a8 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Wed, 2 Nov 2022 14:42:17 -0400 Subject: [PATCH] Workspace symbols for JAX-RS endpoints Closes #87 Signed-off-by: David Thompson --- README.md | 6 + .../META-INF/MANIFEST.MF | 13 +- .../org.eclipse.lsp4mp.jdt.core/plugin.xml | 3 + .../schema/javaFeatureParticipants.exsd | 24 +- .../jdt/core/PropertiesManagerForJava.java | 38 ++- .../IJavaWorkspaceSymbolsParticipant.java | 39 +++ .../lsp4mp/jdt/core/jaxrs/JaxRsContext.java | 37 ++- .../lsp4mp/jdt/core/jaxrs/JaxRsUtils.java | 65 +++-- .../jdt/core/utils/AnnotationUtils.java | 32 +++ .../jdt/core/utils/JDTMicroProfileUtils.java | 39 +++ .../core/java/JavaFeaturesRegistry.java | 21 ++ .../JavaWorkspaceSymbolsDefinition.java | 50 ++++ ...oProfileDelegateCommandHandlerForJava.java | 20 ++ .../jdt/internal/jaxrs/JaxRsConstants.java | 44 +++- .../jaxrs/java/JaxRsCodeLensParticipant.java | 4 +- .../java/JaxRsWorkspaceSymbolParticipant.java | 246 ++++++++++++++++++ .../java/org/acme/config/FakeResource.java | 9 + .../org/acme/config/GreetingResource.java | 6 + .../src/main/java/org/acme/config/POST.java | 5 + .../src/main/java/org/acme/config/Path.java | 5 + .../projects/maven/open-liberty/.classpath | 27 ++ .../projects/maven/open-liberty/.gitignore | 11 + .../projects/maven/open-liberty/.project | 23 ++ .../projects/maven/open-liberty/pom.xml | 57 ++++ .../main/java/com/demo/rest/MyResource.java | 18 ++ .../java/com/demo/rest/RestApplication.java | 9 + .../src/main/liberty/config/server.xml | 42 +++ .../jdt/core/BasePropertiesManagerTest.java | 1 + .../JaxRsApplicationPathCodeLensTest.java | 14 + .../JaxRsWorkspaceSymbolParticipantTest.java | 99 +++++++ .../lsp4mp/commons/ProjectLabelInfoEntry.java | 2 + .../lsp4mp/ls/MicroProfileLanguageServer.java | 20 +- .../ls/MicroProfileTextDocumentService.java | 9 +- .../ls/MicroProfileWorkspaceService.java | 50 +++- ...MicroProfileJavaProjectLabelsProvider.java | 8 +- ...roProfileJavaWorkspaceSymbolsProvider.java | 34 +++ .../ls/api/MicroProfileLanguageClientAPI.java | 2 +- .../ls/java/JavaFileTextDocumentService.java | 4 +- .../lsp4mp/ls/java/JavaTextDocuments.java | 53 +++- .../ClientCapabilitiesWrapper.java | 10 + .../MicroProfileCapabilityManager.java | 6 + .../ServerCapabilitiesConstants.java | 9 +- .../ServerCapabilitiesInitializer.java | 1 + ...icroProfileLanguageServerDeadlockTest.java | 2 +- .../lsp4mp/ls/java/JavaTextDocumentsTest.java | 2 +- 45 files changed, 1139 insertions(+), 80 deletions(-) create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/java/symbols/IJavaWorkspaceSymbolsParticipant.java create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/java/symbols/JavaWorkspaceSymbolsDefinition.java create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/java/JaxRsWorkspaceSymbolParticipant.java create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/FakeResource.java create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/POST.java create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/Path.java create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.classpath create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.gitignore create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.project create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/pom.xml create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/java/com/demo/rest/MyResource.java create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/java/com/demo/rest/RestApplication.java create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/liberty/config/server.xml create mode 100644 microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/java/JaxRsWorkspaceSymbolParticipantTest.java create mode 100644 microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileJavaWorkspaceSymbolsProvider.java diff --git a/README.md b/README.md index f82975c41..3216d391c 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,12 @@ You can build all projects at once by running the `buildAll.sh` script (`buildAl ## Features +#### General + +When you open a MicroProfile project, lsp4mp provides: + +- Symbols to help you navigate to JAX-RS REST endpoint methods, searchable using the naming convention: `@/api/endpointName: GET` + #### Properties files In `microprofile-config.properties` files, you will benefit with: diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/META-INF/MANIFEST.MF b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/META-INF/MANIFEST.MF index 583907a18..55dfa8738 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/META-INF/MANIFEST.MF +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/META-INF/MANIFEST.MF @@ -46,18 +46,19 @@ Export-Package: io.quarkus.runtime.util, org.eclipse.lsp4mp.jdt.internal.core.utils;x-friends:="org.eclipse.lsp4mp.jdt.test", org.eclipse.lsp4mp.jdt.internal.faulttolerance;x-friends:="org.eclipse.lsp4mp.jdt.test", org.eclipse.lsp4mp.jdt.internal.faulttolerance.java;x-friends:="org.eclipse.lsp4mp.jdt.test", - org.eclipse.lsp4mp.jdt.internal.reactivemessaging;x-friends:="org.eclipse.lsp4mp.jdt.test", - org.eclipse.lsp4mp.jdt.internal.reactivemessaging.java;x-friends:="org.eclipse.lsp4mp.jdt.test", org.eclipse.lsp4mp.jdt.internal.health;x-friends:="org.eclipse.lsp4mp.jdt.test", org.eclipse.lsp4mp.jdt.internal.health.java;x-friends:="org.eclipse.lsp4mp.jdt.test", + org.eclipse.lsp4mp.jdt.internal.jaxrs.java;x-friends:="org.eclipse.lsp4mp.jdt.test", org.eclipse.lsp4mp.jdt.internal.metrics;x-friends:="org.eclipse.lsp4mp.jdt.test", org.eclipse.lsp4mp.jdt.internal.metrics.java;x-friends:="org.eclipse.lsp4mp.jdt.test", + org.eclipse.lsp4mp.jdt.internal.reactivemessaging;x-friends:="org.eclipse.lsp4mp.jdt.test", + org.eclipse.lsp4mp.jdt.internal.reactivemessaging.java;x-friends:="org.eclipse.lsp4mp.jdt.test", org.eclipse.lsp4mp.jdt.internal.restclient;x-friends:="org.eclipse.lsp4mp.jdt.test" Bundle-ClassPath: . -Import-Package: com.google.gson, +Import-Package: com.google.common.graph, + com.google.gson, com.google.gson.stream, + io.smallrye.common.constraint, io.smallrye.common.expression, io.smallrye.common.function, - io.smallrye.common.constraint, - org.jboss.logging, - com.google.common.graph + org.jboss.logging diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/plugin.xml b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/plugin.xml index a59cb7142..ecb65e68c 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/plugin.xml +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/plugin.xml @@ -41,6 +41,7 @@ + @@ -325,5 +326,7 @@ + diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/schema/javaFeatureParticipants.exsd b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/schema/javaFeatureParticipants.exsd index af1fb5d1e..e49ab01cd 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/schema/javaFeatureParticipants.exsd +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/schema/javaFeatureParticipants.exsd @@ -25,6 +25,7 @@ + @@ -198,6 +199,26 @@ + + + + Java workspaceSymbols participant. + + + + + + + Name of a class that implements IJavaWorkspaceSymbolParticipant + + + + + + + + + @@ -238,7 +259,4 @@ - - - diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/PropertiesManagerForJava.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/PropertiesManagerForJava.java index 6adb5e2c6..bbef0ece9 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/PropertiesManagerForJava.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/PropertiesManagerForJava.java @@ -16,13 +16,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.IBuffer; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.ILocalVariable; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.ISourceRange; @@ -52,6 +55,7 @@ import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.jsonrpc.validation.NonNull; +import org.eclipse.lsp4j.SymbolInformation; import org.eclipse.lsp4mp.commons.DocumentFormat; import org.eclipse.lsp4mp.commons.JavaCursorContextKind; import org.eclipse.lsp4mp.commons.JavaCursorContextResult; @@ -72,6 +76,7 @@ import org.eclipse.lsp4mp.jdt.core.java.hover.JavaHoverContext; import org.eclipse.lsp4mp.jdt.core.utils.ASTNodeUtils; import org.eclipse.lsp4mp.jdt.core.utils.IJDTUtils; +import org.eclipse.lsp4mp.jdt.core.utils.JDTMicroProfileUtils; import org.eclipse.lsp4mp.jdt.internal.core.java.JavaFeaturesRegistry; import org.eclipse.lsp4mp.jdt.internal.core.java.codeaction.CodeActionHandler; import org.eclipse.lsp4mp.jdt.internal.core.java.codelens.JavaCodeLensDefinition; @@ -79,6 +84,7 @@ import org.eclipse.lsp4mp.jdt.internal.core.java.definition.JavaDefinitionDefinition; import org.eclipse.lsp4mp.jdt.internal.core.java.diagnostics.JavaDiagnosticsDefinition; import org.eclipse.lsp4mp.jdt.internal.core.java.hover.JavaHoverDefinition; +import org.eclipse.lsp4mp.jdt.internal.core.java.symbols.JavaWorkspaceSymbolsDefinition; /** * JDT MicroProfile manager for Java files. @@ -585,6 +591,36 @@ private void collectHover(String uri, ITypeRoot typeRoot, IJavaElement hoverElem definitions.forEach(definition -> definition.endHover(context, monitor)); } + /** + * Returns the workspace symbols for the given java project. + * + * @param projectUri the uri of the java project + * @param utils the JDT utils + * @param monitor the progress monitor + * @return the workspace symbols for the given java project + */ + public List workspaceSymbols(String projectUri, IJDTUtils utils, IProgressMonitor monitor) { + List symbols = new ArrayList<>(); + Optional projectOpt = Stream.of(JDTMicroProfileUtils.getJavaProjects()) // + .filter(project -> projectUri.equals(JDTMicroProfileUtils.getProjectURI(project))) // + .findFirst(); + if (projectOpt.isEmpty()) { + return symbols; + } + collectWorkspaceSymbols(projectOpt.get(), utils, symbols, monitor); + return symbols; + } + + private void collectWorkspaceSymbols(IJavaProject project, IJDTUtils utils, List symbols, + IProgressMonitor monitor) { + List definitions = JavaFeaturesRegistry.getInstance() + .getJavaWorkspaceSymbolsDefinitions(); + if (definitions.isEmpty()) { + return; + } + definitions.forEach(definition -> definition.collectSymbols(project, utils, symbols, monitor)); + } + /** * Given the uri returns a {@link ITypeRoot}. May return null if it can not * associate the uri with a Java file or class file. @@ -755,4 +791,4 @@ private static int offsetOfFirstNonAnnotationModifier(BodyDeclaration node) { } } -} \ No newline at end of file +} diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/java/symbols/IJavaWorkspaceSymbolsParticipant.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/java/symbols/IJavaWorkspaceSymbolsParticipant.java new file mode 100644 index 000000000..7ec79c949 --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/java/symbols/IJavaWorkspaceSymbolsParticipant.java @@ -0,0 +1,39 @@ +/******************************************************************************* +* Copyright (c) 2023 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4mp.jdt.core.java.symbols; + +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4mp.jdt.core.utils.IJDTUtils; + +/** + * Represents an object that can collect workspace symbols for java projects. + */ +public interface IJavaWorkspaceSymbolsParticipant { + + /** + * Fill in symbols with workspace symbols of the given project. + * + * @param project the project to collect workspace symbols from + * @param utils the JDT utils + * @param symbols the list of symbols to add to + * @param monitor the progress monitor + */ + void collectSymbols(IJavaProject project, IJDTUtils utils, List symbols, + IProgressMonitor monitor); + +} diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/JaxRsContext.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/JaxRsContext.java index 4df400ee5..cfedbd781 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/JaxRsContext.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/JaxRsContext.java @@ -14,6 +14,7 @@ package org.eclipse.lsp4mp.jdt.core.jaxrs; import static org.eclipse.lsp4mp.jdt.core.jaxrs.JaxRsUtils.getJaxRsApplicationPathValue; +import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAKARTA_WS_RS_APPLICATIONPATH_ANNOTATION; import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAVAX_WS_RS_APPLICATIONPATH_ANNOTATION; import java.util.concurrent.atomic.AtomicReference; @@ -45,6 +46,12 @@ public class JaxRsContext { private static final String CONTEXT_KEY = JaxRsContext.class.getName(); + private static final SearchPattern SEARCH_PATTERN = SearchPattern.createOrPattern( + SearchPattern.createPattern(JAVAX_WS_RS_APPLICATIONPATH_ANNOTATION, IJavaSearchConstants.ANNOTATION_TYPE, + IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, SearchPattern.R_EXACT_MATCH), + SearchPattern.createPattern(JAKARTA_WS_RS_APPLICATIONPATH_ANNOTATION, IJavaSearchConstants.ANNOTATION_TYPE, + IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, SearchPattern.R_EXACT_MATCH)); + private int serverPort; // The quarkus.http.root-path property in application.properties @@ -53,11 +60,11 @@ public class JaxRsContext { // The value of the @ApplicationPath annotation private String applicationPath; - private final JavaCodeLensContext javaCodeLensContext; + private final IJavaProject javaProject; - public JaxRsContext(JavaCodeLensContext javaCodeLensContext) { + public JaxRsContext(IJavaProject javaProject) { setServerPort(DEFAULT_PORT); - this.javaCodeLensContext = javaCodeLensContext; + this.javaProject = javaProject; } public int getServerPort() { @@ -95,9 +102,13 @@ public void setRootPath(String rootPath) { */ public String getApplicationPath(IProgressMonitor monitor) throws CoreException { if (applicationPath == null) { - IType applicationPathType = JDTTypeUtils.findType(javaCodeLensContext.getJavaProject(), + IType applicationPathType = JDTTypeUtils.findType(javaProject, JAVAX_WS_RS_APPLICATIONPATH_ANNOTATION); - applicationPath = findApplicationPath(applicationPathType, javaCodeLensContext, monitor); + if (applicationPathType == null) { + applicationPathType = JDTTypeUtils.findType(javaProject, + JAKARTA_WS_RS_APPLICATIONPATH_ANNOTATION); + } + applicationPath = findApplicationPath(javaProject, monitor); } return applicationPath; } @@ -114,7 +125,7 @@ public void setApplicationPath(String applicationPath) { public static JaxRsContext getJaxRsContext(JavaCodeLensContext context) { JaxRsContext jaxRsContext = (JaxRsContext) context.get(CONTEXT_KEY); if (jaxRsContext == null) { - jaxRsContext = new JaxRsContext(context); + jaxRsContext = new JaxRsContext(context.getJavaProject()); context.put(CONTEXT_KEY, jaxRsContext); } return jaxRsContext; @@ -150,16 +161,13 @@ public String getLocalBaseURL() { * @return the value of the @ApplicationPath annotation, or null if not found * @throws CoreException */ - private static String findApplicationPath(IType annotationType, JavaCodeLensContext context, + private static String findApplicationPath(IJavaProject javaProject, IProgressMonitor monitor) throws CoreException { AtomicReference applicationPathRef = new AtomicReference(); - SearchPattern pattern = SearchPattern.createPattern(JAVAX_WS_RS_APPLICATIONPATH_ANNOTATION, - IJavaSearchConstants.ANNOTATION_TYPE, IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, - SearchPattern.R_EXACT_MATCH); SearchEngine engine = new SearchEngine(); - engine.search(pattern, new SearchParticipant[] { + engine.search(SEARCH_PATTERN, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() - }, createSearchScope(annotationType.getJavaProject()), new SearchRequestor() { + }, createSearchScope(javaProject), new SearchRequestor() { @Override public void acceptSearchMatch(SearchMatch match) throws CoreException { @@ -170,8 +178,9 @@ public void acceptSearchMatch(SearchMatch match) throws CoreException { } private void collectApplicationPath(IType type) throws CoreException { - if (AnnotationUtils.hasAnnotation(type, JAVAX_WS_RS_APPLICATIONPATH_ANNOTATION)) { - applicationPathRef.set(getJaxRsApplicationPathValue(type)); + String applicationPathValue = getJaxRsApplicationPathValue(type); + if (applicationPathValue != null) { + applicationPathRef.set(applicationPathValue); } } }, monitor); diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/JaxRsUtils.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/JaxRsUtils.java index 45744a776..221583786 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/JaxRsUtils.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/JaxRsUtils.java @@ -16,14 +16,12 @@ import static org.eclipse.lsp4mp.jdt.core.utils.AnnotationUtils.getAnnotation; import static org.eclipse.lsp4mp.jdt.core.utils.AnnotationUtils.getAnnotationMemberValue; import static org.eclipse.lsp4mp.jdt.core.utils.AnnotationUtils.hasAnnotation; +import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.HTTP_METHOD_ANNOTATIONS; +import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAKARTA_WS_RS_APPLICATIONPATH_ANNOTATION; +import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAKARTA_WS_RS_GET_ANNOTATION; +import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAKARTA_WS_RS_PATH_ANNOTATION; import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAVAX_WS_RS_APPLICATIONPATH_ANNOTATION; import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAVAX_WS_RS_GET_ANNOTATION; -import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAVAX_WS_RS_POST_ANNOTATION; -import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAVAX_WS_RS_PUT_ANNOTATION; -import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAVAX_WS_RS_DELETE_ANNOTATION; -import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAVAX_WS_RS_HEAD_ANNOTATION; -import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAVAX_WS_RS_OPTIONS_ANNOTATION; -import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAVAX_WS_RS_PATCH_ANNOTATION; import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAVAX_WS_RS_PATH_ANNOTATION; import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.PATH_VALUE; @@ -53,35 +51,46 @@ private JaxRsUtils() { } /** - * Returns the value of the JAX-RS Path annotation and null otherwise.. + * Returns the value of the JAX-RS/Jakarta Path annotation and null otherwise. * - * @param annotatable - * @return the value of the JAX-RS Path annotation and null otherwise.. + * @param annotatable the annotatable that might be annotated with the + * JAX-RS/Jakarta Path annotation + * @return the value of the JAX-RS/Jakarta Path annotation and null otherwise * @throws JavaModelException */ public static String getJaxRsPathValue(IAnnotatable annotatable) throws JavaModelException { - IAnnotation annotationPath = getAnnotation(annotatable, JAVAX_WS_RS_PATH_ANNOTATION); - return annotationPath != null ? getAnnotationMemberValue(annotationPath, PATH_VALUE) : null; + IAnnotation annotationPath = getAnnotation(annotatable, JAVAX_WS_RS_PATH_ANNOTATION, + JAKARTA_WS_RS_PATH_ANNOTATION); + if (annotationPath == null) { + return null; + } + return getAnnotationMemberValue(annotationPath, PATH_VALUE); } /** - * Returns the value of the JAX-RS ApplicationPath annotation and null - * otherwise.. + * Returns the value of the JAX-RS/Jakarta ApplicationPath annotation and null + * otherwise. * - * @param annotatable - * @return the value of the JAX-RS ApplicationPath annotation and null - * otherwise.. + * @param annotatable the annotatable that might be annotated with the + * JAX-RS/Jakarta ApplicationPath annotation + * @return the value of the JAX-RS/Jakarta ApplicationPath annotation and null + * otherwise * @throws JavaModelException */ public static String getJaxRsApplicationPathValue(IAnnotatable annotatable) throws JavaModelException { - IAnnotation annotationPath = getAnnotation(annotatable, JAVAX_WS_RS_APPLICATIONPATH_ANNOTATION); - return annotationPath != null ? getAnnotationMemberValue(annotationPath, PATH_VALUE) : null; + + IAnnotation annotationApplicationPath = getAnnotation(annotatable, JAVAX_WS_RS_APPLICATIONPATH_ANNOTATION, + JAKARTA_WS_RS_APPLICATIONPATH_ANNOTATION); + if (annotationApplicationPath == null) { + return null; + } + return getAnnotationMemberValue(annotationApplicationPath, PATH_VALUE); } /** * Returns true if the given method - * has @GET, @POST, @PUT, @DELETE, @HEAD, @OPTIONS, or @PATCH annotation - * and false otherwise. + * has @GET, @POST, @PUT, @DELETE, @HEAD, @OPTIONS, or @PATCH annotation and + * false otherwise. * * @param method the method. * @return true if the given method @@ -90,13 +99,12 @@ public static String getJaxRsApplicationPathValue(IAnnotatable annotatable) thro * @throws JavaModelException */ public static boolean isJaxRsRequestMethod(IMethod method) throws JavaModelException { - return (hasAnnotation(method, JAVAX_WS_RS_GET_ANNOTATION) - || hasAnnotation(method, JAVAX_WS_RS_POST_ANNOTATION) - || hasAnnotation(method, JAVAX_WS_RS_PUT_ANNOTATION) - || hasAnnotation(method, JAVAX_WS_RS_DELETE_ANNOTATION) - || hasAnnotation(method, JAVAX_WS_RS_HEAD_ANNOTATION) - || hasAnnotation(method, JAVAX_WS_RS_OPTIONS_ANNOTATION) - || hasAnnotation(method, JAVAX_WS_RS_PATCH_ANNOTATION)); + for (String annotation : HTTP_METHOD_ANNOTATIONS) { + if (hasAnnotation(method, annotation)) { + return true; + } + } + return false; } /** @@ -107,7 +115,8 @@ public static boolean isJaxRsRequestMethod(IMethod method) throws JavaModelExcep * @throws JavaModelException */ public static boolean isClickableJaxRsRequestMethod(IMethod method) throws JavaModelException { - return hasAnnotation(method, JAVAX_WS_RS_GET_ANNOTATION); + return hasAnnotation(method, JAVAX_WS_RS_GET_ANNOTATION) + || hasAnnotation(method, JAKARTA_WS_RS_GET_ANNOTATION); } /** diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/utils/AnnotationUtils.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/utils/AnnotationUtils.java index c2bd03c3e..23d3428c2 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/utils/AnnotationUtils.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/utils/AnnotationUtils.java @@ -77,6 +77,38 @@ public static IAnnotation getAnnotation(IAnnotatable annotatable, String annotat return null; } + /** + * Returns an IAnnotation of the first annotation in + * annotationNames that appears on the given annotatable. + * + * It returns the first in the annotationNames list, not the + * first in the order that the annotations appear on the annotatable.

+ * eg. + * + *
+	 * @Singleton @Deprecated String myString;
+	 * 
+ * + * when given the annotationNames list {"Potato", "Deprecated", + * "Singleton"} will return the IAnnotation for @Deprecated. + * + * @param annotatable the annotatable to check for the annotations + * @param annotationNames the FQNs of the annotations to check for + * @return an IAnnotation of the first annotation in + * annotationNames that appears on the given annotatable + * @throws JavaModelException + */ + public static IAnnotation getAnnotation(IAnnotatable annotatable, String... annotationNames) + throws JavaModelException { + for (String annotationName : annotationNames) { + IAnnotation annotation = getAnnotation(annotatable, annotationName); + if (annotation != null) { + return annotation; + } + } + return null; + } + /** * Returns true if the given annotation match the given annotation name and * false otherwise. diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/utils/JDTMicroProfileUtils.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/utils/JDTMicroProfileUtils.java index 2afe89ea0..6bbd8f36e 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/utils/JDTMicroProfileUtils.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/utils/JDTMicroProfileUtils.java @@ -15,6 +15,7 @@ import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Stream; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; @@ -23,6 +24,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.core.JavaProject; import org.eclipse.lsp4mp.commons.ClasspathKind; @@ -150,4 +152,41 @@ public static boolean isMicroProfileProject(IJavaProject javaProject) { return false; } } + + /** + * Returns an array of all the java projects that are currently loaded into the JDT + * workspace. + * + * @return an array of all the projects that are currently loaded into the JDT + * workspace + */ + public static IJavaProject[] getJavaProjects() { + return Stream.of(getAllProjects()) // + .filter(JDTMicroProfileUtils::isJavaProject) // + .map(p -> JavaCore.create(p)) // + .filter(p -> p != null) // + .toArray(IJavaProject[]::new); + } + + /** + * Returns an array of all the projects that are currently loaded into the JDT + * workspace. + * + * @return an array of all the projects that are currently loaded into the JDT + * workspace + */ + private static IProject[] getAllProjects() { + return ResourcesPlugin.getWorkspace().getRoot().getProjects(); + } + + private static boolean isJavaProject(IProject project) { + if (project == null) { + return false; + } + try { + return project.hasNature(JavaCore.NATURE_ID); + } catch (CoreException e) { + return false; + } + } } diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/java/JavaFeaturesRegistry.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/java/JavaFeaturesRegistry.java index 42ad60bcd..cb6865979 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/java/JavaFeaturesRegistry.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/java/JavaFeaturesRegistry.java @@ -30,6 +30,7 @@ import org.eclipse.lsp4mp.jdt.internal.core.java.definition.JavaDefinitionDefinition; import org.eclipse.lsp4mp.jdt.internal.core.java.diagnostics.JavaDiagnosticsDefinition; import org.eclipse.lsp4mp.jdt.internal.core.java.hover.JavaHoverDefinition; +import org.eclipse.lsp4mp.jdt.internal.core.java.symbols.JavaWorkspaceSymbolsDefinition; /** * Registry to hold the extension point @@ -45,6 +46,7 @@ public class JavaFeaturesRegistry { private static final String DEFINITION_ELT = "definition"; private static final String DIAGNOSTICS_ELT = "diagnostics"; private static final String HOVER_ELT = "hover"; + private static final String WORKSPACE_SYMBOLS_ELT = "workspaceSymbols"; private static final Logger LOGGER = Logger.getLogger(JavaFeaturesRegistry.class.getName()); @@ -62,6 +64,8 @@ public class JavaFeaturesRegistry { private final List javaHoverDefinitions; + private final List javaWorkspaceSymbolsDefinitions; + private boolean javaFeatureDefinitionsLoaded; public static JavaFeaturesRegistry getInstance() { @@ -76,6 +80,7 @@ public JavaFeaturesRegistry() { javaDefinitionDefinitions = new ArrayList<>(); javaDiagnosticsDefinitions = new ArrayList<>(); javaHoverDefinitions = new ArrayList<>(); + javaWorkspaceSymbolsDefinitions = new ArrayList<>(); } /** @@ -139,6 +144,16 @@ public List getJavaHoverDefinitions() { return javaHoverDefinitions; } + /** + * Returns a list of workspace symbols definition. + * + * @return a list of workspace symbols definition + */ + public List getJavaWorkspaceSymbolsDefinitions() { + loadJavaFeatureDefinitions(); + return javaWorkspaceSymbolsDefinitions; + } + private synchronized void loadJavaFeatureDefinitions() { if (javaFeatureDefinitionsLoaded) return; @@ -207,6 +222,12 @@ private void createAndAddDefinition(IConfigurationElement ce) throws CoreExcepti } break; } + case WORKSPACE_SYMBOLS_ELT: { + JavaWorkspaceSymbolsDefinition definition = new JavaWorkspaceSymbolsDefinition(ce); + synchronized (javaWorkspaceSymbolsDefinitions) { + javaWorkspaceSymbolsDefinitions.add(definition); + } + } default: } diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/java/symbols/JavaWorkspaceSymbolsDefinition.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/java/symbols/JavaWorkspaceSymbolsDefinition.java new file mode 100644 index 000000000..eca8bd988 --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/java/symbols/JavaWorkspaceSymbolsDefinition.java @@ -0,0 +1,50 @@ +/******************************************************************************* +* Copyright (c) 2023 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4mp.jdt.internal.core.java.symbols; + +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4mp.jdt.core.java.symbols.IJavaWorkspaceSymbolsParticipant; +import org.eclipse.lsp4mp.jdt.core.utils.IJDTUtils; +import org.eclipse.lsp4mp.jdt.internal.core.java.AbstractJavaFeatureDefinition; + +/** + * Wrapper class around {@link IJavaWorkspaceSymbolsParticipant} participants. + */ +public class JavaWorkspaceSymbolsDefinition extends AbstractJavaFeatureDefinition + implements IJavaWorkspaceSymbolsParticipant { + + private static final Logger LOGGER = Logger.getLogger(JavaWorkspaceSymbolsDefinition.class.getName()); + + public JavaWorkspaceSymbolsDefinition(IConfigurationElement element) { + super(element); + } + + @Override + public void collectSymbols(IJavaProject project, IJDTUtils utils, List symbols, + IProgressMonitor monitor) { + try { + getParticipant().collectSymbols(project, utils, symbols, monitor); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Unable to get WorkspaceSymbol participant", e); + } + } + +} diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/ls/MicroProfileDelegateCommandHandlerForJava.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/ls/MicroProfileDelegateCommandHandlerForJava.java index 30885d1ca..c014cb944 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/ls/MicroProfileDelegateCommandHandlerForJava.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/ls/MicroProfileDelegateCommandHandlerForJava.java @@ -36,6 +36,7 @@ import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.SymbolInformation; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.eclipse.lsp4mp.commons.CodeActionResolveData; import org.eclipse.lsp4mp.commons.DocumentFormat; @@ -71,6 +72,7 @@ public class MicroProfileDelegateCommandHandlerForJava extends AbstractMicroProf private static final String JAVA_DEFINITION_COMMAND_ID = "microprofile/java/definition"; private static final String JAVA_DIAGNOSTICS_COMMAND_ID = "microprofile/java/diagnostics"; private static final String JAVA_HOVER_COMMAND_ID = "microprofile/java/hover"; + private static final String JAVA_WORKSPACE_SYMBOLS_ID = "microprofile/java/workspaceSymbols"; public MicroProfileDelegateCommandHandlerForJava() { } @@ -94,6 +96,8 @@ public Object executeCommand(String commandId, List arguments, IProgress return getDiagnosticsForJava(arguments, commandId, progress); case JAVA_HOVER_COMMAND_ID: return getHoverForJava(arguments, commandId, progress); + case JAVA_WORKSPACE_SYMBOLS_ID: + return getWorkspaceSymbolsForJava(arguments, commandId, progress); default: throw new UnsupportedOperationException(String.format("Unsupported command '%s'!", commandId)); } @@ -464,4 +468,20 @@ private static MicroProfileJavaHoverParams createMicroProfileJavaHoverParams(Lis return new MicroProfileJavaHoverParams(javaFileUri, hoverPosition, documentFormat, surroundEqualsWithSpaces); } + private List getWorkspaceSymbolsForJava(List arguments, String commandId, + IProgressMonitor monitor) { + String projectUri = createMicroProfileJavaWorkspaceSymbolParams(arguments, commandId); + return PropertiesManagerForJava.getInstance().workspaceSymbols(projectUri, JDTUtilsLSImpl.getInstance(), + monitor); + } + + private static String createMicroProfileJavaWorkspaceSymbolParams(List arguments, String commandId) { + Object projectUriObj = (String) arguments.get(0); + if (projectUriObj == null || !(projectUriObj instanceof String)) { + throw new UnsupportedOperationException(String + .format("Command '%s' must be called with one projectUri: String argument!", commandId)); + } + return (String)projectUriObj; + } + } diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/JaxRsConstants.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/JaxRsConstants.java index 8db6a98fa..050a90371 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/JaxRsConstants.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/JaxRsConstants.java @@ -13,8 +13,11 @@ *******************************************************************************/ package org.eclipse.lsp4mp.jdt.internal.jaxrs; +import java.util.Arrays; +import java.util.List; + /** - * JAX-RS constants + * JAX-RS and jakarta.ws.rs constants. * * @author Angelo ZERR * @@ -25,24 +28,49 @@ public JaxRsConstants() { } public static final String JAVAX_WS_RS_PATH_ANNOTATION = "javax.ws.rs.Path"; + public static final String JAKARTA_WS_RS_PATH_ANNOTATION = "jakarta.ws.rs.Path"; + public static final String PATH_VALUE = "value"; public static final String JAVAX_WS_RS_APPLICATIONPATH_ANNOTATION = "javax.ws.rs.ApplicationPath"; + public static final String JAKARTA_WS_RS_APPLICATIONPATH_ANNOTATION = "jakarta.ws.rs.ApplicationPath"; + // JAX-RS HTTP method annotations public static final String JAVAX_WS_RS_GET_ANNOTATION = "javax.ws.rs.GET"; - public static final String JAVAX_WS_RS_POST_ANNOTATION = "javax.ws.rs.POST"; - public static final String JAVAX_WS_RS_PUT_ANNOTATION = "javax.ws.rs.PUT"; - public static final String JAVAX_WS_RS_DELETE_ANNOTATION = "javax.ws.rs.DELETE"; - public static final String JAVAX_WS_RS_HEAD_ANNOTATION = "javax.ws.rs.HEAD"; - public static final String JAVAX_WS_RS_OPTIONS_ANNOTATION = "javax.ws.rs.OPTIONS"; - public static final String JAVAX_WS_RS_PATCH_ANNOTATION = "javax.ws.rs.PATCH"; - public static final String PATH_VALUE = "value"; + // jakarta.ws.rs HTTP method annotations + public static final String JAKARTA_WS_RS_GET_ANNOTATION = "jakarta.ws.rs.GET"; + public static final String JAKARTA_WS_RS_POST_ANNOTATION = "jakarta.ws.rs.POST"; + public static final String JAKARTA_WS_RS_PUT_ANNOTATION = "jakarta.ws.rs.PUT"; + public static final String JAKARTA_WS_RS_DELETE_ANNOTATION = "jakarta.ws.rs.DELETE"; + public static final String JAKARTA_WS_RS_HEAD_ANNOTATION = "jakarta.ws.rs.HEAD"; + public static final String JAKARTA_WS_RS_OPTIONS_ANNOTATION = "jakarta.ws.rs.OPTIONS"; + public static final String JAKARTA_WS_RS_PATCH_ANNOTATION = "jakarta.ws.rs.PATCH"; + + /** + * A list of the fully qualified names of all jax-rs and jakarta.ws.rs http + * method annotations. + */ + public static final List HTTP_METHOD_ANNOTATIONS = Arrays.asList( // + JAVAX_WS_RS_GET_ANNOTATION, // + JAVAX_WS_RS_POST_ANNOTATION, // + JAVAX_WS_RS_PUT_ANNOTATION, // + JAVAX_WS_RS_DELETE_ANNOTATION, // + JAVAX_WS_RS_HEAD_ANNOTATION, // + JAVAX_WS_RS_OPTIONS_ANNOTATION, // + JAVAX_WS_RS_PATCH_ANNOTATION, // + JAKARTA_WS_RS_GET_ANNOTATION, // + JAKARTA_WS_RS_POST_ANNOTATION, // + JAKARTA_WS_RS_PUT_ANNOTATION, // + JAKARTA_WS_RS_DELETE_ANNOTATION, // + JAKARTA_WS_RS_HEAD_ANNOTATION, // + JAKARTA_WS_RS_OPTIONS_ANNOTATION, // + JAKARTA_WS_RS_PATCH_ANNOTATION); public static final String JAVAX_WS_RS_RESPONSE_TYPE = "javax.ws.rs.core.Response"; diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/java/JaxRsCodeLensParticipant.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/java/JaxRsCodeLensParticipant.java index db76ca6a5..4fcf5cdd8 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/java/JaxRsCodeLensParticipant.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/java/JaxRsCodeLensParticipant.java @@ -18,6 +18,7 @@ import static org.eclipse.lsp4mp.jdt.core.jaxrs.JaxRsUtils.isClickableJaxRsRequestMethod; import static org.eclipse.lsp4mp.jdt.core.jaxrs.JaxRsUtils.isJaxRsRequestMethod; import static org.eclipse.lsp4mp.jdt.core.utils.JDTTypeUtils.overlaps; +import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAKARTA_WS_RS_PATH_ANNOTATION; import static org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants.JAVAX_WS_RS_PATH_ANNOTATION; import java.io.IOException; @@ -66,7 +67,8 @@ public boolean isAdaptedForCodeLens(JavaCodeLensContext context, IProgressMonito } // Collection of URL codeLens is done only if JAX-RS is on the classpath IJavaProject javaProject = context.getJavaProject(); - return JDTTypeUtils.findType(javaProject, JAVAX_WS_RS_PATH_ANNOTATION) != null; + return JDTTypeUtils.findType(javaProject, JAVAX_WS_RS_PATH_ANNOTATION) != null + || JDTTypeUtils.findType(javaProject, JAKARTA_WS_RS_PATH_ANNOTATION) != null; } @Override diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/java/JaxRsWorkspaceSymbolParticipant.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/java/JaxRsWorkspaceSymbolParticipant.java new file mode 100644 index 000000000..6096ea4a1 --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/java/JaxRsWorkspaceSymbolParticipant.java @@ -0,0 +1,246 @@ +/******************************************************************************* +* Copyright (c) 2023 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4mp.jdt.internal.jaxrs.java; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.IAnnotatable; +import org.eclipse.jdt.core.IAnnotation; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.ISourceRange; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.search.IJavaSearchConstants; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.core.search.SearchMatch; +import org.eclipse.jdt.core.search.SearchParticipant; +import org.eclipse.jdt.core.search.SearchPattern; +import org.eclipse.jdt.core.search.SearchRequestor; +import org.eclipse.jdt.internal.core.search.BasicSearchEngine; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; +import org.eclipse.lsp4mp.jdt.core.MicroProfileCorePlugin; +import org.eclipse.lsp4mp.jdt.core.java.symbols.IJavaWorkspaceSymbolsParticipant; +import org.eclipse.lsp4mp.jdt.core.jaxrs.JaxRsContext; +import org.eclipse.lsp4mp.jdt.core.jaxrs.JaxRsUtils; +import org.eclipse.lsp4mp.jdt.core.utils.AnnotationUtils; +import org.eclipse.lsp4mp.jdt.core.utils.IJDTUtils; +import org.eclipse.lsp4mp.jdt.internal.jaxrs.JaxRsConstants; +import org.eclipse.lsp4mp.jdt.internal.restclient.MicroProfileRestClientConstants; + +/** + * Collects workspace symbols for JAX-RS REST endpoints. + */ +public class JaxRsWorkspaceSymbolParticipant implements IJavaWorkspaceSymbolsParticipant { + + private static final Logger LOGGER = Logger.getLogger(JaxRsWorkspaceSymbolParticipant.class.getName()); + + private static final SearchPattern SEARCH_PATTERN; + static { + SearchPattern leftPattern = null; + for (String annotation : JaxRsConstants.HTTP_METHOD_ANNOTATIONS) { + if (leftPattern == null) { + leftPattern = annotationSearchPattern(annotation); + } else { + leftPattern = SearchPattern.createOrPattern(leftPattern, annotationSearchPattern(annotation)); + } + } + SEARCH_PATTERN = leftPattern; + } + + @Override + public void collectSymbols(IJavaProject project, IJDTUtils utils, List symbols, IProgressMonitor monitor) { + String applicationPrefix = getJaxApplicationPath(project); + SearchEngine engine = new SearchEngine(); + IJavaSearchScope scope = BasicSearchEngine.createJavaSearchScope(true, new IJavaElement[] { project }, + IJavaSearchScope.SOURCES); + Set annotatables = new HashSet<>(); + try { + engine.search(SEARCH_PATTERN, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() }, scope, + new SearchRequestor() { + + @Override + public void acceptSearchMatch(SearchMatch match) throws CoreException { + if (match.isInsideDocComment()) { + return; + } + + if (match.getElement() instanceof IAnnotation) { + annotatables.add((IAnnotatable) ((IAnnotation) match.getElement()).getParent()); + } else if (match.getElement() instanceof IAnnotatable) { + annotatables.add((IAnnotatable) match.getElement()); + } + } + + }, null); + } catch (CoreException | ClassCastException e) { + LOGGER.log(Level.SEVERE, + "While collecting symbols for project " + project.getResource().getLocationURI().toString(), e); + } + annotatables + .forEach(annotatable -> collectSymbolFromAnnotatable(symbols, annotatable, applicationPrefix, utils)); + } + + private void collectSymbolFromAnnotatable(List symbols, IAnnotatable annotatable, + String applicationPrefix, IJDTUtils utils) { + + if (!(annotatable instanceof IMethod)) { + return; + } + + IMethod method = (IMethod) annotatable; + try { + if (!Flags.isPublic(method.getFlags())) { + return; + } + } catch (JavaModelException e) { + return; + } + + String endpointUri = getEndpointUriFromAnnotatable(annotatable, applicationPrefix); + String httpMethods = getHttpMethodsFromAnnotatable(annotatable); + if (endpointUri == null || endpointUri.isEmpty() || httpMethods.isEmpty()) { + return; + } + + Location location = getLocationFromAnnotatable(method, utils); + if (location == null) { + return; + } + + StringBuilder nameBuilder = new StringBuilder("@"); + nameBuilder.append(endpointUri); + nameBuilder.append(": "); + nameBuilder.append(httpMethods); + + SymbolInformation symbol = new SymbolInformation(); + symbol.setName(nameBuilder.toString()); + symbol.setKind(SymbolKind.Method); + symbol.setLocation(location); + + symbols.add(symbol); + } + + private static Location getLocationFromAnnotatable(IMethod method, IJDTUtils utils) { + try { + String uri = method.getResource().getLocationURI().toString(); + ISourceRange r = method.getNameRange(); + Range range = utils.toRange(method.getOpenable(), r.getOffset(), r.getLength()); + if (range == null) { + return null; + } + return new Location(uri, range); + } catch (JavaModelException e) { + return null; + } + } + + private static String getEndpointUriFromAnnotatable(IAnnotatable annotatable, String applicationPrefix) { + StringBuilder builder = new StringBuilder(); + IAnnotatable current = annotatable; + + while (current != null && current != (IAnnotatable) ((IJavaElement) current).getAncestor(IJavaElement.TYPE)) { + if (hasRestClientAnnotation(current)) { + // This is not an endpoint, it's an interface to an outside service + return null; + } + prependPathSegment(builder, current); + current = (IAnnotatable) ((IJavaElement) current).getAncestor(IJavaElement.TYPE); + } + if (hasRestClientAnnotation(current)) { + return null; + } + if (current != null) { + prependPathSegment(builder, current); + } + if (applicationPrefix != null) { + builder.insert(0, applicationPrefix); + if (applicationPrefix.charAt(0) != '/') { + builder.insert(0, '/'); + } + } + return builder.toString(); + } + + private static void prependPathSegment(StringBuilder builder, IAnnotatable current) { + String pathValue = null; + try { + pathValue = JaxRsUtils.getJaxRsPathValue(current); + } catch (JavaModelException e) { + } + if (pathValue != null) { + builder.insert(0, pathValue); + if (pathValue.charAt(0) != '/') { + builder.insert(0, "/"); + } + } + } + + private static String getHttpMethodsFromAnnotatable(IAnnotatable annotatable) { + StringBuilder builder = new StringBuilder(); + for (String methodName : JaxRsConstants.HTTP_METHOD_ANNOTATIONS) { + if (hasAnnotation(annotatable, methodName)) { + if (builder.isEmpty()) { + builder.append(methodName.substring(methodName.lastIndexOf('.') + 1)); + } else { + builder.append("|"); + builder.append(methodName.substring(methodName.lastIndexOf('.') + 1)); + } + } + } + return builder.toString(); + } + + private static final SearchPattern annotationSearchPattern(String annotationFQN) { + return SearchPattern.createPattern(annotationFQN, IJavaSearchConstants.ANNOTATION_TYPE, + IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, SearchPattern.R_EXACT_MATCH); + } + + private static boolean hasRestClientAnnotation(IAnnotatable annotatable) { + return hasAnnotation(annotatable, MicroProfileRestClientConstants.REGISTER_REST_CLIENT_ANNOTATION); + } + + private static boolean hasAnnotation(IAnnotatable annotatable, String annotationSimpleName) { + try { + return AnnotationUtils.hasAnnotation(annotatable, annotationSimpleName); + } catch (JavaModelException e) { + return false; + } + } + + private static String getJaxApplicationPath(IJavaProject project) { + JaxRsContext jaxContext = new JaxRsContext(project); + try { + String prefix = jaxContext.getApplicationPath(null); + if (prefix == null || prefix.isEmpty()) { + return null; + } + return prefix; + } catch (CoreException e) { + return null; + } + } + +} diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/FakeResource.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/FakeResource.java new file mode 100644 index 000000000..22510fc6a --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/FakeResource.java @@ -0,0 +1,9 @@ +package org.acme.config; + +@Path("/api/endpoint") +public class FakeResource { + + @POST + public void postData(String info) { + } +} \ No newline at end of file diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/GreetingResource.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/GreetingResource.java index 4b276e837..ca64bde85 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/GreetingResource.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/GreetingResource.java @@ -3,6 +3,7 @@ import java.util.Optional; import javax.ws.rs.GET; +import javax.ws.rs.PATCH; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @@ -40,4 +41,9 @@ public String hello2() { public String hello3() { return message + " 4 " + name.orElse("world") + suffix; } + + @PATCH + @Path("hello5") + public String hello5() { + } } diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/POST.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/POST.java new file mode 100644 index 000000000..84b57de53 --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/POST.java @@ -0,0 +1,5 @@ +package org.acme.config; + +public @interface POST { + +} \ No newline at end of file diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/Path.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/Path.java new file mode 100644 index 000000000..b4ef7f9a8 --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/config-quickstart/src/main/java/org/acme/config/Path.java @@ -0,0 +1,5 @@ +package org.acme.config; + +public @interface Path { + String value(); +} \ No newline at end of file diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.classpath b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.classpath new file mode 100644 index 000000000..4559ca0b2 --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.classpath @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.gitignore b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.gitignore new file mode 100644 index 000000000..fef207d2f --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.gitignore @@ -0,0 +1,11 @@ +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar \ No newline at end of file diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.project b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.project new file mode 100644 index 000000000..d91ff3542 --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/.project @@ -0,0 +1,23 @@ + + + app-name + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/pom.xml b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/pom.xml new file mode 100644 index 000000000..541ab406b --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + com.demo + open-liberty + 1.0-SNAPSHOT + war + + + 11 + 11 + UTF-8 + + + + + jakarta.platform + jakarta.jakartaee-api + 9.1.0 + provided + + + org.eclipse.microprofile + microprofile + 5.0 + pom + provided + + + + + app-name + + + + org.apache.maven.plugins + maven-war-plugin + 3.3.2 + + + io.openliberty.tools + liberty-maven-plugin + 3.7.1 + + + + + + io.openliberty.tools + liberty-maven-plugin + + + + diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/java/com/demo/rest/MyResource.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/java/com/demo/rest/MyResource.java new file mode 100644 index 000000000..188294fbb --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/java/com/demo/rest/MyResource.java @@ -0,0 +1,18 @@ +package com.demo.rest; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +@Path("/api/resource") +public class MyResource { + + /** + * this is a documentation + * @return + */ + @GET + public String getMy() { + return "my"; + } + +} diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/java/com/demo/rest/RestApplication.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/java/com/demo/rest/RestApplication.java new file mode 100644 index 000000000..fbe023447 --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/java/com/demo/rest/RestApplication.java @@ -0,0 +1,9 @@ +package com.demo.rest; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +@ApplicationPath("/api") +public class RestApplication extends Application { + +} \ No newline at end of file diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/liberty/config/server.xml b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/liberty/config/server.xml new file mode 100644 index 000000000..6ac7a8060 --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/projects/maven/open-liberty/src/main/liberty/config/server.xml @@ -0,0 +1,42 @@ + + + + + + jakartaee-9.1 + microProfile-5.0 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/BasePropertiesManagerTest.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/BasePropertiesManagerTest.java index b029d59d4..1201b339a 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/BasePropertiesManagerTest.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/BasePropertiesManagerTest.java @@ -88,6 +88,7 @@ public static class MicroProfileMavenProjectName { public static String microprofile_jwt_quickstart = "microprofile-jwt-quickstart"; public static String rest_client_quickstart = "rest-client-quickstart"; public static String using_vertx = "using-vertx"; + public static String open_liberty = "open-liberty"; } diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/java/JaxRsApplicationPathCodeLensTest.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/java/JaxRsApplicationPathCodeLensTest.java index 9bca98e6f..30407877b 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/java/JaxRsApplicationPathCodeLensTest.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/java/JaxRsApplicationPathCodeLensTest.java @@ -108,6 +108,20 @@ public void urlCodeLensApplicationPathChange() throws Exception { assertCodeLense(8080, params, utils, "/ipa/path"); } + @Test + public void openLibertyJakarta() throws Exception { + IJavaProject javaProject = loadMavenProject(MicroProfileMavenProjectName.open_liberty); + IJDTUtils utils = JDT_UTILS; + + MicroProfileJavaCodeLensParams params = new MicroProfileJavaCodeLensParams(); + params.setCheckServerAvailable(false); + IFile javaFile = javaProject.getProject().getFile(new Path("src/main/java/com/demo/rest/MyResource.java")); + params.setUri(javaFile.getLocation().toFile().toURI().toString()); + params.setUrlCodeLensEnabled(true); + + assertCodeLense(8080, params, utils, "/api/api/resource"); + } + private static void assertCodeLense(int port, MicroProfileJavaCodeLensParams params, IJDTUtils utils, String actualEndpoint) throws JavaModelException { List lenses = PropertiesManagerForJava.getInstance().codeLens(params, utils, diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/java/JaxRsWorkspaceSymbolParticipantTest.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/java/JaxRsWorkspaceSymbolParticipantTest.java new file mode 100644 index 000000000..5a00351b9 --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.test/src/main/java/org/eclipse/lsp4mp/jdt/core/jaxrs/java/JaxRsWorkspaceSymbolParticipantTest.java @@ -0,0 +1,99 @@ +/******************************************************************************* +* Copyright (c) 2023 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4mp.jdt.core.jaxrs.java; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4mp.jdt.core.BasePropertiesManagerTest; +import org.eclipse.lsp4mp.jdt.core.PropertiesManagerForJava; +import org.eclipse.lsp4mp.jdt.core.utils.IJDTUtils; +import org.eclipse.lsp4mp.jdt.core.utils.JDTMicroProfileUtils; +import org.junit.Test; + +/** + * Tests for JaxRsWorkspaceSymbolParticipantTest. + */ +public class JaxRsWorkspaceSymbolParticipantTest extends BasePropertiesManagerTest { + + private static IProgressMonitor NULL_MONITOR = new NullProgressMonitor(); + + @Test + public void testConfigQuickstart() throws Exception { + IJavaProject javaProject = loadMavenProject(MicroProfileMavenProjectName.config_quickstart); + IJDTUtils utils = JDT_UTILS; + String projectUri = JDTMicroProfileUtils.getProjectURI(javaProject); + + List actual = PropertiesManagerForJava.getInstance().workspaceSymbols(projectUri, utils, NULL_MONITOR); + + assertWorkspaceSymbols(Arrays.asList( // + si("@/greeting/hello4: GET", 40, 18, 40, 24), si("@/greeting/constructor: GET", 34, 18, 34, 23), + si("@/greeting/hello: GET", 33, 18, 33, 24), si("@/greeting: GET", 26, 18, 26, 23), + si("@/greeting/method: GET", 38, 18, 38, 23), si("@/greeting/hello5: PATCH", 46, 18, 46, 24)), actual); + } + + @Test + public void testOpenLiberty() throws Exception { + IJavaProject javaProject = loadMavenProject(MicroProfileMavenProjectName.open_liberty); + IJDTUtils utils = JDT_UTILS; + String projectUri = JDTMicroProfileUtils.getProjectURI(javaProject); + + List actual = PropertiesManagerForJava.getInstance().workspaceSymbols(projectUri, utils, NULL_MONITOR); + + assertWorkspaceSymbols(Arrays.asList( // + si("@/api/api/resource: GET", 13, 15, 13, 20)), actual); + } + + private static void assertWorkspaceSymbols(List expected, List actual) { + assertEquals(expected.size(), actual.size()); + Collections.sort(expected, (si1, si2) -> si1.getName().compareTo(si2.getName())); + Collections.sort(actual, (si1, si2) -> si1.getName().compareTo(si2.getName())); + for (int i = 0; i < expected.size(); i++) { + assertSymbolInformation(expected.get(i), actual.get(i)); + } + } + + /** + * Asserts that the expected and actual symbol informations' name and range are + * the same. + * + * Doesn't check any of the other properties. + * + * @param expected the expected symbol information + * @param actual the actual symbol information + */ + private static void assertSymbolInformation(SymbolInformation expected, SymbolInformation actual) { + assertEquals(expected.getName(), actual.getName()); + assertEquals(expected.getLocation().getRange(), actual.getLocation().getRange()); + } + + private static SymbolInformation si(String name, int startLine, int startChar, int endLine, int endChar) { + SymbolInformation symbolInformation = new SymbolInformation(); + symbolInformation.setName(name); + Range range = new Range(new Position(startLine, startChar), new Position(endLine, endChar)); + Location location = new Location("", range); + symbolInformation.setLocation(location); + return symbolInformation; + } +} diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/commons/ProjectLabelInfoEntry.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/commons/ProjectLabelInfoEntry.java index 1ff187e43..ba6020ae4 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/commons/ProjectLabelInfoEntry.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/commons/ProjectLabelInfoEntry.java @@ -38,6 +38,8 @@ public ProjectLabelInfoEntry(String uri, String name, List labels) { /** * Returns the project uri + * + * FIXME: on Linux, this is actually an absolute path and not a uri. * * @return the project uri */ diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileLanguageServer.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileLanguageServer.java index b2ea710ca..d0cee988a 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileLanguageServer.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileLanguageServer.java @@ -17,6 +17,7 @@ import static org.eclipse.lsp4j.jsonrpc.CompletableFutures.computeAsync; import static org.eclipse.lsp4mp.utils.VersionHelper.getVersion; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -45,6 +46,7 @@ import org.eclipse.lsp4mp.ls.commons.ParentProcessWatcher.ProcessLanguageServer; import org.eclipse.lsp4mp.ls.commons.client.ExtendedClientCapabilities; import org.eclipse.lsp4mp.ls.commons.client.InitializationOptionsExtendedClientCapabilities; +import org.eclipse.lsp4mp.ls.java.JavaTextDocuments; import org.eclipse.lsp4mp.services.properties.PropertiesFileLanguageService; import org.eclipse.lsp4mp.settings.AllMicroProfileSettings; import org.eclipse.lsp4mp.settings.InitializationOptionsSettings; @@ -55,6 +57,7 @@ import org.eclipse.lsp4mp.settings.MicroProfileInlayHintSettings; import org.eclipse.lsp4mp.settings.MicroProfileSymbolSettings; import org.eclipse.lsp4mp.settings.MicroProfileValidationSettings; +import org.eclipse.lsp4mp.settings.SharedSettings; import org.eclipse.lsp4mp.settings.capabilities.MicroProfileCapabilityManager; import org.eclipse.lsp4mp.settings.capabilities.ServerCapabilitiesInitializer; @@ -70,6 +73,8 @@ public class MicroProfileLanguageServer implements LanguageServer, ProcessLangua private final PropertiesFileLanguageService propertiesFileLanguageService; private final MicroProfileTextDocumentService textDocumentService; private final WorkspaceService workspaceService; + private final SharedSettings sharedSettings; + private final JavaTextDocuments javaDocuments; private final MicroProfileExtensionSettings extensionSettings; @@ -78,9 +83,11 @@ public class MicroProfileLanguageServer implements LanguageServer, ProcessLangua private MicroProfileCapabilityManager capabilityManager; public MicroProfileLanguageServer() { + sharedSettings = new SharedSettings(); + javaDocuments = new JavaTextDocuments(this, this); propertiesFileLanguageService = new PropertiesFileLanguageService(); - textDocumentService = new MicroProfileTextDocumentService(this); - workspaceService = new MicroProfileWorkspaceService(this); + textDocumentService = new MicroProfileTextDocumentService(this, sharedSettings, javaDocuments); + workspaceService = new MicroProfileWorkspaceService(this, javaDocuments); this.extensionSettings = new MicroProfileExtensionSettings(); } @@ -224,9 +231,14 @@ public CompletableFuture getJsonSchemaForProjectInfo( } @Override - public CompletableFuture getJavaProjectlabels( + public CompletableFuture getJavaProjectLabels( MicroProfileJavaProjectLabelsParams javaParams) { - return getLanguageClient().getJavaProjectlabels(javaParams); + return getLanguageClient().getJavaProjectLabels(javaParams); + } + + @Override + public CompletableFuture> getAllJavaProjectLabels() { + return getLanguageClient().getAllJavaProjectLabels(); } @Override diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileTextDocumentService.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileTextDocumentService.java index cf851120f..e9146c9f4 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileTextDocumentService.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileTextDocumentService.java @@ -58,6 +58,7 @@ import org.eclipse.lsp4mp.ls.api.MicroProfileLanguageServerAPI.JsonSchemaForProjectInfo; import org.eclipse.lsp4mp.ls.commons.client.ExtendedClientCapabilities; import org.eclipse.lsp4mp.ls.java.JavaFileTextDocumentService; +import org.eclipse.lsp4mp.ls.java.JavaTextDocuments; import org.eclipse.lsp4mp.ls.properties.PropertiesFileTextDocumentService; import org.eclipse.lsp4mp.settings.MicroProfileCodeLensSettings; import org.eclipse.lsp4mp.settings.MicroProfileFormattingSettings; @@ -75,15 +76,15 @@ public class MicroProfileTextDocumentService implements TextDocumentService { private final Map textDocumentServicesMap; private final PropertiesFileTextDocumentService applicationPropertiesTextDocumentService; private final JavaFileTextDocumentService javaTextDocumentService; - private SharedSettings sharedSettings; + private final SharedSettings sharedSettings; - public MicroProfileTextDocumentService(MicroProfileLanguageServer microprofileLanguageServer) { + public MicroProfileTextDocumentService(MicroProfileLanguageServer microprofileLanguageServer, SharedSettings sharedSettings, JavaTextDocuments javaTextDocuments) { textDocumentServicesMap = new HashMap<>(); - this.sharedSettings = new SharedSettings(); + this.sharedSettings = sharedSettings; applicationPropertiesTextDocumentService = new PropertiesFileTextDocumentService(microprofileLanguageServer, sharedSettings); javaTextDocumentService = new JavaFileTextDocumentService(microprofileLanguageServer, - applicationPropertiesTextDocumentService, sharedSettings); + applicationPropertiesTextDocumentService, sharedSettings, javaTextDocuments); textDocumentServicesMap.put("properties", applicationPropertiesTextDocumentService); textDocumentServicesMap.put("java", javaTextDocumentService); } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileWorkspaceService.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileWorkspaceService.java index a377313dc..ca38d7162 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileWorkspaceService.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/MicroProfileWorkspaceService.java @@ -13,9 +13,21 @@ *******************************************************************************/ package org.eclipse.lsp4mp.ls; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + import org.eclipse.lsp4j.DidChangeConfigurationParams; import org.eclipse.lsp4j.DidChangeWatchedFilesParams; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.WorkspaceSymbol; +import org.eclipse.lsp4j.WorkspaceSymbolParams; +import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.services.WorkspaceService; +import org.eclipse.lsp4mp.ls.java.JavaTextDocuments; /** * MicroProfile workspace service. @@ -23,10 +35,14 @@ */ public class MicroProfileWorkspaceService implements WorkspaceService { + private static final Logger LOGGER = Logger.getLogger(MicroProfileWorkspaceService.class.getName()); + private final MicroProfileLanguageServer microprofileLanguageServer; + private final JavaTextDocuments javaTextDocuments; - public MicroProfileWorkspaceService(MicroProfileLanguageServer microprofileLanguageServer) { + public MicroProfileWorkspaceService(MicroProfileLanguageServer microprofileLanguageServer, JavaTextDocuments javaTextDocuments) { this.microprofileLanguageServer = microprofileLanguageServer; + this.javaTextDocuments = javaTextDocuments; } @Override @@ -39,4 +55,36 @@ public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) { } + @Override + public CompletableFuture, List>> symbol( + WorkspaceSymbolParams params) { + return javaTextDocuments.getWorkspaceProjects() // + .thenCompose(workspaceProjects -> { + + List>> symbolFutures = workspaceProjects.stream() // + .map(projectLabelInfo -> { + String uri = projectLabelInfo.getUri(); + return microprofileLanguageServer.getLanguageClient().getJavaWorkspaceSymbols(uri); + }) // + .collect(Collectors.toList()); + + // NOTE: we don't need to implement resolve, because resolve is just + // for calculating the source range. The source range is very cheap to calculate + // in comparison to invoking the search engine to locate the symbols. + + return CompletableFuture + .allOf((CompletableFuture[]) symbolFutures.stream().toArray(CompletableFuture[]::new)) + .exceptionally(e -> { + LOGGER.log(Level.SEVERE, "Failure while collecting symbols", e); + return null; + }).thenApply(_void -> { + return Either.forLeft(symbolFutures.stream() // + .flatMap(projectSymbolsFuture -> { + return projectSymbolsFuture.getNow(Collections.emptyList()).stream(); + }) // + .collect(Collectors.toList())); + }); + }); + } + } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileJavaProjectLabelsProvider.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileJavaProjectLabelsProvider.java index b2951ee55..6f35a1d01 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileJavaProjectLabelsProvider.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileJavaProjectLabelsProvider.java @@ -13,6 +13,7 @@ *******************************************************************************/ package org.eclipse.lsp4mp.ls.api; +import java.util.List; import java.util.concurrent.CompletableFuture; import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; @@ -28,9 +29,14 @@ public interface MicroProfileJavaProjectLabelsProvider { @JsonRequest("microprofile/java/projectLabels") - default CompletableFuture getJavaProjectlabels( + default CompletableFuture getJavaProjectLabels( MicroProfileJavaProjectLabelsParams javaParams) { return CompletableFuture.completedFuture(null); } + @JsonRequest("microprofile/java/workspaceLabels") + default CompletableFuture> getAllJavaProjectLabels() { + return CompletableFuture.completedFuture(null); + } + } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileJavaWorkspaceSymbolsProvider.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileJavaWorkspaceSymbolsProvider.java new file mode 100644 index 000000000..53dab056b --- /dev/null +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileJavaWorkspaceSymbolsProvider.java @@ -0,0 +1,34 @@ +/******************************************************************************* +* Copyright (c) 2023 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4mp.ls.api; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; + +/** + * Provides the workspace symbols given the project uri. + * + * @author datho7561 + */ +public interface MicroProfileJavaWorkspaceSymbolsProvider { + + @JsonRequest("microprofile/java/workspaceSymbols") + default CompletableFuture> getJavaWorkspaceSymbols(String projectUri) { + return CompletableFuture.completedFuture(null); + } + +} diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileLanguageClientAPI.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileLanguageClientAPI.java index a113df261..f727f103b 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileLanguageClientAPI.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/api/MicroProfileLanguageClientAPI.java @@ -26,6 +26,6 @@ public interface MicroProfileLanguageClientAPI MicroProfilePropertyDocumentationProvider, MicroProfileJavaCodeActionProvider, MicroProfileJavaCodeLensProvider, MicroProfileJavaCompletionProvider, MicroProfileJavaDiagnosticsProvider, MicroProfileJavaDefinitionProvider, MicroProfileJavaHoverProvider, MicroProfileJavaProjectLabelsProvider, MicroProfileJavaFileInfoProvider, - MicroProfileJavaCodeActionResolveProvider, MicroProfileJavaCursorContextProvider { + MicroProfileJavaCodeActionResolveProvider, MicroProfileJavaCursorContextProvider, MicroProfileJavaWorkspaceSymbolsProvider { } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java index b7e7be51b..19a62353c 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java @@ -93,10 +93,10 @@ public class JavaFileTextDocumentService extends AbstractTextDocumentService { private ValidatorDelayer validatorDelayer; public JavaFileTextDocumentService(MicroProfileLanguageServer microprofileLanguageServer, - IPropertiesModelProvider propertiesModelProvider, SharedSettings sharedSettings) { + IPropertiesModelProvider propertiesModelProvider, SharedSettings sharedSettings, JavaTextDocuments javaTextDocuments) { super(microprofileLanguageServer, sharedSettings); this.propertiesModelProvider = propertiesModelProvider; - this.documents = new JavaTextDocuments(microprofileLanguageServer, microprofileLanguageServer); + this.documents = javaTextDocuments; this.validatorDelayer = new ValidatorDelayer<>((javaTextDocument) -> { triggerValidationFor(javaTextDocument); }); diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaTextDocuments.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaTextDocuments.java index e1f8d5d7c..b57626050 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaTextDocuments.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaTextDocuments.java @@ -13,6 +13,7 @@ *******************************************************************************/ package org.eclipse.lsp4mp.ls.java; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -22,6 +23,7 @@ import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import org.eclipse.lsp4j.TextDocumentItem; import org.eclipse.lsp4j.jsonrpc.CancelChecker; @@ -44,7 +46,7 @@ * @author Angelo ZERR * */ -class JavaTextDocuments extends TextDocuments { +public class JavaTextDocuments extends TextDocuments { private static final String MICROPROFILE_PROJECT_LABEL = "microprofile"; @@ -62,6 +64,8 @@ class JavaTextDocuments extends TextDocuments { private JavaTextDocumentSnippetRegistry snippetRegistry; + private boolean hasLoadedAllProjects = false; + /** * Opened Java file. * @@ -191,7 +195,7 @@ public boolean isInMicroProfileProject() { } } - JavaTextDocuments(MicroProfileJavaProjectLabelsProvider projectInfoProvider, + public JavaTextDocuments(MicroProfileJavaProjectLabelsProvider projectInfoProvider, MicroProfileJavaFileInfoProvider fileInfoProvider) { this.projectInfoProvider = projectInfoProvider; this.fileInfoProvider = fileInfoProvider; @@ -241,7 +245,7 @@ CompletableFuture getProjectInfoFromCache(JavaTextDocumen MicroProfileJavaProjectLabelsParams params = new MicroProfileJavaProjectLabelsParams(); params.setUri(documentURI); params.setTypes(getSnippetRegistry().getTypes()); - final CompletableFuture future = projectInfoProvider.getJavaProjectlabels(params); + final CompletableFuture future = projectInfoProvider.getJavaProjectLabels(params); future.thenApply(entry -> { if (entry != null) { // project info with labels are get from the JDT LS @@ -264,6 +268,49 @@ CompletableFuture getProjectInfoFromCache(JavaTextDocumen return projectInfo; } + /** + * Returns a list of all projects in the current workspace as a completable + * future + * + * Loads and caches any projects that have not yet been loaded into the cache. + * + * @returns a list of all projects in the current workspace as a completable + * future + */ + public CompletableFuture> getWorkspaceProjects() { + if (!hasLoadedAllProjects) { + return projectInfoProvider.getAllJavaProjectLabels() // + .thenApply(entries -> { + if (entries != null && entries.size() > 0) { + for (ProjectLabelInfoEntry entry : entries) { + if (entry != null) { + String newProjectURI = entry.getUri(); + if (!projectCache.containsKey(newProjectURI)) { + projectCache.put(newProjectURI, CompletableFuture.completedFuture(entry)); + } + } + } + } + hasLoadedAllProjects = true; + return entries; + }); + } + + // otherwise the list of all projects is cached + Collection> projectLabelFutures = projectCache.values(); + return CompletableFuture + .allOf((CompletableFuture[]) projectLabelFutures.stream().toArray(CompletableFuture[]::new)) // + .thenApply(voidFuture -> { + return projectLabelFutures.stream() // + .map(futureProject -> { + return futureProject.getNow(null); + }) // + .filter(project -> project != null) // + .distinct() // + .collect(Collectors.toList()); + }); + } + public boolean propertiesChanged(MicroProfilePropertiesChangeEvent event) { List scopes = event.getType(); boolean changedOnlyInSources = MicroProfilePropertiesScope.isOnlySources(scopes); diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ClientCapabilitiesWrapper.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ClientCapabilitiesWrapper.java index 986ff8eeb..26ba76bb7 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ClientCapabilitiesWrapper.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ClientCapabilitiesWrapper.java @@ -17,6 +17,7 @@ import org.eclipse.lsp4j.DynamicRegistrationCapabilities; import org.eclipse.lsp4j.ResourceOperationKind; import org.eclipse.lsp4j.TextDocumentClientCapabilities; +import org.eclipse.lsp4j.WorkspaceClientCapabilities; import org.eclipse.lsp4mp.ls.commons.client.ExtendedClientCapabilities; /** @@ -78,6 +79,10 @@ public boolean isFormattingDynamicRegistered() { public boolean isRangeFormattingDynamicRegistered() { return v3Supported && isDynamicRegistrationSupported(getTextDocument().getRangeFormatting()); } + + public boolean isWorkspaceSymbolDynamicRegistered() { + return v3Supported && isDynamicRegistrationSupported(getWorkspace().getSymbol()); + } public boolean isDocumentHighlightSupported() { return v3Supported && isDynamicRegistrationSupported(getTextDocument().getDocumentHighlight()); @@ -91,6 +96,10 @@ private boolean isDynamicRegistrationSupported(DynamicRegistrationCapabilities c public TextDocumentClientCapabilities getTextDocument() { return this.capabilities.getTextDocument(); } + + public WorkspaceClientCapabilities getWorkspace() { + return this.capabilities.getWorkspace(); + } public ExtendedClientCapabilities getExtendedCapabilities() { return extendedCapabilities; @@ -131,4 +140,5 @@ public boolean isCodeActionResolveSupported() { && capabilities.getTextDocument().getCodeAction().getResolveSupport().getProperties() != null && capabilities.getTextDocument().getCodeAction().getResolveSupport().getProperties().contains("edit"); } + } \ No newline at end of file diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/MicroProfileCapabilityManager.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/MicroProfileCapabilityManager.java index cb08ec79a..f96b03f27 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/MicroProfileCapabilityManager.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/MicroProfileCapabilityManager.java @@ -35,6 +35,9 @@ import static org.eclipse.lsp4mp.settings.capabilities.ServerCapabilitiesConstants.TEXT_DOCUMENT_HOVER; import static org.eclipse.lsp4mp.settings.capabilities.ServerCapabilitiesConstants.TEXT_DOCUMENT_INLAY_HINT; import static org.eclipse.lsp4mp.settings.capabilities.ServerCapabilitiesConstants.TEXT_DOCUMENT_RANGE_FORMATTING; +import static org.eclipse.lsp4mp.settings.capabilities.ServerCapabilitiesConstants.WORKSPACE_SYMBOL_ID; +import static org.eclipse.lsp4mp.settings.capabilities.ServerCapabilitiesConstants.WORKSPACE_SYMBOLS; +import static org.eclipse.lsp4mp.settings.capabilities.ServerCapabilitiesConstants.DEFAULT_WORKSPACE_SYMBOL_OPTIONS; import java.util.ArrayList; import java.util.Collections; @@ -120,6 +123,9 @@ public void initializeCapabilities() { if (this.getClientCapabilities().isInlayHintDynamicRegistered()) { registerCapability(INLAY_HINT_ID, TEXT_DOCUMENT_INLAY_HINT); } + if (this.getClientCapabilities().isWorkspaceSymbolDynamicRegistered()) { + registerCapability(WORKSPACE_SYMBOL_ID, WORKSPACE_SYMBOLS, DEFAULT_WORKSPACE_SYMBOL_OPTIONS); + } } private TextDocumentRegistrationOptions getFormattingRegistrationOptions() { diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ServerCapabilitiesConstants.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ServerCapabilitiesConstants.java index 216b4adec..d1108a79e 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ServerCapabilitiesConstants.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ServerCapabilitiesConstants.java @@ -19,6 +19,7 @@ import org.eclipse.lsp4j.CodeActionOptions; import org.eclipse.lsp4j.CodeLensOptions; import org.eclipse.lsp4j.CompletionOptions; +import org.eclipse.lsp4j.WorkspaceSymbolOptions; /** * Server Capabilities Constants @@ -38,6 +39,8 @@ private ServerCapabilitiesConstants() { public static final String TEXT_DOCUMENT_CODE_LENS = "textDocument/codeLens"; public static final String TEXT_DOCUMENT_DOCUMENT_HIGHLIGHT = "textDocument/documentHighlight"; public static final String TEXT_DOCUMENT_INLAY_HINT = "textDocument/inlayHint"; + + public static final String WORKSPACE_SYMBOLS = "workspace/symbol"; public static final String COMPLETION_ID = UUID.randomUUID().toString(); public static final String HOVER_ID = UUID.randomUUID().toString(); @@ -48,8 +51,9 @@ private ServerCapabilitiesConstants() { public static final String CODE_ACTION_ID = UUID.randomUUID().toString(); public static final String CODE_LENS_ID = UUID.randomUUID().toString(); public static final String DOCUMENT_HIGHLIGHT_ID = UUID.randomUUID().toString(); - public static final String INLAY_HINT_ID = UUID.randomUUID().toString(); + + public static final String WORKSPACE_SYMBOL_ID = UUID.randomUUID().toString(); public static final CompletionOptions DEFAULT_COMPLETION_OPTIONS = new CompletionOptions(false, Arrays.asList(".", "%", "=", "$", "{", ":" /* triggered characters for properties file */ , @@ -59,10 +63,13 @@ private ServerCapabilitiesConstants() { public static final CodeLensOptions DEFAULT_CODELENS_OPTIONS = new CodeLensOptions(); public static final CodeActionOptions DEFAULT_CODEACTION_OPTIONS = createDefaultCodeActionOptions(); + + public static final WorkspaceSymbolOptions DEFAULT_WORKSPACE_SYMBOL_OPTIONS = new WorkspaceSymbolOptions(false); private static CodeActionOptions createDefaultCodeActionOptions() { CodeActionOptions options = new CodeActionOptions(); options.setResolveProvider(Boolean.TRUE); return options; } + } \ No newline at end of file diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ServerCapabilitiesInitializer.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ServerCapabilitiesInitializer.java index 73671707a..259b22a80 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ServerCapabilitiesInitializer.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ServerCapabilitiesInitializer.java @@ -56,6 +56,7 @@ public static ServerCapabilities getNonDynamicServerCapabilities(ClientCapabilit serverCapabilities.setCodeActionProvider(DEFAULT_CODEACTION_OPTIONS); } serverCapabilities.setInlayHintProvider(!clientCapabilities.isInlayHintDynamicRegistered()); + serverCapabilities.setWorkspaceSymbolProvider(!clientCapabilities.isWorkspaceSymbolDynamicRegistered()); return serverCapabilities; } } \ No newline at end of file diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/ls/deadlock/MicroProfileLanguageServerDeadlockTest.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/ls/deadlock/MicroProfileLanguageServerDeadlockTest.java index a3f391d46..4b2644003 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/ls/deadlock/MicroProfileLanguageServerDeadlockTest.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/ls/deadlock/MicroProfileLanguageServerDeadlockTest.java @@ -81,7 +81,7 @@ public void logMessage(MessageParams message) { } @Override - public CompletableFuture getJavaProjectlabels(MicroProfileJavaProjectLabelsParams javaParams) { + public CompletableFuture getJavaProjectLabels(MicroProfileJavaProjectLabelsParams javaParams) { latch.countDown(); return CompletableFuture.completedFuture(null); } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/ls/java/JavaTextDocumentsTest.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/ls/java/JavaTextDocumentsTest.java index 939b3f8fb..482498cc3 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/ls/java/JavaTextDocumentsTest.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/ls/java/JavaTextDocumentsTest.java @@ -40,7 +40,7 @@ public class JavaTextDocumentsTest { private static MicroProfileJavaProjectLabelsProvider PROVIDER = new MicroProfileJavaProjectLabelsProvider() { @Override - public CompletableFuture getJavaProjectlabels( + public CompletableFuture getJavaProjectLabels( MicroProfileJavaProjectLabelsParams javaParams) { String uri = javaParams.getUri(); List labels = null;