-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #1114 Signed-off-by: azerr <[email protected]>
- Loading branch information
1 parent
9b9fc6a
commit 6d53a63
Showing
6 changed files
with
303 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
.../java/com/redhat/microprofile/psi/internal/quarkus/route/java/ReactiveRouteConstants.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Red Hat Inc. and others. | ||
* All rights reserved. This program and the accompanying materials | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package com.redhat.microprofile.psi.internal.quarkus.route.java; | ||
|
||
/** | ||
* Reactive route constants. | ||
* | ||
* @see <a href="https://quarkus.io/guides/reactive-routes#declaring-reactive-routes">https://quarkus.io/guides/reactive-routes#declaring-reactive-routes</a> | ||
*/ | ||
public class ReactiveRouteConstants { | ||
|
||
public static final String ROUTE_BASE_FQN = "io.quarkus.vertx.web.RouteBase"; | ||
|
||
public static final String ROUTE_BASE_PATH = "path"; | ||
|
||
public static final String ROUTE_FQN = "io.quarkus.vertx.web.Route"; | ||
|
||
public static final String ROUTE_PATH = "path"; | ||
|
||
public static final String REACTIVE_ROUTE_GET_ANNOTATION = "io.quarkus.vertx.web.Route.HttpMethod.GET"; | ||
} |
159 changes: 159 additions & 0 deletions
159
...m/redhat/microprofile/psi/internal/quarkus/route/java/ReactiveRouteJaxRsInfoProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Red Hat Inc. and others. | ||
* All rights reserved. This program and the accompanying materials | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package com.redhat.microprofile.psi.internal.quarkus.route.java; | ||
|
||
|
||
import com.intellij.openapi.module.Module; | ||
import com.intellij.openapi.progress.ProcessCanceledException; | ||
import com.intellij.openapi.progress.ProgressIndicator; | ||
import com.intellij.psi.*; | ||
import com.intellij.util.KeyedLazyInstanceEP; | ||
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils; | ||
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.jaxrs.*; | ||
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.IPsiUtils; | ||
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.PsiTypeUtils; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
|
||
import static com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.PsiTypeUtils.overlaps; | ||
import static com.redhat.microprofile.psi.internal.quarkus.route.java.ReactiveRouteConstants.ROUTE_FQN; | ||
|
||
/** | ||
* Use custom logic for all JAX-RS features for Reactive @Route. | ||
* | ||
* @see <a href="https://quarkus.io/guides/reactive-routes#declaring-reactive-routes">https://quarkus.io/guides/reactive-routes#declaring-reactive-routes</a> | ||
*/ | ||
public class ReactiveRouteJaxRsInfoProvider extends KeyedLazyInstanceEP<IJaxRsInfoProvider> implements IJaxRsInfoProvider { | ||
|
||
private static final Logger LOGGER = Logger.getLogger(ReactiveRouteJaxRsInfoProvider.class.getName()); | ||
|
||
@Override | ||
public boolean canProvideJaxRsMethodInfoForClass(PsiFile typeRoot, Module javaProject, ProgressIndicator monitor) { | ||
return PsiTypeUtils.findType(javaProject, ROUTE_FQN) != null; | ||
} | ||
|
||
@Override | ||
public Set<PsiClass> getAllJaxRsClasses(Module javaProject, ProgressIndicator monitor) { | ||
// TODO: implement when LSP4IJ will support workspace symbols | ||
return Collections.emptySet(); | ||
} | ||
|
||
@Override | ||
public List<JaxRsMethodInfo> getJaxRsMethodInfo(PsiFile typeRoot, JaxRsContext jaxrsContext, IPsiUtils utils, | ||
ProgressIndicator monitor) { | ||
try { | ||
PsiClass type = findFirstClass(typeRoot); | ||
if (type == null) { | ||
return Collections.emptyList(); | ||
} | ||
// See https://quarkus.io/guides/reactive-routes#routebase | ||
// Try to get the @RouteBase declared in the Java type | ||
|
||
PsiAnnotation routeBaseAnnotation = ReactiveRouteUtils.getRouteBaseAnnotation(type); | ||
String pathSegment = routeBaseAnnotation != null ? ReactiveRouteUtils.getRouteBasePath(routeBaseAnnotation) : null; | ||
|
||
List<JaxRsMethodInfo> methodInfos = new ArrayList<>(); | ||
for (PsiMethod method : type.getMethods()) { | ||
|
||
if (method.isConstructor() || utils.isHiddenGeneratedElement(method)) { | ||
continue; | ||
} | ||
// ignore element if method range overlaps the type range, | ||
// happens for generated | ||
// bytecode, i.e. with lombok | ||
if (overlaps(type.getNameIdentifier().getTextRange(), method.getNameIdentifier().getTextRange())) { | ||
continue; | ||
} | ||
|
||
// A route method must be a non-private non-static method of a CDI bean. | ||
// See https://quarkus.io/guides/reactive-routes#reactive-route-methods | ||
if (!method.getModifierList().hasExplicitModifier(PsiModifier.PRIVATE) && !method.getModifierList().hasExplicitModifier(PsiModifier.STATIC)) { | ||
|
||
// Method can have several @Route | ||
// @Route(path = "/first") | ||
// @Route(path = "/second") | ||
// public void route(RoutingContext rc) { | ||
// // ... | ||
List<PsiAnnotation> routeAnnotations = ReactiveRouteUtils.getRouteAnnotations(method); | ||
if (routeAnnotations.isEmpty()) { | ||
continue; | ||
} | ||
|
||
// Loop for @Route annotation | ||
for (PsiAnnotation routeAnnotation : routeAnnotations) { | ||
// @Route(path = "/first") | ||
String methodSegment = ReactiveRouteUtils.getRoutePath(routeAnnotation); | ||
if (methodSegment == null) { | ||
// @Route(methods = Route.HttpMethod.GET) | ||
// void hello(RoutingContext rc) | ||
// Here the segment is the method name | ||
methodSegment = method.getName(); | ||
} | ||
String path; | ||
if (pathSegment == null) { | ||
path = methodSegment; | ||
} else { | ||
path = JaxRsUtils.buildURL(pathSegment, methodSegment); | ||
} | ||
String url = JaxRsUtils.buildURL(jaxrsContext.getLocalBaseURL(), path); | ||
|
||
JaxRsMethodInfo methodInfo = createMethodInfo(method, routeAnnotation, url); | ||
if (methodInfo != null) { | ||
methodInfos.add(methodInfo); | ||
} | ||
} | ||
} | ||
} | ||
return methodInfos; | ||
} catch (ProcessCanceledException e) { | ||
throw e; | ||
} catch (Exception e) { | ||
LOGGER.log(Level.SEVERE, "Error while collecting JAX-RS methods for Reactive @Route", e); | ||
return Collections.emptyList(); | ||
} | ||
} | ||
|
||
private PsiClass findFirstClass(PsiFile typeRoot) { | ||
for (PsiElement element : typeRoot.getChildren()) { | ||
if (element instanceof PsiClass) { | ||
return (PsiClass) element; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
private static JaxRsMethodInfo createMethodInfo(PsiMethod method, PsiAnnotation routeAnnotation, String url) { | ||
|
||
PsiFile resource = method.getContainingFile(); | ||
if (resource == null) { | ||
return null; | ||
} | ||
String documentUri = LSPIJUtils.toUriAsString(resource); | ||
|
||
HttpMethod httpMethod = HttpMethod.GET; | ||
// TODO: collect the proper http method from @Route(methods=) | ||
/*for (String methodAnnotationFQN : JaxRsConstants.HTTP_METHOD_ANNOTATIONS) { | ||
if (hasAnnotation(method, methodAnnotationFQN)) { | ||
httpMethod = ReactiveRouteUtils.getHttpMethodForAnnotation(methodAnnotationFQN); | ||
break; | ||
} | ||
}*/ | ||
|
||
return new JaxRsMethodInfo(url, httpMethod, method, documentUri); | ||
} | ||
|
||
} |
86 changes: 86 additions & 0 deletions
86
...main/java/com/redhat/microprofile/psi/internal/quarkus/route/java/ReactiveRouteUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/******************************************************************************* | ||
* 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 com.redhat.microprofile.psi.internal.quarkus.route.java; | ||
|
||
import com.intellij.psi.PsiAnnotation; | ||
import com.intellij.psi.PsiElement; | ||
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.jaxrs.HttpMethod; | ||
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.jaxrs.JaxRsConstants; | ||
|
||
import java.util.List; | ||
|
||
import static com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.AnnotationUtils.*; | ||
import static com.redhat.microprofile.psi.internal.quarkus.route.java.ReactiveRouteConstants.*; | ||
|
||
|
||
/** | ||
* Reactive @Route utilities. | ||
* | ||
* @see <a href="https://quarkus.io/guides/reactive-routes#declaring-reactive-routes">https://quarkus.io/guides/reactive-routes#declaring-reactive-routes</a> | ||
*/ | ||
public class ReactiveRouteUtils { | ||
|
||
private ReactiveRouteUtils() { | ||
|
||
} | ||
|
||
public static PsiAnnotation getRouteBaseAnnotation(PsiElement annotatable) { | ||
return getFirstAnnotation(annotatable, ROUTE_BASE_FQN); | ||
} | ||
|
||
public static String getRouteBasePath(PsiAnnotation routeBaseAnnotation) { | ||
return getAnnotationMemberValue(routeBaseAnnotation, ROUTE_BASE_PATH); | ||
} | ||
|
||
public static List<PsiAnnotation> getRouteAnnotations(PsiElement annotatable) { | ||
return getAllAnnotations(annotatable, ROUTE_FQN); | ||
} | ||
|
||
public static String getRoutePath(PsiAnnotation routeAnnotation) { | ||
return getAnnotationMemberValue(routeAnnotation, ROUTE_PATH); | ||
} | ||
|
||
/** | ||
* Returns an HttpMethod given the FQN of a JAX-RS or Jakarta RESTful | ||
* annotation, nor null if the FQN doesn't match any HttpMethod. | ||
* | ||
* @param annotationFQN the FQN of the annotation to convert into a HttpMethod | ||
* @return an HttpMethod given the FQN of a JAX-RS or Jakarta RESTful | ||
* annotation, nor null if the FQN doesn't match any HttpMethod | ||
*/ | ||
public static HttpMethod getHttpMethodForAnnotation(String annotationFQN) { | ||
switch (annotationFQN) { | ||
case ReactiveRouteConstants.REACTIVE_ROUTE_GET_ANNOTATION: | ||
case JaxRsConstants.JAVAX_WS_RS_GET_ANNOTATION: | ||
return HttpMethod.GET; | ||
case JaxRsConstants.JAKARTA_WS_RS_HEAD_ANNOTATION: | ||
case JaxRsConstants.JAVAX_WS_RS_HEAD_ANNOTATION: | ||
return HttpMethod.HEAD; | ||
case JaxRsConstants.JAKARTA_WS_RS_POST_ANNOTATION: | ||
case JaxRsConstants.JAVAX_WS_RS_POST_ANNOTATION: | ||
return HttpMethod.POST; | ||
case JaxRsConstants.JAKARTA_WS_RS_PUT_ANNOTATION: | ||
case JaxRsConstants.JAVAX_WS_RS_PUT_ANNOTATION: | ||
return HttpMethod.PUT; | ||
case JaxRsConstants.JAKARTA_WS_RS_DELETE_ANNOTATION: | ||
case JaxRsConstants.JAVAX_WS_RS_DELETE_ANNOTATION: | ||
return HttpMethod.DELETE; | ||
case JaxRsConstants.JAKARTA_WS_RS_PATCH_ANNOTATION: | ||
case JaxRsConstants.JAVAX_WS_RS_PATCH_ANNOTATION: | ||
return HttpMethod.PATCH; | ||
default: | ||
return null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters