From 0e70a34b0201d1a9776b8e436949a3585e213416 Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Tue, 20 Nov 2018 16:32:45 -0500 Subject: [PATCH] PT #162139447: Fix live RM actuator data parsing --- .../Boot20DispatcherServletMapping.java | 50 +++++++++++++++-- .../app/cli/Boot2xRequestMappingsTest.java | 23 ++++++-- .../BeanInjectedIntoHoverProvider.java | 21 +------- .../RequestMappingHoverProvider.java | 54 +++++++++++++++++++ .../ide/vscode/boot/java/utils/ASTUtils.java | 17 ++++++ 5 files changed, 137 insertions(+), 28 deletions(-) diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/requestmappings/Boot20DispatcherServletMapping.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/requestmappings/Boot20DispatcherServletMapping.java index a55a51c15..5f8e20636 100644 --- a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/requestmappings/Boot20DispatcherServletMapping.java +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/requestmappings/Boot20DispatcherServletMapping.java @@ -10,8 +10,10 @@ *******************************************************************************/ package org.springframework.ide.vscode.commons.boot.app.cli.requestmappings; +import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; import org.json.JSONArray; @@ -60,6 +62,10 @@ Example entry: return data.optJSONObject("details"); } + private String getPredicate() { + return data.optString("predicate"); + } + private JSONObject getHandlerMethod() { JSONObject details = getDetails(); if (details != null) { @@ -72,6 +78,16 @@ Example entry: return null; } + private JSONObject getHandlerFunction() { + JSONObject details = getDetails(); + if (details != null) { + if (details.has("handlerFunction")) { + return details.getJSONObject("handlerFunction"); + } + } + return null; + } + private JSONObject getRequestMappingConditions() { JSONObject details = getDetails(); return details == null ? null : details.optJSONObject("requestMappingConditions"); @@ -82,11 +98,17 @@ Example entry: return data.optString("handler"); } - @Override public String getFullyQualifiedClassName() { JSONObject handlerMethod = getHandlerMethod(); - return handlerMethod == null ? null : handlerMethod.getString("className"); + if (handlerMethod != null) { + return handlerMethod.getString("className"); + } + JSONObject handlerFunction = getHandlerFunction(); + if (handlerFunction != null) { + return handlerFunction.getString("className"); + } + return null; } @Override @@ -114,7 +136,20 @@ Example entry: public String[] getSplitPath() { JSONObject rmConditions = getRequestMappingConditions(); if (rmConditions == null) { - return new String[0]; + String predicate = getPredicate(); + if (predicate != null) { + // Predicate is and/or string expression: ((GET && /hello) && Accept: [text/plain]) + String[] tokens = predicate.split("\\w*(&&|\\|\\|)\\w*"); + List splitPaths = new ArrayList<>(tokens.length); + for (String t : tokens) { + // Remove leading `(`, trailing `)` + String token = removeLeadingAndTrailingParenthises(t); + if (!token.isEmpty() && token.charAt(0) == '/') { + splitPaths.add(token); + } + } + return splitPaths.toArray(new String[splitPaths.size()]); + } } else { JSONArray jsonArray = rmConditions.getJSONArray("patterns"); String[] paths = new String[jsonArray.length()]; @@ -123,6 +158,15 @@ Example entry: } return paths; } + return new String[0]; + } + + private static String removeLeadingAndTrailingParenthises(String s) { + int start = 0; + int end = s.length(); + for(; start < s.length() && (s.charAt(start) == '(' || Character.isWhitespace(s.charAt(start))); start++); + for(; end > start && (s.charAt(end - 1) == ')' || Character.isWhitespace(s.charAt(end - 1))); end--); + return start <= end ? s.substring(start, end) : ""; } @Override diff --git a/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/Boot2xRequestMappingsTest.java b/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/Boot2xRequestMappingsTest.java index 424d47285..07c35f555 100644 --- a/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/Boot2xRequestMappingsTest.java +++ b/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/Boot2xRequestMappingsTest.java @@ -34,12 +34,15 @@ public class Boot2xRequestMappingsTest { ImmutableSet expected = ImmutableSet.of( "/error", + "/**/favicon.ico", "/actuator", "/actuator/health", "/actuator/info", "/hello", "/qq", - "/pp" + "/pp", + "/webjars/**", + "/**" ); assertEquals(expected, rms.stream() @@ -60,9 +63,11 @@ public class Boot2xRequestMappingsTest { "/actuator", "/actuator/health", "/actuator/info", + "/webjars/**", "/hello", "/pp", - "/qq" + "/qq", + "/**" ); assertEquals(expected, rms.stream() @@ -81,7 +86,10 @@ public class Boot2xRequestMappingsTest { ImmutableSet expected = ImmutableSet.of( "/actuator", "/actuator/health", - "/actuator/info" + "/actuator/info", + "/webjars/**", + "/hello", + "/**" ); assertEquals(expected, rms.stream() @@ -98,10 +106,13 @@ public class Boot2xRequestMappingsTest { ImmutableSet expected = ImmutableSet.of( "/error", + "/**/favicon.ico", "/actuator", + "/welcome", "/actuator/health", "/actuator/info", - "/welcome" + "/webjars/**", + "/**" ); assertEquals(expected, rms.stream() @@ -121,7 +132,9 @@ public class Boot2xRequestMappingsTest { "/actuator", "/actuator/health", "/actuator/info", - "/welcome" + "/welcome", + "/webjars/**", + "/**" ); assertEquals(expected, rms.stream() diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/BeanInjectedIntoHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/BeanInjectedIntoHoverProvider.java index 3ed8e2cf5..e1c7b8079 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/BeanInjectedIntoHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/BeanInjectedIntoHoverProvider.java @@ -16,7 +16,6 @@ import java.util.Optional; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Annotation; -import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.lsp4j.CodeLens; @@ -25,7 +24,6 @@ import org.eclipse.lsp4j.Range; import org.gradle.internal.impldep.com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider; import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.java.utils.ASTUtils; @@ -125,7 +123,7 @@ public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProv if (runningApps.length > 0) { Range range = ASTUtils.nodeRegion(doc, parameter.getName()).asRange(); MethodDeclaration method = (MethodDeclaration) parameter.getParent(); - Annotation beanAnnotation = getBeanAnnotation(method); + Annotation beanAnnotation = ASTUtils.getBeanAnnotation(method); if (beanAnnotation != null) { LiveBean definedBean = getDefinedBean(beanAnnotation); if (definedBean != null) { @@ -144,22 +142,5 @@ public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProv return null; } - private static Annotation getBeanAnnotation(MethodDeclaration method) { - List modifiers = method.modifiers(); - for (Object modifier : modifiers) { - if (modifier instanceof Annotation) { - Annotation annotation = (Annotation) modifier; - ITypeBinding typeBinding = annotation.resolveTypeBinding(); - if (typeBinding != null) { - String fqName = typeBinding.getQualifiedName(); - if (Annotations.BEAN.equals(fqName)) { - return annotation; - } - } - } - } - return null; - } - } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingHoverProvider.java index 193a4c996..2dfc67c59 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingHoverProvider.java @@ -50,6 +50,8 @@ import reactor.util.function.Tuples; */ public class RequestMappingHoverProvider implements HoverProvider { +// private static final String $$_LAMBDA$ = "$$Lambda$"; + private static final Logger log = LoggerFactory.getLogger(RequestMappingHoverProvider.class); private static final int CODE_LENS_LIMIT = 3; @@ -79,6 +81,58 @@ public class RequestMappingHoverProvider implements HoverProvider { return null; } +// @Override +// public Collection getLiveHintCodeLenses(IJavaProject project, MethodDeclaration methodDeclaration, +// TextDocument doc, SpringBootApp[] runningApps) { +// try { +// ImmutableList.Builder> builder = ImmutableList.builder(); +// if (runningApps.length > 0) { +// Annotation beanAnnotation = ASTUtils.getBeanAnnotation(methodDeclaration); +// if (beanAnnotation != null) { +// ITypeBinding returnTypeBinding = methodDeclaration.getReturnType2().resolveBinding(); +// if ("org.springframework.web.reactive.function.server.RouterFunction".equals(returnTypeBinding.getErasure().getQualifiedName())) { +// for (SpringBootApp app : runningApps) { +// List matches = findFunctionalRequestMappings(app.getRequestMappings(), methodDeclaration); +// for (RequestMapping rm : matches) { +// builder.add(Tuples.of(rm, app)); +// } +// } +// } +// } +// } +// List> data = builder.build(); +// if (!data.isEmpty()) { +// SimpleName methodName = methodDeclaration.getName(); +// Range hoverRange = doc.toRange(methodName.getStartPosition(), methodName.getLength()); +// return assembleCodeLenses(hoverRange, getUrls(data)); +// } +// } catch (Exception e) { +// log.error("", e); +// } +// return null; +// } +// +// private List findFunctionalRequestMappings(Collection requestMappings, +// MethodDeclaration methodDeclaration) { +// ImmutableList.Builder builder = ImmutableList.builder(); +// IMethodBinding binding = methodDeclaration.resolveBinding(); +// if (requestMappings != null) { +// for (RequestMapping rm : requestMappings) { +// String fqName = rm.getFullyQualifiedClassName(); +// if (fqName != null) { +// int lambdaIdx = fqName.indexOf($$_LAMBDA$); +// if (lambdaIdx > 0) { +// String containingTypeFqName = fqName.substring(0, lambdaIdx); +// if (binding.getDeclaringClass().getQualifiedName().equals(containingTypeFqName)) { +// builder.add(rm); +// } +// } +// } +// } +// } +// return builder.build(); +// } + private Collection assembleCodeLenses(Range range, List urls) { Collection lenses = new ArrayList<>(); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java index 5ec58d6c5..15e3eca62 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java @@ -262,4 +262,21 @@ public class ASTUtils { .map(o -> (String) o); } + public static Annotation getBeanAnnotation(MethodDeclaration method) { + List modifiers = method.modifiers(); + for (Object modifier : modifiers) { + if (modifier instanceof Annotation) { + Annotation annotation = (Annotation) modifier; + ITypeBinding typeBinding = annotation.resolveTypeBinding(); + if (typeBinding != null) { + String fqName = typeBinding.getQualifiedName(); + if (Annotations.BEAN.equals(fqName)) { + return annotation; + } + } + } + } + return null; + } + }