Merge branch 'master' into spring-data-content-assist

This commit is contained in:
Martin Lippert
2018-11-20 15:29:24 +01:00
21 changed files with 834 additions and 90 deletions

View File

@@ -30,10 +30,10 @@ public class RequestMappingsParser20 {
.getJSONObject(contextId)
.getJSONObject("mappings");
JSONArray rmArray = null;
if (mappings.has("dispatcherServlets")) {
if (mappings.has("dispatcherServlets") && mappings.getJSONObject("dispatcherServlets").has("dispatcherServlet")) {
// Regular Web starter endpoints RMs JMX beans format
rmArray = mappings.getJSONObject("dispatcherServlets").getJSONArray("dispatcherServlet");
} else if (mappings.has("dispatcherHandlers")) {
} else if (mappings.has("dispatcherHandlers") && mappings.getJSONObject("dispatcherHandlers").has("webHandler")) {
// WebFlux endpoints RMs JMX bean format
rmArray = mappings.getJSONObject("dispatcherHandlers").getJSONArray("webHandler");
}

View File

@@ -89,4 +89,45 @@ public class Boot2xRequestMappingsTest {
.collect(Collectors.toSet())
);
}
@Test
public void testWebEurekaRms() throws Exception {
String json = IOUtils.toString(Boot2xRequestMappingsTest.class.getResourceAsStream("/live-rm-beans/rms-boot2-web-eureka.json"));
Collection<RequestMapping> rms = RequestMappingsParser20.parse(new JSONObject(json));
assertEquals(9, rms.size());
ImmutableSet<String> expected = ImmutableSet.of(
"/error",
"/actuator",
"/actuator/health",
"/actuator/info",
"/welcome"
);
assertEquals(expected,
rms.stream()
.flatMap(rm -> Arrays.stream(rm.getSplitPath()))
.collect(Collectors.toSet())
);
}
@Test
public void testWebFluxEurekaRms() throws Exception {
String json = IOUtils.toString(Boot2xRequestMappingsTest.class.getResourceAsStream("/live-rm-beans/rms-boot2-webflux-eureka.json"));
Collection<RequestMapping> rms = RequestMappingsParser20.parse(new JSONObject(json));
assertEquals(6, rms.size());
ImmutableSet<String> expected = ImmutableSet.of(
"/actuator",
"/actuator/health",
"/actuator/info",
"/welcome"
);
assertEquals(expected,
rms.stream()
.flatMap(rm -> Arrays.stream(rm.getSplitPath()))
.collect(Collectors.toSet())
);
}
}

View File

@@ -0,0 +1,270 @@
{
"contexts": {
"welcome-messages-1": {
"mappings": {
"dispatcherServlets": {
"dispatcherServlet": [
{
"handler": "ResourceHttpRequestHandler [locations=[class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/], class path resource []], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@22fd98a9]]",
"predicate": "/**/favicon.ico"
},
{
"handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
"predicate": "{[/actuator/health],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}",
"details": {
"requestMappingConditions": {
"headers": [],
"methods": [
"GET"
],
"patterns": [
"/actuator/health"
],
"produces": [
{
"negated": false,
"mediaType": "application/vnd.spring-boot.actuator.v2+json"
},
{
"negated": false,
"mediaType": "application/json"
}
],
"params": [],
"consumes": []
},
"handlerMethod": {
"name": "handle",
"className": "org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.OperationHandler",
"descriptor": "(Ljavax/servlet/http/HttpServletRequest;Ljava/util/Map;)Ljava/lang/Object;"
}
}
},
{
"handler": "public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)",
"predicate": "{[/actuator/info],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}",
"details": {
"requestMappingConditions": {
"headers": [],
"methods": [
"GET"
],
"patterns": [
"/actuator/info"
],
"produces": [
{
"negated": false,
"mediaType": "application/vnd.spring-boot.actuator.v2+json"
},
{
"negated": false,
"mediaType": "application/json"
}
],
"params": [],
"consumes": []
},
"handlerMethod": {
"name": "handle",
"className": "org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.OperationHandler",
"descriptor": "(Ljavax/servlet/http/HttpServletRequest;Ljava/util/Map;)Ljava/lang/Object;"
}
}
},
{
"handler": "protected java.util.Map<java.lang.String, java.util.Map<java.lang.String, org.springframework.boot.actuate.endpoint.web.Link>> org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.links(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)",
"predicate": "{[/actuator],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}",
"details": {
"requestMappingConditions": {
"headers": [],
"methods": [
"GET"
],
"patterns": [
"/actuator"
],
"produces": [
{
"negated": false,
"mediaType": "application/vnd.spring-boot.actuator.v2+json"
},
{
"negated": false,
"mediaType": "application/json"
}
],
"params": [],
"consumes": []
},
"handlerMethod": {
"name": "links",
"className": "org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping",
"descriptor": "(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)Ljava/util/Map;"
}
}
},
{
"handler": "public com.example.demo.Greeting com.example.demo.WelcomeMessageServiceApplication.greeting()",
"predicate": "{[/welcome],methods=[GET]}",
"details": {
"requestMappingConditions": {
"headers": [],
"methods": [
"GET"
],
"patterns": [
"/welcome"
],
"produces": [],
"params": [],
"consumes": []
},
"handlerMethod": {
"name": "greeting",
"className": "com.example.demo.WelcomeMessageServiceApplication",
"descriptor": "()Lcom/example/demo/Greeting;"
}
}
},
{
"handler": "public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)",
"predicate": "{[/error]}",
"details": {
"requestMappingConditions": {
"headers": [],
"methods": [],
"patterns": [
"/error"
],
"produces": [],
"params": [],
"consumes": []
},
"handlerMethod": {
"name": "error",
"className": "org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController",
"descriptor": "(Ljavax/servlet/http/HttpServletRequest;)Lorg/springframework/http/ResponseEntity;"
}
}
},
{
"handler": "public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)",
"predicate": "{[/error],produces=[text/html]}",
"details": {
"requestMappingConditions": {
"headers": [],
"methods": [],
"patterns": [
"/error"
],
"produces": [
{
"negated": false,
"mediaType": "text/html"
}
],
"params": [],
"consumes": []
},
"handlerMethod": {
"name": "errorHtml",
"className": "org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController",
"descriptor": "(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)Lorg/springframework/web/servlet/ModelAndView;"
}
}
},
{
"handler": "ResourceHttpRequestHandler [locations=[class path resource [META-INF/resources/webjars/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@474c937f]]",
"predicate": "/webjars/**"
},
{
"handler": "ResourceHttpRequestHandler [locations=[class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@6a7b18f7]]",
"predicate": "/**"
}
]
},
"servletFilters": [
{
"name": "webMvcMetricsFilter",
"className": "org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter",
"urlPatternMappings": [
"/*"
],
"servletNameMappings": []
},
{
"name": "requestContextFilter",
"className": "org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter",
"urlPatternMappings": [
"/*"
],
"servletNameMappings": []
},
{
"name": "Tomcat WebSocket (JSR356) Filter",
"className": "org.apache.tomcat.websocket.server.WsFilter",
"urlPatternMappings": [
"/*"
],
"servletNameMappings": []
},
{
"name": "httpPutFormContentFilter",
"className": "org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter",
"urlPatternMappings": [
"/*"
],
"servletNameMappings": []
},
{
"name": "hiddenHttpMethodFilter",
"className": "org.springframework.boot.web.servlet.filter.OrderedHiddenHttpMethodFilter",
"urlPatternMappings": [
"/*"
],
"servletNameMappings": []
},
{
"name": "characterEncodingFilter",
"className": "org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter",
"urlPatternMappings": [
"/*"
],
"servletNameMappings": []
},
{
"name": "httpTraceFilter",
"className": "org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter",
"urlPatternMappings": [
"/*"
],
"servletNameMappings": []
}
],
"servlets": [
{
"mappings": [],
"name": "default",
"className": "org.apache.catalina.servlets.DefaultServlet"
},
{
"mappings": [
"/"
],
"name": "dispatcherServlet",
"className": "org.springframework.web.servlet.DispatcherServlet"
}
]
},
"parentId": "welcome-messages-1"
},
"bootstrap": {
"mappings": {
"dispatcherServlets": {},
"servletFilters": [],
"servlets": []
}
}
}
}

View File

@@ -0,0 +1,145 @@
{
"contexts": {
"welcome-messages-1": {
"mappings": {
"dispatcherHandlers": {
"webHandler": [
{
"predicate": "{[/actuator/health],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}",
"handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
"details": {
"requestMappingConditions": {
"headers": [],
"methods": [
"GET"
],
"patterns": [
"/actuator/health"
],
"produces": [
{
"negated": false,
"mediaType": "application/vnd.spring-boot.actuator.v2+json"
},
{
"negated": false,
"mediaType": "application/json"
}
],
"params": [],
"consumes": []
},
"handlerMethod": {
"name": "handle",
"className": "org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping.ReadOperationHandler",
"descriptor": "(Lorg/springframework/web/server/ServerWebExchange;)Lorg/reactivestreams/Publisher;"
}
}
},
{
"predicate": "{[/actuator/info],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}",
"handler": "public org.reactivestreams.Publisher<org.springframework.http.ResponseEntity<java.lang.Object>> org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping$ReadOperationHandler.handle(org.springframework.web.server.ServerWebExchange)",
"details": {
"requestMappingConditions": {
"headers": [],
"methods": [
"GET"
],
"patterns": [
"/actuator/info"
],
"produces": [
{
"negated": false,
"mediaType": "application/vnd.spring-boot.actuator.v2+json"
},
{
"negated": false,
"mediaType": "application/json"
}
],
"params": [],
"consumes": []
},
"handlerMethod": {
"name": "handle",
"className": "org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping.ReadOperationHandler",
"descriptor": "(Lorg/springframework/web/server/ServerWebExchange;)Lorg/reactivestreams/Publisher;"
}
}
},
{
"predicate": "{[/actuator],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}",
"handler": "protected java.util.Map<java.lang.String, java.util.Map<java.lang.String, org.springframework.boot.actuate.endpoint.web.Link>> org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping.links(org.springframework.web.server.ServerWebExchange)",
"details": {
"requestMappingConditions": {
"headers": [],
"methods": [
"GET"
],
"patterns": [
"/actuator"
],
"produces": [
{
"negated": false,
"mediaType": "application/vnd.spring-boot.actuator.v2+json"
},
{
"negated": false,
"mediaType": "application/json"
}
],
"params": [],
"consumes": []
},
"handlerMethod": {
"name": "links",
"className": "org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping",
"descriptor": "(Lorg/springframework/web/server/ServerWebExchange;)Ljava/util/Map;"
}
}
},
{
"predicate": "{[/welcome],methods=[GET]}",
"handler": "public com.example.demo.Greeting com.example.demo.WelcomeMessageServiceApplication.greeting()",
"details": {
"requestMappingConditions": {
"headers": [],
"methods": [
"GET"
],
"patterns": [
"/welcome"
],
"produces": [],
"params": [],
"consumes": []
},
"handlerMethod": {
"name": "greeting",
"className": "com.example.demo.WelcomeMessageServiceApplication",
"descriptor": "()Lcom/example/demo/Greeting;"
}
}
},
{
"predicate": "/webjars/**",
"handler": "ResourceWebHandler [locations=[class path resource [META-INF/resources/webjars/]], resolvers=[org.springframework.web.reactive.resource.PathResourceResolver@7030aee8]]"
},
{
"predicate": "/**",
"handler": "ResourceWebHandler [locations=[class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/]], resolvers=[org.springframework.web.reactive.resource.PathResourceResolver@2c2efafe]]"
}
]
}
},
"parentId": "welcome-messages-1"
},
"bootstrap": {
"mappings": {
"dispatcherHandlers": {}
}
}
}
}

View File

@@ -83,7 +83,7 @@ public class BootLanguagServerBootApp {
@Bean InitializingBean initializeValueProviders(ValueProviderRegistry r, @Qualifier("adHocProperties") ProjectBasedPropertyIndexProvider adHocProperties) {
return () -> {
r.def("logger-name", new LoggerNameProvider(adHocProperties).FACTORY);
r.def("logger-name", LoggerNameProvider.factory(adHocProperties));
r.def("class-reference", ClassReferenceProvider.FACTORY);
};
}

View File

@@ -56,5 +56,4 @@ class ConfigurationMetadataItem extends ConfigurationMetadataProperty {
public void setSourceMethod(String sourceMethod) {
this.sourceMethod = sourceMethod;
}
}

View File

@@ -71,32 +71,30 @@ public class AutowiredHoverProvider implements HoverProvider {
}
@Override
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, Annotation annotation, TextDocument doc,
SpringBootApp[] runningApps) {
ImmutableList.Builder<CodeLens> builder = ImmutableList.builder();
if (runningApps.length > 0) {
LiveBean definedBean = getDefinedBeanForTypeDeclaration(ASTUtils.findDeclaringType(annotation));
// Annotation is MarkerNode, parent is some field, method, variable declaration node.
// Annotation is MarkerNode, parent is some field, method, variable declaration
// node.
ASTNode declarationNode = annotation.getParent();
try {
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
return getLiveHoverHints(project, declarationNode, hoverRange, runningApps, definedBean);
for (SpringBootApp app : runningApps) {
List<LiveBean> relevantBeans = getRelevantAutowiredBeans(project, declarationNode, app,
definedBean);
if (!relevantBeans.isEmpty()) {
builder.addAll(LiveHoverUtils.createCodeLensesForBeans(hoverRange, relevantBeans,
BEANS_PREFIX_PLAIN_TEXT, MAX_INLINE_BEANS_STRING_LENGTH,
INLINE_BEANS_STRING_SEPARATOR));
}
}
} catch (BadLocationException e) {
log.error("", e);
}
}
return null;
}
private Collection<CodeLens> getLiveHoverHints(IJavaProject project, ASTNode declarationNode, Range range,
SpringBootApp[] runningApps, LiveBean definedBean) {
if (declarationNode != null && definedBean != null) {
for (SpringBootApp app : runningApps) {
List<LiveBean> relevantBeans = getRelevantAutowiredBeans(project, declarationNode, app, definedBean);
if (!relevantBeans.isEmpty()) {
return LiveHoverUtils.createCodeLensesForBeans(range, relevantBeans, BEANS_PREFIX_PLAIN_TEXT, MAX_INLINE_BEANS_STRING_LENGTH, INLINE_BEANS_STRING_SEPARATOR);
}
}
}
return null;
return builder.build();
}
@Override
@@ -125,16 +123,12 @@ public class AutowiredHoverProvider implements HoverProvider {
StringBuilder hover = new StringBuilder();
boolean hasContent = false;
for (SpringBootApp app : runningApps) {
List<LiveBean> autowiredBeans = getRelevantAutowiredBeans(project, declarationNode, app, definedBean);
if (!autowiredBeans.isEmpty()) {
if (!hasContent) {
hasContent = true;
} else {
if (hover.length() > 0) {
hover.append(" \n \n");
}
createHoverContentForBeans(sourceLinks, project, hover, autowiredBeans);
@@ -145,7 +139,7 @@ public class AutowiredHoverProvider implements HoverProvider {
}
}
if (hasContent) {
if (hover.length() > 0) {
return new Hover(ImmutableList.of(Either.forLeft(hover.toString())));
}
}
@@ -189,7 +183,7 @@ public class AutowiredHoverProvider implements HoverProvider {
}
@SuppressWarnings("unchecked")
private static List<LiveBean> findAutowiredBeans(IJavaProject project, ASTNode declarationNode, Collection<LiveBean> beans) {
public static List<LiveBean> findAutowiredBeans(IJavaProject project, ASTNode declarationNode, Collection<LiveBean> beans) {
if (declarationNode instanceof MethodDeclaration) {
MethodDeclaration methodDeclaration = (MethodDeclaration)declarationNode;
return ((List<Object>)methodDeclaration.parameters()).stream()
@@ -325,16 +319,54 @@ public class AutowiredHoverProvider implements HoverProvider {
}
@Override
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, MethodDeclaration methodDeclaration, TextDocument doc,
SpringBootApp[] runningApps) {
LiveBean definedBean = getDefinedBeanForImplicitAutowiredConstructor(methodDeclaration);
try {
Range hoverRange = doc.toRange(methodDeclaration.getName().getStartPosition(), methodDeclaration.getName().getLength());
return getLiveHoverHints(project, methodDeclaration, hoverRange, runningApps, definedBean);
} catch (BadLocationException e) {
log.error("", e);
public Hover provideMethodParameterHover(SingleVariableDeclaration parameter, int offset, TextDocument doc,
IJavaProject project, SpringBootApp[] runningApps) {
MethodDeclaration method = (MethodDeclaration) parameter.getParent();
LiveBean definedBean = getDefinedBeanForImplicitAutowiredConstructor(method);
Hover hover = provideHover(definedBean, parameter, offset, doc, project, runningApps);
if (hover != null) {
SimpleName name = parameter.getName();
try {
hover.setRange(doc.toRange(name.getStartPosition(), name.getLength()));
} catch (BadLocationException e) {
log.error("", e);
}
}
return null;
return hover;
}
@Override
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, MethodDeclaration methodDeclaration,
TextDocument doc, SpringBootApp[] runningApps) {
ImmutableList.Builder<CodeLens> builder = ImmutableList.builder();
LiveBean definedBean = getDefinedBeanForImplicitAutowiredConstructor(methodDeclaration);
if (definedBean != null) {
try {
Range hoverRange = doc.toRange(methodDeclaration.getName().getStartPosition(),
methodDeclaration.getName().getLength());
for (SpringBootApp app : runningApps) {
List<LiveBean> relevantBeans = getRelevantAutowiredBeans(project, methodDeclaration, app,
definedBean);
if (!relevantBeans.isEmpty()) {
// CodeLens for the method
builder.addAll(LiveHoverUtils.createCodeLensesForBeans(hoverRange, relevantBeans,
BEANS_PREFIX_PLAIN_TEXT, MAX_INLINE_BEANS_STRING_LENGTH,
INLINE_BEANS_STRING_SEPARATOR));
// CodeLenses for the method parameters. Only ranges just to provide a highlight
// for the hover
builder.addAll(LiveHoverUtils.createCodeLensForMethodParameters(app, project, methodDeclaration, doc, relevantBeans));
}
}
} catch (BadLocationException e) {
log.error("", e);
}
}
return builder.build();
}
private LiveBean getDefinedBeanForImplicitAutowiredConstructor(MethodDeclaration methodDeclaration) {

View File

@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.handlers;
import java.net.URI;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Optional;
@@ -24,6 +25,7 @@ import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.CodeLens;
import org.eclipse.lsp4j.Hover;
@@ -101,7 +103,7 @@ public class BootJavaHoverProvider implements HoverHandler {
if (!project.isPresent()) return new CodeLens[0];
if (!hasActuatorDependency(project.get())) return new CodeLens[0];
return server.getCompilationUnitCache().withCompilationUnit(document, cu -> {
return server.getCompilationUnitCache().withCompilationUnit(project.get(), URI.create(document.getUri()), cu -> {
Collection<CodeLens> result = new LinkedHashSet<>();
try {
if (cu != null) {
@@ -210,7 +212,7 @@ public class BootJavaHoverProvider implements HoverHandler {
private Hover provideHover(TextDocument document, int offset) throws Exception {
IJavaProject project = getProject(document).orElse(null);
if (project != null) {
return server.getCompilationUnitCache().withCompilationUnit(document, cu -> {
return server.getCompilationUnitCache().withCompilationUnit(project, URI.create(document.getUri()), cu -> {
ASTNode node = NodeFinder.perform(cu, offset, 0);
if (node != null) {
return provideHover(node, offset, document, project);
@@ -239,6 +241,23 @@ public class BootJavaHoverProvider implements HoverHandler {
return provideHoverForTypeDeclaration(node, (TypeDeclaration) parent, offset, doc, project);
} else if (parent instanceof MethodDeclaration) {
return provideHoverForMethodDeclaration((MethodDeclaration) parent, offset, doc, project);
} else if (parent instanceof SingleVariableDeclaration && parent.getParent() instanceof MethodDeclaration) {
return provideHoverForMethodParameter((SingleVariableDeclaration) parent, offset, doc, project);
}
}
return null;
}
private Hover provideHoverForMethodParameter(SingleVariableDeclaration parameter, int offset, TextDocument doc,
IJavaProject project) {
SpringBootApp[] runningApps = getRunningSpringApps(project);
if (runningApps.length > 0) {
for (HoverProvider provider : this.hoverProviders.getAll()) {
Hover hover = provider.provideMethodParameterHover(parameter, offset, doc, project, runningApps);
if (hover != null) {
return hover;
}
}
}
return null;

View File

@@ -16,6 +16,7 @@ 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.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.CodeLens;
import org.eclipse.lsp4j.Hover;
@@ -31,13 +32,19 @@ public interface HoverProvider {
default Hover provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset, TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
return null;
}
default Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset, TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
return null;
}
default Hover provideHover(MethodDeclaration methodDeclaration, int offset, TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
return null;
}
default Hover provideMethodParameterHover(SingleVariableDeclaration parameter, int offset, TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
return null;
}
default Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
return null;
}

View File

@@ -10,7 +10,6 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.livehover;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -65,7 +64,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
if (Stream.of(runningApps).anyMatch(app -> LiveHoverUtils.hasRelevantBeans(app, definedBean))) {
Optional<Range> nameRange = ASTUtils.nameRange(doc, annotation);
if (nameRange.isPresent()) {
List<CodeLens> codeLenses = assembleCodeLenses(project, runningApps, definedBean, nameRange.get(), annotation);
List<CodeLens> codeLenses = assembleCodeLenses(project, runningApps, definedBean, doc, nameRange.get(), annotation);
return codeLenses.isEmpty() ? ImmutableList.of(new CodeLens(nameRange.get())) : codeLenses;
}
}
@@ -97,31 +96,38 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
return null;
}
protected List<CodeLens> assembleCodeLenses(IJavaProject project, SpringBootApp[] runningApps, LiveBean definedBean, Range range, ASTNode astNode) {
List<CodeLens> codeLensList = new ArrayList<>();
for (SpringBootApp app : runningApps) {
protected List<CodeLens> assembleCodeLenses(IJavaProject project, SpringBootApp[] runningApps, LiveBean definedBean,
TextDocument doc, Range range, ASTNode node) {
for (SpringBootApp app : runningApps) {
List<LiveBean> relevantBeans = LiveHoverUtils.findRelevantBeans(app, definedBean);
List<LiveBean> relevantBeans = LiveHoverUtils.findRelevantBeans(app, definedBean);
if (!relevantBeans.isEmpty()) {
List<LiveBean> injectedBeans = getRelevantInjectedIntoBeans(project, app, definedBean, relevantBeans);
ImmutableList.Builder<CodeLens> builder = ImmutableList.builder();
if (!injectedBeans.isEmpty()) {
// Break out of the loop. Just look for the first app with injected into beans
List<CodeLens> injectedCodeLenses = LiveHoverUtils.createCodeLensesForBeans(range, injectedBeans, BEANS_PREFIX_PLAIN_TEXT, MAX_INLINE_BEANS_STRING_LENGTH, INLINE_BEANS_STRING_SEPARATOR);
builder.addAll(injectedCodeLenses.isEmpty() ? ImmutableList.of(new CodeLens(range)) : injectedCodeLenses);
}
// Wired beans code lenses
List<LiveBean> wiredBeans = findWiredBeans(project, app, relevantBeans, astNode);
builder.addAll(LiveHoverUtils.createCodeLensesForBeans(range, wiredBeans,
AutowiredHoverProvider.BEANS_PREFIX_PLAIN_TEXT, MAX_INLINE_BEANS_STRING_LENGTH,
INLINE_BEANS_STRING_SEPARATOR));
return builder.build();
if (!relevantBeans.isEmpty()) {
List<LiveBean> injectedBeans = getRelevantInjectedIntoBeans(project, app, definedBean, relevantBeans);
ImmutableList.Builder<CodeLens> builder = ImmutableList.builder();
if (!injectedBeans.isEmpty()) {
// Break out of the loop. Just look for the first app with injected into beans
List<CodeLens> injectedCodeLenses = LiveHoverUtils.createCodeLensesForBeans(range, injectedBeans,
BEANS_PREFIX_PLAIN_TEXT, MAX_INLINE_BEANS_STRING_LENGTH, INLINE_BEANS_STRING_SEPARATOR);
builder.addAll(
injectedCodeLenses.isEmpty() ? ImmutableList.of(new CodeLens(range)) : injectedCodeLenses);
}
// Wired beans code lenses
List<LiveBean> wiredBeans = findWiredBeans(project, app, relevantBeans, node);
builder.addAll(assembleCodeLenseForAutowired(wiredBeans, project, app, doc, range, node));
List<CodeLens> codeLenses = builder.build();
return codeLenses.isEmpty() ? ImmutableList.of(new CodeLens(range)) : codeLenses;
}
}
return codeLensList;
return ImmutableList.of();
}
protected List<CodeLens> assembleCodeLenseForAutowired(List<LiveBean> wiredBeans, IJavaProject project, SpringBootApp app, TextDocument doc, Range nameRange, ASTNode astNode) {
return LiveHoverUtils.createCodeLensesForBeans(nameRange, wiredBeans,
AutowiredHoverProvider.BEANS_PREFIX_PLAIN_TEXT, MAX_INLINE_BEANS_STRING_LENGTH,
INLINE_BEANS_STRING_SEPARATOR);
}
protected List<LiveBean> findWiredBeans(IJavaProject project, SpringBootApp app, List<LiveBean> relevantBeans, ASTNode astNode) {
@@ -131,8 +137,6 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
protected Hover assembleHover(IJavaProject project, SpringBootApp[] runningApps, LiveBean definedBean, ASTNode astNode) {
StringBuilder hover = new StringBuilder();
boolean hasContent = false;
for (SpringBootApp app : runningApps) {
List<LiveBean> relevantBeans = LiveHoverUtils.findRelevantBeans(app, definedBean);
@@ -140,9 +144,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
if (!relevantBeans.isEmpty()) {
List<LiveBean> injectedBeans = getRelevantInjectedIntoBeans(project, app, definedBean, relevantBeans);
if (!hasContent) {
hasContent = true;
} else {
if (hover.length() > 0) {
hover.append(" \n \n");
}
@@ -167,7 +169,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
}
}
if (hasContent) {
if (hover.length() > 0) {
return new Hover(ImmutableList.of(Either.forLeft(hover.toString())));
} else {
return null;

View File

@@ -16,7 +16,16 @@ 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;
import org.eclipse.lsp4j.Hover;
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;
@@ -24,9 +33,12 @@ import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.Optionals;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProvider {
private static final Logger log = LoggerFactory.getLogger(BeanInjectedIntoHoverProvider.class);
public BeanInjectedIntoHoverProvider(SourceLinks sourceLinks) {
super(sourceLinks);
}
@@ -75,12 +87,79 @@ public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProv
@Override
protected List<LiveBean> findWiredBeans(IJavaProject project, SpringBootApp app, List<LiveBean> relevantBeans, ASTNode astNode) {
if (astNode instanceof Annotation) {
// @Bean annotation case
MethodDeclaration beanMethod = ASTUtils.getAnnotatedMethod((Annotation) astNode);
if (beanMethod != null) {
return AutowiredHoverProvider.getRelevantAutowiredBeans(project, beanMethod, app, relevantBeans);
}
} else if (astNode instanceof SingleVariableDeclaration) {
// Bean method parameter case
return AutowiredHoverProvider.getRelevantAutowiredBeans(project, astNode, app, relevantBeans);
}
return Collections.emptyList();
}
@Override
protected List<CodeLens> assembleCodeLenseForAutowired(List<LiveBean> wiredBeans, IJavaProject project,
SpringBootApp app, TextDocument doc, Range nameRange, ASTNode astNode) {
ImmutableList.Builder<CodeLens> builder = ImmutableList.builder();
// Code lens for the @Bean annotation
builder.addAll(super.assembleCodeLenseForAutowired(wiredBeans, project, app, doc, nameRange, astNode));
if (astNode instanceof Annotation) {
// Add code lenses for method parameters
MethodDeclaration beanMethod = ASTUtils.getAnnotatedMethod((Annotation) astNode);
if (beanMethod != null) {
builder.addAll(LiveHoverUtils.createCodeLensForMethodParameters(app, project, beanMethod, doc, wiredBeans));
}
}
return builder.build();
}
@Override
public Hover provideMethodParameterHover(SingleVariableDeclaration parameter, int offset, TextDocument doc,
IJavaProject project, SpringBootApp[] runningApps) {
try {
if (runningApps.length > 0) {
Range range = ASTUtils.nodeRegion(doc, parameter.getName()).asRange();
MethodDeclaration method = (MethodDeclaration) parameter.getParent();
Annotation beanAnnotation = getBeanAnnotation(method);
if (beanAnnotation != null) {
LiveBean definedBean = getDefinedBean(beanAnnotation);
if (definedBean != null) {
Hover hover = assembleHover(project, runningApps, definedBean, parameter);
if (hover != null) {
hover.setRange(range);
}
return hover;
}
}
}
} catch (Exception e) {
log.error("", e);
}
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;
}
}

View File

@@ -111,7 +111,7 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
if (Stream.of(runningApps).anyMatch(app -> LiveHoverUtils.hasRelevantBeans(app, definedBean))) {
Optional<Range> nameRange = Optional.of(ASTUtils.nodeRegion(doc, typeDeclaration.getName()).asRange());
if (nameRange.isPresent()) {
List<CodeLens> codeLenses = assembleCodeLenses(project, runningApps, definedBean, nameRange.get(), typeDeclaration);
List<CodeLens> codeLenses = assembleCodeLenses(project, runningApps, definedBean, doc, nameRange.get(), typeDeclaration);
return codeLenses.isEmpty() ? ImmutableList.of(new CodeLens(nameRange.get())) : codeLenses;
}
}
@@ -146,8 +146,6 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
return null;
}
@Override
protected List<LiveBean> findWiredBeans(IJavaProject project, SpringBootApp app, List<LiveBean> relevantBeans,
ASTNode astNode) {

View File

@@ -17,22 +17,32 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.lsp4j.CodeLens;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.Range;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
import org.springframework.ide.vscode.boot.java.utils.SpringResource;
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBeansModel;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Renderables;
import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import com.google.common.collect.ImmutableList;
public class LiveHoverUtils {
private static final Logger log = LoggerFactory.getLogger(LiveHoverUtils.class);
public static final LiveBean CANT_MATCH_PROPER_BEAN = LiveBean.builder().id("UNKNOWN").build();
public static String showBean(LiveBean bean) {
@@ -161,7 +171,7 @@ public class LiveHoverUtils {
try {
return niceAppName(app.getProcessID(), app.getProcessName());
} catch (Exception e) {
e.printStackTrace();
log.error("", e);
return app.toString();
}
}
@@ -189,6 +199,27 @@ public class LiveHoverUtils {
}
@SuppressWarnings("unchecked")
public static List<CodeLens> createCodeLensForMethodParameters(SpringBootApp app, IJavaProject project, MethodDeclaration method, TextDocument doc, List<LiveBean> wiredBeans) {
ImmutableList.Builder<CodeLens> builder = ImmutableList.builder();
method.parameters().forEach(p -> {
if (p instanceof SingleVariableDeclaration) {
SingleVariableDeclaration parameter = (SingleVariableDeclaration) p;
List<LiveBean> parameterMatchingBean = AutowiredHoverProvider.findAutowiredBeans(project, parameter, wiredBeans);
if (parameterMatchingBean.size() == 0) {
log.warn("No Live Bean matching parameter `" + parameter.getName().getIdentifier() + " for method " + method);
} else {
try {
builder.add(new CodeLens(ASTUtils.nodeRegion(doc, parameter.getName()).asRange()));
} catch (BadLocationException e) {
// ignore
}
}
}
});
return builder.build();
}
public static StringBuilder createBeansTitlePlainText(Collection<LiveBean> beans, String prefix, int maxInlineBeansStringLength, String beansSeparator) {
StringBuilder sb = new StringBuilder(prefix);
if (LiveHoverUtils.doBeansFitInline(beans, maxInlineBeansStringLength, beansSeparator)) {

View File

@@ -39,18 +39,23 @@ import reactor.util.function.Tuples;
public class LoggerNameProvider extends CachingValueProvider {
private static final String LOGGING_GROUPS_PREFIX = "logging.group.";
private final ProjectBasedPropertyIndexProvider adhocProperties;
private final boolean includeGroups;
public LoggerNameProvider(ProjectBasedPropertyIndexProvider adhocProperties) {
public LoggerNameProvider(ProjectBasedPropertyIndexProvider adhocProperties, boolean includeGroups) {
this.adhocProperties = adhocProperties;
this.includeGroups = includeGroups;
}
public final Function<Map<String, Object>, ValueProviderStrategy> FACTORY = (params) -> this;
public static final Function<Map<String, Object>, ValueProviderStrategy> factory(ProjectBasedPropertyIndexProvider adhocProperties) {
return (params) -> {
return new LoggerNameProvider(adhocProperties, (boolean) params.getOrDefault("group", true));
};
}
Collection<String> loggerGroupNames(IJavaProject jp) {
Builder<String> builder = ImmutableSet.builder();
if (adhocProperties!=null) {
if (adhocProperties!=null && includeGroups) {
SortedMap<String, PropertyInfo> index = adhocProperties.getIndex(jp).getTreeMap();
index = index.subMap(LOGGING_GROUPS_PREFIX, LOGGING_GROUPS_PREFIX+Character.MAX_VALUE);
for (String prop : index.keySet()) {

View File

@@ -21,6 +21,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.TextDocumentIdentifier;
@@ -136,6 +137,14 @@ public abstract class AbstractPropsEditorTest {
assertCompletions(text /*NONE*/);
}
public void assertNoCompletionWithLabel(String textBefore, String expectLabel) throws Exception {
Editor editor = newEditor(textBefore);
List<CompletionItem> completions = editor.getCompletions().stream().filter(c -> c.getLabel().equals(expectLabel)).collect(Collectors.toList());
if (!completions.isEmpty()) {
fail("Expecting no completions with label '"+expectLabel+"', but found some");
}
}
/**
* Checks that completions contains a completion with a given display string (and check that
* it applies as expected).

View File

@@ -507,7 +507,7 @@ public class AutowiredHoverProviderTest {
"}\n"
);
editor.assertHighlights("@Component", "SomeComponent");
editor.assertHighlights("@Component", "SomeComponent", "depA", "depB");
editor.assertTrimmedHover("SomeComponent", 2,
"**&#8592; `DependencyA` `DependencyB`**\n" +
@@ -519,6 +519,25 @@ public class AutowiredHoverProviderTest {
"Bean id: `someComponent` \n" +
"Process [PID=111, name=`the-app`]\n"
);
editor.assertTrimmedHover("depA", 2,
"**&#8592; `DependencyA`**\n" +
"- Bean: `dependencyA` \n" +
" Type: `com.example.DependencyA`\n" +
" \n" +
"Bean id: `someComponent` \n" +
"Process [PID=111, name=`the-app`]\n"
);
editor.assertTrimmedHover("depB", 2,
"**&#8592; `DependencyB`**\n" +
"- Bean: `dependencyB` \n" +
" Type: `com.example.DependencyB`\n" +
" \n" +
"Bean id: `someComponent` \n" +
"Process [PID=111, name=`the-app`]\n"
);
}
@Test
@@ -718,7 +737,7 @@ public class AutowiredHoverProviderTest {
" private IDependency a;\n" +
" private IDependency b;\n" +
"\n" +
" public SomeComponent(@Qualifier(\"dependencyA\") IDependency a, @Qualifier(\"dependencyB\") IDependency b) {\n" +
" public SomeComponent(@Qualifier(\"dependencyA\") IDependency depA, @Qualifier(\"dependencyB\") IDependency depB) {\n" +
" this.a = a;\n" +
" this.b = b;\n" +
" }\n" +
@@ -726,7 +745,7 @@ public class AutowiredHoverProviderTest {
"}\n"
);
editor.assertHighlights("@Component", "SomeComponent");
editor.assertHighlights("@Component", "SomeComponent", "depA", "depB");
editor.assertTrimmedHover("SomeComponent", 2,
"**&#8592; `DependencyA` `DependencyB`**\n" +
"- Bean: `dependencyA` \n" +
@@ -737,6 +756,25 @@ public class AutowiredHoverProviderTest {
"Bean id: `someComponent` \n" +
"Process [PID=111, name=`the-app`]\n"
);
editor.assertTrimmedHover("depA",
"**&#8592; `DependencyA`**\n" +
"- Bean: `dependencyA` \n" +
" Type: `com.example.DependencyA`\n" +
" \n" +
"Bean id: `someComponent` \n" +
"Process [PID=111, name=`the-app`]\n"
);
editor.assertTrimmedHover("depB",
"**&#8592; `DependencyB`**\n" +
"- Bean: `dependencyB` \n" +
" Type: `com.example.DependencyB`\n" +
" \n" +
"Bean id: `someComponent` \n" +
"Process [PID=111, name=`the-app`]\n"
);
}
@Test

View File

@@ -549,12 +549,12 @@ public class BeanInjectedIntoHoverProviderTest {
"public class LocalConfig {\n" +
" \n" +
" @Bean(\"fooImplementation\")\n" +
" Foo someFoo(DependencyA a) {\n" +
" Foo someFoo(DependencyA depA) {\n" +
" return new FooImplementation();\n" +
" }\n" +
"}"
);
editor.assertHighlights("@Bean");
editor.assertHighlights("@Bean", "depA");
editor.assertTrimmedHover("@Bean",
"**&#8592; `DependencyA`**\n" +
"- Bean: `depA` \n" +
@@ -563,6 +563,16 @@ public class BeanInjectedIntoHoverProviderTest {
"Bean id: `fooImplementation` \n" +
"Process [PID=111, name=`the-app`]"
);
editor.assertTrimmedHover("depA",
"**&#8592; `DependencyA`**\n" +
"- Bean: `depA` \n" +
" Type: `hello.DependencyA`\n" +
" \n" +
"Bean id: `fooImplementation` \n" +
"Process [PID=111, name=`the-app`]"
);
}
@Test
@@ -603,12 +613,12 @@ public class BeanInjectedIntoHoverProviderTest {
"public class LocalConfig {\n" +
" \n" +
" @Bean(\"fooImplementation\")\n" +
" Foo someFoo(DependencyA a, DependencyB b) {\n" +
" Foo someFoo(DependencyA depA, DependencyB depB) {\n" +
" return new FooImplementation();\n" +
" }\n" +
"}"
);
editor.assertHighlights("@Bean");
editor.assertHighlights("@Bean", "depA", "depB");
editor.assertTrimmedHover("@Bean",
"**&#8592; `DependencyA` `DependencyB`**\n" +
"- Bean: `depA` \n" +
@@ -619,6 +629,25 @@ public class BeanInjectedIntoHoverProviderTest {
"Bean id: `fooImplementation` \n" +
"Process [PID=111, name=`the-app`]"
);
editor.assertTrimmedHover("depA",
"**&#8592; `DependencyA`**\n" +
"- Bean: `depA` \n" +
" Type: `hello.DependencyA`\n" +
" \n" +
"Bean id: `fooImplementation` \n" +
"Process [PID=111, name=`the-app`]"
);
editor.assertTrimmedHover("depB",
"**&#8592; `DependencyB`**\n" +
"- Bean: `depB` \n" +
" Type: `hello.DependencyB`\n" +
" \n" +
"Bean id: `fooImplementation` \n" +
"Process [PID=111, name=`the-app`]"
);
}
@Test
@@ -664,7 +693,7 @@ public class BeanInjectedIntoHoverProviderTest {
" }\n" +
"}"
);
editor.assertHighlights("@Bean");
editor.assertHighlights("@Bean", "deps");
editor.assertTrimmedHover("@Bean",
"**&#8592; `DependencyA` `DependencyB`**\n" +
"- Bean: `depA` \n" +
@@ -675,7 +704,18 @@ public class BeanInjectedIntoHoverProviderTest {
"Bean id: `fooImplementation` \n" +
"Process [PID=111, name=`the-app`]"
);
}
editor.assertTrimmedHover("deps",
"**&#8592; `DependencyA` `DependencyB`**\n" +
"- Bean: `depA` \n" +
" Type: `hello.DependencyA`\n" +
"- Bean: `depB` \n" +
" Type: `hello.DependencyB`\n" +
" \n" +
"Bean id: `fooImplementation` \n" +
"Process [PID=111, name=`the-app`]"
);
}
@Test
public void beanWithQualifierWiring() throws Exception {
@@ -715,7 +755,7 @@ public class BeanInjectedIntoHoverProviderTest {
" }\n" +
"}"
);
editor.assertHighlights("@Bean");
editor.assertHighlights("@Bean", "deps");
editor.assertTrimmedHover("@Bean",
"**&#8592; `DependencyB`**\n" +
"- Bean: `depB` \n" +
@@ -724,5 +764,15 @@ public class BeanInjectedIntoHoverProviderTest {
"Bean id: `fooImplementation` \n" +
"Process [PID=111, name=`the-app`]"
);
editor.assertTrimmedHover("deps",
"**&#8592; `DependencyB`**\n" +
"- Bean: `depB` \n" +
" Type: `hello.DependencyB`\n" +
" \n" +
"Bean id: `fooImplementation` \n" +
"Process [PID=111, name=`the-app`]"
);
}
}

View File

@@ -501,7 +501,7 @@ public class ComponentInjectionsHoverProviderTest {
" }\n" +
"}\n"
);
editor.assertHighlights("@Component", "AutowiredClass");
editor.assertHighlights("@Component", "AutowiredClass", "depA", "depB");
editor.assertTrimmedHover("@Component",
"**&#8592; `DependencyA` `DependencyB`**\n" +
"- Bean: `dependencyA` \n" +

View File

@@ -30,6 +30,7 @@ import org.springframework.ide.vscode.boot.metadata.LoggerNameProvider;
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/**
@@ -69,7 +70,7 @@ public class LoggerNameProviderTest {
@Test
public void directResults() throws Exception {
LoggerNameProvider p = new LoggerNameProvider(null);
LoggerNameProvider p = create();
String query = "jboss";
List<String> directQueryResults = getResults(p, query);
@@ -84,7 +85,7 @@ public class LoggerNameProviderTest {
@Test
public void cachedResults() throws Exception {
LoggerNameProvider p = new LoggerNameProvider(null);
LoggerNameProvider p = create();
for (int i = 0; i < 10; i++) {
long startTime = System.currentTimeMillis();
String query = "jboss";
@@ -105,7 +106,7 @@ public class LoggerNameProviderTest {
public void incrementalResults() throws Exception {
String fullQuery = "jboss";
CachingValueProvider p = new LoggerNameProvider(null);
CachingValueProvider p = create();
for (int i = 0; i <= fullQuery.length(); i++) {
String query = fullQuery.substring(0, i);
List<String> results = getResults(p, query);
@@ -120,6 +121,10 @@ public class LoggerNameProviderTest {
}
}
private LoggerNameProvider create() {
return (LoggerNameProvider) LoggerNameProvider.factory(null).apply(ImmutableMap.of());
}
private void assertElementsAtLeast(List<String> results, String[] expecteds) {
Set<String> actuals = ImmutableSet.copyOf(results);
StringBuilder missing = new StringBuilder();

View File

@@ -1183,6 +1183,10 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
"logging.level.indexed=<*>"
);
//Check whether the added parameter to disable group name hints is obeyed:
assertNoCompletionWithLabel("logging.group.whatever=<*>", "foobar");
assertNoCompletionWithLabel("logging.group.whatever=<*>", "user-defined");
assertNoCompletionWithLabel("logging.group.whatever=<*>", "indexed");
}
@Test public void userDefinedLoggingGroupsValueCompletions() throws Exception {

View File

@@ -296,6 +296,16 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
" group:\n"+
" whatever: stuff,com.example.demo<*>"
);
//Check whether the added parameter to disable group name hints is obeyed:
assertNoCompletionWithLabel(
"logging:\n" +
" group:\n"+
" whatever: <*>"
,
"foobar"
);
}
///////////////////// ported tests from old STS code base ////////////////////////////////////////////////