Merge branch 'master' of github.com:spring-projects/sts4
This commit is contained in:
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider
|
||||
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.beans.ComponentSymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.conditionals.ConditionalsLiveHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.DataRepositoryCompletionProcessor;
|
||||
import org.springframework.ide.vscode.boot.java.data.DataRepositorySymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaCodeLensEngine;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaCompletionEngine;
|
||||
@@ -63,7 +64,6 @@ import org.springframework.ide.vscode.boot.java.utils.SpringLiveHoverWatchdog;
|
||||
import org.springframework.ide.vscode.boot.java.value.ValueCompletionProcessor;
|
||||
import org.springframework.ide.vscode.boot.java.value.ValueHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.value.ValuePropertyReferencesProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.AdHocSpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||
@@ -73,6 +73,7 @@ import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserve
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.CodeLensHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentHighlightHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.ReferencesHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
@@ -265,48 +266,61 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
protected ICompletionEngine createCompletionEngine(
|
||||
JavaProjectFinder javaProjectFinder,
|
||||
SpringPropertyIndexProvider indexProvider,
|
||||
ProjectBasedPropertyIndexProvider adHocIndexProvider
|
||||
) {
|
||||
ProjectBasedPropertyIndexProvider adHocIndexProvider) {
|
||||
|
||||
Map<String, CompletionProvider> providers = new HashMap<>();
|
||||
providers.put(org.springframework.ide.vscode.boot.java.scope.Constants.SPRING_SCOPE,
|
||||
new ScopeCompletionProcessor());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.value.Constants.SPRING_VALUE,
|
||||
new ValueCompletionProcessor(javaProjectFinder, indexProvider, adHocIndexProvider));
|
||||
providers.put(Annotations.REPOSITORY, new DataRepositoryCompletionProcessor());
|
||||
|
||||
JavaSnippetManager snippetManager = new JavaSnippetManager(server::createSnippetBuilder);
|
||||
snippetManager.add(
|
||||
new JavaSnippet("RequestMapping method", JavaSnippetContext.BOOT_MEMBERS, CompletionItemKind.Method,
|
||||
ImmutableList.of("org.springframework.web.bind.annotation.RequestMapping",
|
||||
"org.springframework.web.bind.annotation.RequestMethod",
|
||||
"org.springframework.web.bind.annotation.RequestParam"),
|
||||
"@RequestMapping(value=\"${path}\", method=RequestMethod.${GET})\n"
|
||||
+ "public ${SomeData} ${requestMethodName}(@RequestParam ${String} ${param}) {\n"
|
||||
+ " return new ${SomeData}(${cursor});\n" + "}\n"));
|
||||
snippetManager
|
||||
.add(new JavaSnippet("GetMapping method", JavaSnippetContext.BOOT_MEMBERS, CompletionItemKind.Method,
|
||||
ImmutableList.of("org.springframework.web.bind.annotation.GetMapping",
|
||||
"org.springframework.web.bind.annotation.RequestParam"),
|
||||
"@GetMapping(value=\"${path}\")\n"
|
||||
+ "public ${SomeData} ${getMethodName}(@RequestParam ${String} ${param}) {\n"
|
||||
+ " return new ${SomeData}(${cursor});\n" + "}\n"));
|
||||
snippetManager.add(new JavaSnippet("PostMapping method", JavaSnippetContext.BOOT_MEMBERS,
|
||||
CompletionItemKind.Method,
|
||||
ImmutableList.of("org.springframework.web.bind.annotation.PostMapping",
|
||||
"org.springframework.web.bind.annotation.RequestBody"),
|
||||
"@PostMapping(value=\"${path}\")\n"
|
||||
+ "public ${SomeEnityData} ${postMethodName}(@RequestBody ${SomeEnityData} ${entity}) {\n"
|
||||
+ " //TODO: process POST request\n" + " ${cursor}\n" + " return ${entity};\n" + "}\n"));
|
||||
snippetManager.add(new JavaSnippet("PutMapping method", JavaSnippetContext.BOOT_MEMBERS,
|
||||
CompletionItemKind.Method,
|
||||
ImmutableList.of("org.springframework.web.bind.annotation.PutMapping",
|
||||
"org.springframework.web.bind.annotation.RequestBody",
|
||||
"org.springframework.web.bind.annotation.PathVariable"),
|
||||
"@PutMapping(value=\"${path}/{${id}}\")\n"
|
||||
+ "public ${SomeEnityData} ${putMethodName}(@PathVariable ${pvt:String} ${id}, @RequestBody ${SomeEnityData} ${entity}) {\n"
|
||||
+ " //TODO: process PUT request\n" + " ${cursor}\n" + " return ${entity};\n" + "}"));
|
||||
JavaSnippetManager snippetManager = getSnippets();
|
||||
return new BootJavaCompletionEngine(this, providers, snippetManager);
|
||||
}
|
||||
|
||||
protected JavaSnippetManager getSnippets() {
|
||||
JavaSnippetManager snippetManager = new JavaSnippetManager(server::createSnippetBuilder);
|
||||
|
||||
// PT 160529904: Eclipse templates are duplicated, due to templates in Eclipse also being contributed by
|
||||
// STS3 bundle. Therefore do not include templates if client is Eclipse
|
||||
// TODO: REMOVE this check once STS3 is no longer supported
|
||||
if (LspClient.currentClient() != LspClient.Client.ECLIPSE) {
|
||||
snippetManager.add(
|
||||
new JavaSnippet("RequestMapping method", JavaSnippetContext.BOOT_MEMBERS, CompletionItemKind.Method,
|
||||
ImmutableList.of("org.springframework.web.bind.annotation.RequestMapping",
|
||||
"org.springframework.web.bind.annotation.RequestMethod",
|
||||
"org.springframework.web.bind.annotation.RequestParam"),
|
||||
"@RequestMapping(value=\"${path}\", method=RequestMethod.${GET})\n"
|
||||
+ "public ${SomeData} ${requestMethodName}(@RequestParam ${String} ${param}) {\n"
|
||||
+ " return new ${SomeData}(${cursor});\n" + "}\n"));
|
||||
snippetManager
|
||||
.add(new JavaSnippet("GetMapping method", JavaSnippetContext.BOOT_MEMBERS, CompletionItemKind.Method,
|
||||
ImmutableList.of("org.springframework.web.bind.annotation.GetMapping",
|
||||
"org.springframework.web.bind.annotation.RequestParam"),
|
||||
"@GetMapping(value=\"${path}\")\n"
|
||||
+ "public ${SomeData} ${getMethodName}(@RequestParam ${String} ${param}) {\n"
|
||||
+ " return new ${SomeData}(${cursor});\n" + "}\n"));
|
||||
snippetManager.add(new JavaSnippet("PostMapping method", JavaSnippetContext.BOOT_MEMBERS,
|
||||
CompletionItemKind.Method,
|
||||
ImmutableList.of("org.springframework.web.bind.annotation.PostMapping",
|
||||
"org.springframework.web.bind.annotation.RequestBody"),
|
||||
"@PostMapping(value=\"${path}\")\n"
|
||||
+ "public ${SomeEnityData} ${postMethodName}(@RequestBody ${SomeEnityData} ${entity}) {\n"
|
||||
+ " //TODO: process POST request\n" + " ${cursor}\n" + " return ${entity};\n" + "}\n"));
|
||||
snippetManager.add(new JavaSnippet("PutMapping method", JavaSnippetContext.BOOT_MEMBERS,
|
||||
CompletionItemKind.Method,
|
||||
ImmutableList.of("org.springframework.web.bind.annotation.PutMapping",
|
||||
"org.springframework.web.bind.annotation.RequestBody",
|
||||
"org.springframework.web.bind.annotation.PathVariable"),
|
||||
"@PutMapping(value=\"${path}/{${id}}\")\n"
|
||||
+ "public ${SomeEnityData} ${putMethodName}(@PathVariable ${pvt:String} ${id}, @RequestBody ${SomeEnityData} ${entity}) {\n"
|
||||
+ " //TODO: process PUT request\n" + " ${cursor}\n" + " return ${entity};\n" + "}"));
|
||||
}
|
||||
|
||||
return snippetManager;
|
||||
}
|
||||
|
||||
protected BootJavaHoverProvider createHoverHandler(JavaProjectFinder javaProjectFinder,
|
||||
RunningAppProvider runningAppProvider, SourceLinks sourceLinks) {
|
||||
AnnotationHierarchyAwareLookup<HoverProvider> providers = new AnnotationHierarchyAwareLookup<>();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String REPOSITORY_TYPE = "org.springframework.data.repository.Repository";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data;
|
||||
|
||||
import java.util.Collection;
|
||||
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.TypeDeclaration;
|
||||
import org.eclipse.jdt.internal.core.util.ASTNodeFinder;
|
||||
import org.eclipse.lsp4j.CompletionItemKind;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.commons.util.text.IRegion;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class DataRepositoryCompletionProcessor implements CompletionProvider {
|
||||
|
||||
@Override
|
||||
public void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type,
|
||||
int offset, IDocument doc, Collection<ICompletionProposal> completions) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provideCompletions(ASTNode node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
|
||||
TypeDeclaration type = ASTUtils.findDeclaringType(node);
|
||||
DataRepositoryDefinition repo = getDataRepositoryDefinition(type);
|
||||
if (repo != null) {
|
||||
DomainType domainType = repo.getDomainType();
|
||||
if (domainType != null) {
|
||||
|
||||
String prefix = "";
|
||||
try {
|
||||
IRegion line = doc.getLineInformationOfOffset(offset);
|
||||
prefix = doc.get(line.getOffset(), offset - line.getOffset()).trim();
|
||||
} catch (BadLocationException e) {
|
||||
// ignore if there is a problem computing the prefix, continue without prefix
|
||||
}
|
||||
|
||||
DomainProperty[] properties = domainType.getProperties();
|
||||
for (DomainProperty property : properties) {
|
||||
completions.add(generateCompletionProposal(offset, prefix, repo, property));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected ICompletionProposal generateCompletionProposal(int offset, String prefix, DataRepositoryDefinition repoDef, DomainProperty domainProperty) {
|
||||
StringBuilder label = new StringBuilder();
|
||||
label.append("findBy");
|
||||
label.append(StringUtils.capitalize(domainProperty.getName()));
|
||||
label.append("(");
|
||||
label.append(domainProperty.getType().getSimpleName());
|
||||
label.append(" ");
|
||||
label.append(StringUtils.uncapitalize(domainProperty.getName()));
|
||||
label.append(");");
|
||||
|
||||
DocumentEdits edits = new DocumentEdits(null);
|
||||
|
||||
StringBuilder completion = new StringBuilder();
|
||||
completion.append("List<");
|
||||
completion.append(repoDef.getDomainType().getSimpleName());
|
||||
completion.append("> findBy");
|
||||
completion.append(StringUtils.capitalize(domainProperty.getName()));
|
||||
completion.append("(");
|
||||
completion.append(domainProperty.getType().getSimpleName());
|
||||
completion.append(" ");
|
||||
completion.append(StringUtils.uncapitalize(domainProperty.getName()));
|
||||
completion.append(");");
|
||||
|
||||
String filter = label.toString();
|
||||
if (prefix != null && label.toString().startsWith(prefix)) {
|
||||
edits.replace(offset - prefix.length(), offset, completion.toString());
|
||||
}
|
||||
else if (prefix != null && completion.toString().startsWith(prefix)) {
|
||||
edits.replace(offset - prefix.length(), offset, completion.toString());
|
||||
filter = completion.toString();
|
||||
}
|
||||
else {
|
||||
edits.insert(offset, completion.toString());
|
||||
}
|
||||
|
||||
DocumentEdits additionalEdits = new DocumentEdits(null);
|
||||
return new FindByCompletionProposal(label.toString(), CompletionItemKind.Method, edits, null, null, Optional.of(additionalEdits), filter);
|
||||
}
|
||||
|
||||
private DataRepositoryDefinition getDataRepositoryDefinition(TypeDeclaration type) {
|
||||
if (type != null) {
|
||||
ITypeBinding resolvedType = type.resolveBinding();
|
||||
return getDataRepositoryDefinition(type, resolvedType);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private DataRepositoryDefinition getDataRepositoryDefinition(TypeDeclaration type, ITypeBinding resolvedType) {
|
||||
if (resolvedType != null) {
|
||||
|
||||
// interface analysis
|
||||
ITypeBinding[] interfaces = resolvedType.getInterfaces();
|
||||
for (ITypeBinding resolvedInterface : interfaces) {
|
||||
String simplifiedType = null;
|
||||
if (resolvedInterface.isParameterizedType()) {
|
||||
simplifiedType = resolvedInterface.getBinaryName();
|
||||
}
|
||||
else {
|
||||
simplifiedType = resolvedType.getQualifiedName();
|
||||
}
|
||||
|
||||
if (Constants.REPOSITORY_TYPE.equals(simplifiedType)) {
|
||||
DomainType domainType = null;
|
||||
if (resolvedInterface.isParameterizedType()) {
|
||||
ITypeBinding[] typeParameters = resolvedInterface.getTypeArguments();
|
||||
if (typeParameters != null && typeParameters.length > 0) {
|
||||
domainType = new DomainType(typeParameters[0]);
|
||||
}
|
||||
}
|
||||
return createDataRepositoryDefinitionFromType(domainType);
|
||||
}
|
||||
else {
|
||||
DataRepositoryDefinition repo = getDataRepositoryDefinition(type, resolvedInterface);
|
||||
if (repo != null) {
|
||||
return repo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// super type analysis
|
||||
ITypeBinding superclass = resolvedType.getSuperclass();
|
||||
if (superclass != null) {
|
||||
return getDataRepositoryDefinition(type, superclass);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DataRepositoryDefinition createDataRepositoryDefinitionFromType(DomainType domainType) {
|
||||
return new DataRepositoryDefinition(domainType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class DataRepositoryDefinition {
|
||||
|
||||
private final DomainType domainType;
|
||||
|
||||
public DataRepositoryDefinition(DomainType domainType) {
|
||||
super();
|
||||
this.domainType = domainType;
|
||||
}
|
||||
|
||||
public DomainType getDomainType() {
|
||||
return domainType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,8 +36,6 @@ import reactor.util.function.Tuples;
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class DataRepositorySymbolProvider implements SymbolProvider {
|
||||
|
||||
private static final String REPOSITORY_TYPE = "org.springframework.data.repository.Repository";
|
||||
|
||||
@Override
|
||||
public Collection<EnhancedSymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc) {
|
||||
@@ -96,10 +94,10 @@ public class DataRepositorySymbolProvider implements SymbolProvider {
|
||||
simplifiedType = resolvedType.getQualifiedName();
|
||||
}
|
||||
|
||||
if (REPOSITORY_TYPE.equals(simplifiedType)) {
|
||||
if (Constants.REPOSITORY_TYPE.equals(simplifiedType)) {
|
||||
String beanName = getBeanName(typeDeclaration);
|
||||
String beanType = resolvedInterface.getName();
|
||||
|
||||
|
||||
String domainType = null;
|
||||
if (resolvedInterface.isParameterizedType()) {
|
||||
ITypeBinding[] typeParameters = resolvedInterface.getTypeArguments();
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class DomainProperty {
|
||||
|
||||
private final String name;
|
||||
private final DomainType type;
|
||||
|
||||
public DomainProperty(String name, DomainType type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public DomainType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.IMethodBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class DomainType {
|
||||
|
||||
private final String packageName;
|
||||
private final String fullName;
|
||||
private final String simpleName;
|
||||
private DomainProperty[] properties;
|
||||
|
||||
public DomainType(String packageName, String fullName, String simpleName) {
|
||||
this.packageName = packageName;
|
||||
this.fullName = fullName;
|
||||
this.simpleName = simpleName;
|
||||
}
|
||||
|
||||
public DomainType(ITypeBinding typeBinding) {
|
||||
this.packageName = typeBinding.getPackage().getName();
|
||||
this.fullName = typeBinding.getQualifiedName();
|
||||
this.simpleName = typeBinding.getName();
|
||||
|
||||
if (!this.packageName.startsWith("java")) {
|
||||
IMethodBinding[] methods = typeBinding.getDeclaredMethods();
|
||||
if (methods != null && methods.length > 0) {
|
||||
List<DomainProperty> properties = new ArrayList<>();
|
||||
|
||||
for (IMethodBinding method : methods) {
|
||||
String methodName = method.getName();
|
||||
if (methodName != null && methodName.startsWith("get")) {
|
||||
String propertyName = methodName.substring(3);
|
||||
properties.add(new DomainProperty(propertyName, new DomainType(method.getReturnType())));
|
||||
}
|
||||
}
|
||||
this.properties = (DomainProperty[]) properties.toArray(new DomainProperty[properties.size()]);
|
||||
}
|
||||
else {
|
||||
this.properties = new DomainProperty[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
public String getSimpleName() {
|
||||
return simpleName;
|
||||
}
|
||||
|
||||
public DomainProperty[] getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.lsp4j.CompletionItemKind;
|
||||
import org.eclipse.lsp4j.InsertTextFormat;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
|
||||
public class FindByCompletionProposal implements ICompletionProposal {
|
||||
|
||||
private String label;
|
||||
private CompletionItemKind kind;
|
||||
private DocumentEdits edits;
|
||||
private String details;
|
||||
private Renderable doc;
|
||||
private Optional<DocumentEdits> additionalEdits;
|
||||
private String filter;
|
||||
|
||||
public FindByCompletionProposal(String label, CompletionItemKind kind, DocumentEdits edits, String details,
|
||||
Renderable doc, Optional<DocumentEdits> additionalEdits, String filter) {
|
||||
super();
|
||||
this.label = label;
|
||||
this.kind = kind;
|
||||
this.edits = edits;
|
||||
this.details = details;
|
||||
this.doc = doc;
|
||||
this.additionalEdits = additionalEdits;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionItemKind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentEdits getTextEdit() {
|
||||
return edits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDetail() {
|
||||
return details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Renderable getDocumentation() {
|
||||
return doc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DocumentEdits> getAdditionalEdit() {
|
||||
return additionalEdits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertTextFormat getInsertTextFormat() {
|
||||
return InsertTextFormat.Snippet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilterText() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,8 +49,9 @@ public class BootJavaCompletionEngine implements ICompletionEngine {
|
||||
|
||||
if (node != null) {
|
||||
Collection<ICompletionProposal> completions = new ArrayList<ICompletionProposal>();
|
||||
completions.addAll(collectCompletionsForAnnotations(node, offset, document));
|
||||
completions.addAll(snippets.getCompletions(document, offset, node, cu));
|
||||
collectCompletionsForAnnotations(node, offset, document, completions);
|
||||
collectCompletions(node, offset, document, completions);
|
||||
snippets.getCompletions(document, offset, node, cu, completions);
|
||||
return completions;
|
||||
}
|
||||
}
|
||||
@@ -59,7 +60,7 @@ public class BootJavaCompletionEngine implements ICompletionEngine {
|
||||
});
|
||||
}
|
||||
|
||||
private Collection<ICompletionProposal> collectCompletionsForAnnotations(ASTNode node, int offset, IDocument doc) {
|
||||
private void collectCompletionsForAnnotations(ASTNode node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
|
||||
Annotation annotation = null;
|
||||
ASTNode exactNode = node;
|
||||
|
||||
@@ -75,13 +76,19 @@ public class BootJavaCompletionEngine implements ICompletionEngine {
|
||||
if (qualifiedName != null) {
|
||||
CompletionProvider provider = this.completionProviders.get(qualifiedName);
|
||||
if (provider != null) {
|
||||
return provider.provideCompletions(exactNode, annotation, type, offset, doc);
|
||||
provider.provideCompletions(exactNode, annotation, type, offset, doc, completions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
private void collectCompletions(ASTNode node, int offset, TextDocument document, Collection<ICompletionProposal> completions) {
|
||||
if (node != null) {
|
||||
for (CompletionProvider completionProvider : this.completionProviders.values()) {
|
||||
completionProvider.provideCompletions(node, offset, document, completions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -23,6 +23,7 @@ import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
*/
|
||||
public interface CompletionProvider {
|
||||
|
||||
Collection<ICompletionProposal> provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type, int offset, IDocument doc);
|
||||
void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type, int offset, IDocument doc, Collection<ICompletionProposal> completions);
|
||||
void provideCompletions(ASTNode node, int offset, IDocument doc, Collection<ICompletionProposal> completions);
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -84,7 +83,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
|
||||
LiveBean definedBean = getDefinedBean(annotation);
|
||||
if (definedBean != null) {
|
||||
Hover hover = assembleHover(project, runningApps, definedBean, annotation);
|
||||
Hover hover = assembleHover(project, runningApps, definedBean, annotation, true, true);
|
||||
if (hover != null) {
|
||||
Optional<Range> nameRange = ASTUtils.nameRange(doc, annotation);
|
||||
if (nameRange.isPresent()) {
|
||||
@@ -97,77 +96,84 @@ 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) {
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
return codeLensList;
|
||||
}
|
||||
|
||||
protected List<LiveBean> findWiredBeans(IJavaProject project, SpringBootApp app, List<LiveBean> relevantBeans, ASTNode astNode) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected Hover assembleHover(IJavaProject project, SpringBootApp[] runningApps, LiveBean definedBean, ASTNode astNode) {
|
||||
StringBuilder hover = new StringBuilder();
|
||||
|
||||
boolean hasContent = false;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (!hasContent) {
|
||||
hasContent = true;
|
||||
} else {
|
||||
// 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 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) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected Hover assembleHover(IJavaProject project, SpringBootApp[] runningApps, LiveBean definedBean, ASTNode astNode, boolean injected, boolean wired) {
|
||||
StringBuilder hover = new StringBuilder();
|
||||
|
||||
for (SpringBootApp app : runningApps) {
|
||||
|
||||
List<LiveBean> relevantBeans = LiveHoverUtils.findRelevantBeans(app, definedBean);
|
||||
|
||||
if (!relevantBeans.isEmpty()) {
|
||||
if (hover.length() > 0) {
|
||||
hover.append(" \n \n");
|
||||
}
|
||||
|
||||
if (!injectedBeans.isEmpty()) {
|
||||
hover.append("**");
|
||||
hover.append(LiveHoverUtils.createBeansTitleMarkdown(sourceLinks, project, injectedBeans, BEANS_PREFIX_MARKDOWN, MAX_INLINE_BEANS_STRING_LENGTH, INLINE_BEANS_STRING_SEPARATOR));
|
||||
hover.append("**\n");
|
||||
hover.append(injectedBeans.stream()
|
||||
.map(b -> "- " + LiveHoverUtils.showBeanWithResource(sourceLinks, b, " ", project))
|
||||
.collect(Collectors.joining("\n")));
|
||||
hover.append("\n \n");
|
||||
}
|
||||
List<LiveBean> wiredBeans = findWiredBeans(project, app, relevantBeans, astNode);
|
||||
if (!wiredBeans.isEmpty()) {
|
||||
AutowiredHoverProvider.createHoverContentForBeans(sourceLinks, project, hover, wiredBeans);
|
||||
if (injected) {
|
||||
List<LiveBean> injectedBeans = getRelevantInjectedIntoBeans(project, app, definedBean, relevantBeans);
|
||||
if (!injectedBeans.isEmpty()) {
|
||||
hover.append("**");
|
||||
hover.append(LiveHoverUtils.createBeansTitleMarkdown(sourceLinks, project, injectedBeans, BEANS_PREFIX_MARKDOWN, MAX_INLINE_BEANS_STRING_LENGTH, INLINE_BEANS_STRING_SEPARATOR));
|
||||
hover.append("**\n");
|
||||
hover.append(injectedBeans.stream()
|
||||
.map(b -> "- " + LiveHoverUtils.showBeanWithResource(sourceLinks, b, " ", project))
|
||||
.collect(Collectors.joining("\n")));
|
||||
hover.append("\n \n");
|
||||
}
|
||||
}
|
||||
|
||||
hover.append("Bean id: `");
|
||||
hover.append(definedBean.getId());
|
||||
hover.append("` \n");
|
||||
hover.append(LiveHoverUtils.niceAppName(app));
|
||||
if (wired) {
|
||||
List<LiveBean> wiredBeans = findWiredBeans(project, app, relevantBeans, astNode);
|
||||
if (!wiredBeans.isEmpty()) {
|
||||
AutowiredHoverProvider.createHoverContentForBeans(sourceLinks, project, hover, wiredBeans);
|
||||
}
|
||||
|
||||
hover.append("Bean id: `");
|
||||
hover.append(definedBean.getId());
|
||||
hover.append("` \n");
|
||||
hover.append(LiveHoverUtils.niceAppName(app));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (hasContent) {
|
||||
if (hover.length() > 0) {
|
||||
return new Hover(ImmutableList.of(Either.forLeft(hover.toString())));
|
||||
} else {
|
||||
return null;
|
||||
|
||||
@@ -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, false, true);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
|
||||
LiveBean definedBean = getDefinedBeanForType(typeDeclaration, null);
|
||||
if (definedBean != null) {
|
||||
Hover hover = assembleHover(project, runningApps, definedBean, typeDeclaration);
|
||||
Hover hover = assembleHover(project, runningApps, definedBean, typeDeclaration, true, true);
|
||||
if (hover != null) {
|
||||
SimpleName name = typeDeclaration.getName();
|
||||
try {
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.scope;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
@@ -30,10 +28,8 @@ import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
public class ScopeCompletionProcessor implements CompletionProvider {
|
||||
|
||||
@Override
|
||||
public Collection<ICompletionProposal> provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type,
|
||||
int offset, IDocument doc) {
|
||||
|
||||
List<ICompletionProposal> result = new ArrayList<>();
|
||||
public void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type,
|
||||
int offset, IDocument doc, Collection<ICompletionProposal> completions) {
|
||||
|
||||
try {
|
||||
if (node instanceof SimpleName && node.getParent() instanceof MemberValuePair) {
|
||||
@@ -43,7 +39,7 @@ public class ScopeCompletionProcessor implements CompletionProvider {
|
||||
if ("value".equals(memberPair.getName().toString()) && memberPair.getValue().toString().equals("$missing$")) {
|
||||
for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, offset, offset, "");
|
||||
result.add(proposal);
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +47,7 @@ public class ScopeCompletionProcessor implements CompletionProvider {
|
||||
else if (node == annotation && doc.get(offset - 1, 2).endsWith("()")) {
|
||||
for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, offset, offset, "");
|
||||
result.add(proposal);
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
else if (node instanceof StringLiteral && node.getParent() instanceof Annotation) {
|
||||
@@ -61,7 +57,7 @@ public class ScopeCompletionProcessor implements CompletionProvider {
|
||||
for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
if (completion.getValue().startsWith(prefix)) {
|
||||
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, node.getStartPosition(), node.getStartPosition() + node.getLength(), prefix);
|
||||
result.add(proposal);
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +71,7 @@ public class ScopeCompletionProcessor implements CompletionProvider {
|
||||
for (ScopeNameCompletion completion : ScopeNameCompletionProposal.COMPLETIONS) {
|
||||
if (completion.getValue().startsWith(prefix)) {
|
||||
ICompletionProposal proposal = new ScopeNameCompletionProposal(completion, doc, node.getStartPosition(), node.getStartPosition() + node.getLength(), prefix);
|
||||
result.add(proposal);
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,8 +80,10 @@ public class ScopeCompletionProcessor implements CompletionProvider {
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@Override
|
||||
public void provideCompletions(ASTNode node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -47,9 +47,7 @@ public class JavaSnippetManager {
|
||||
|
||||
}
|
||||
|
||||
public Collection<ICompletionProposal> getCompletions(IDocument doc, int offset, ASTNode node, CompilationUnit cu) {
|
||||
Collection<ICompletionProposal> completions = new ArrayList<>();
|
||||
|
||||
public void getCompletions(IDocument doc, int offset, ASTNode node, CompilationUnit cu, Collection<ICompletionProposal> completions) {
|
||||
DocumentRegion query = PREFIX_FINDER.getPrefixRegion(doc, offset);
|
||||
|
||||
for (JavaSnippet javaSnippet : snippets) {
|
||||
@@ -58,8 +56,6 @@ public class JavaSnippetManager {
|
||||
.ifPresent((completion) -> completions.add(completion));
|
||||
}
|
||||
}
|
||||
|
||||
return completions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ package org.springframework.ide.vscode.boot.java.value;
|
||||
|
||||
import static org.springframework.ide.vscode.commons.util.StringUtil.camelCaseToHyphens;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -56,10 +55,8 @@ public class ValueCompletionProcessor implements CompletionProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ICompletionProposal> provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type,
|
||||
int offset, IDocument doc) {
|
||||
|
||||
List<ICompletionProposal> result = new ArrayList<>();
|
||||
public void provideCompletions(ASTNode node, Annotation annotation, ITypeBinding type,
|
||||
int offset, IDocument doc, Collection<ICompletionProposal> completions) {
|
||||
|
||||
try {
|
||||
// case: @Value(<*>)
|
||||
@@ -76,40 +73,42 @@ public class ValueCompletionProcessor implements CompletionProvider {
|
||||
// if it cannot resolve it. If sending this as plain text, then insertion happens correctly
|
||||
ValuePropertyKeyProposal proposal = new ValuePropertyKeyProposal(edits, match, InsertTextFormat.PlainText);
|
||||
|
||||
result.add(proposal);
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
// case: @Value(prefix<*>)
|
||||
else if (node instanceof SimpleName && node.getParent() instanceof Annotation) {
|
||||
computeProposalsForSimpleName(node, result, offset, doc);
|
||||
computeProposalsForSimpleName(node, completions, offset, doc);
|
||||
}
|
||||
// case: @Value(value=<*>)
|
||||
else if (node instanceof SimpleName && node.getParent() instanceof MemberValuePair
|
||||
&& "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
|
||||
computeProposalsForSimpleName(node, result, offset, doc);
|
||||
computeProposalsForSimpleName(node, completions, offset, doc);
|
||||
}
|
||||
// case: @Value("prefix<*>")
|
||||
else if (node instanceof StringLiteral && node.getParent() instanceof Annotation) {
|
||||
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
computeProposalsForStringLiteral(node, result, offset, doc);
|
||||
computeProposalsForStringLiteral(node, completions, offset, doc);
|
||||
}
|
||||
}
|
||||
// case: @Value(value="prefix<*>")
|
||||
else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair
|
||||
&& "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
|
||||
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
computeProposalsForStringLiteral(node, result, offset, doc);
|
||||
computeProposalsForStringLiteral(node, completions, offset, doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void computeProposalsForSimpleName(ASTNode node, List<ICompletionProposal> completions, int offset,
|
||||
@Override
|
||||
public void provideCompletions(ASTNode node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
|
||||
}
|
||||
|
||||
private void computeProposalsForSimpleName(ASTNode node, Collection<ICompletionProposal> completions, int offset,
|
||||
IDocument doc) {
|
||||
String prefix = identifyPropertyPrefix(node.toString(), offset - node.getStartPosition());
|
||||
|
||||
@@ -132,7 +131,7 @@ public class ValueCompletionProcessor implements CompletionProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private void computeProposalsForStringLiteral(ASTNode node, List<ICompletionProposal> completions, int offset,
|
||||
private void computeProposalsForStringLiteral(ASTNode node, Collection<ICompletionProposal> completions, int offset,
|
||||
IDocument doc) throws BadLocationException {
|
||||
String prefix = identifyPropertyPrefix(doc.get(node.getStartPosition() + 1, offset - (node.getStartPosition() + 1)), offset - (node.getStartPosition() + 1));
|
||||
|
||||
|
||||
@@ -507,7 +507,7 @@ public class AutowiredHoverProviderTest {
|
||||
"}\n"
|
||||
);
|
||||
|
||||
editor.assertHighlights("@Component", "SomeComponent");
|
||||
editor.assertHighlights("@Component", "SomeComponent", "depA", "depB");
|
||||
|
||||
editor.assertTrimmedHover("SomeComponent", 2,
|
||||
"**← `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,
|
||||
"**← `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,
|
||||
"**← `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,
|
||||
"**← `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",
|
||||
"**← `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",
|
||||
"**← `DependencyB`**\n" +
|
||||
"- Bean: `dependencyB` \n" +
|
||||
" Type: `com.example.DependencyB`\n" +
|
||||
" \n" +
|
||||
"Bean id: `someComponent` \n" +
|
||||
"Process [PID=111, name=`the-app`]\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.lsp4j.CompletionItem;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
|
||||
import org.springframework.ide.vscode.boot.bootiful.HoverTestConf;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.TestAsserts;
|
||||
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@BootLanguageServerTest
|
||||
@Import(HoverTestConf.class)
|
||||
public class DataRepositoryCompletionProcessorTest {
|
||||
|
||||
@Autowired private BootLanguageServerHarness harness;
|
||||
private Editor editor;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
IJavaProject testProject = ProjectsHarness.INSTANCE.mavenProject("test-spring-data-symbols");
|
||||
harness.useProject(testProject);
|
||||
harness.intialize(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardFindByCompletions() throws Exception {
|
||||
prepareCase("{", "{<*>");
|
||||
assertContainsAnnotationCompletions(
|
||||
"List<Customer> findByFirstName(String firstName);",
|
||||
"List<Customer> findByLastName(String lastName);");
|
||||
}
|
||||
|
||||
private void prepareCase(String selectedAnnotation, String annotationStatementBeforeTest) throws Exception {
|
||||
InputStream resource = this.getClass().getResourceAsStream("/test-projects/test-spring-data-symbols/src/main/java/org/test/TestCustomerRepositoryForCompletions.java");
|
||||
String content = IOUtils.toString(resource);
|
||||
|
||||
content = content.replace(selectedAnnotation, annotationStatementBeforeTest);
|
||||
editor = new Editor(harness, content, LanguageId.JAVA);
|
||||
}
|
||||
|
||||
private void assertContainsAnnotationCompletions(String... expectedResultsFromCompletion) throws Exception {
|
||||
List<CompletionItem> completions = editor.getCompletions();
|
||||
|
||||
int i = 0;
|
||||
for (CompletionItem foundCompletion : completions) {
|
||||
Editor clonedEditor = editor.clone();
|
||||
clonedEditor.apply(foundCompletion);
|
||||
|
||||
if (clonedEditor.getText().contains(expectedResultsFromCompletion[i])) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(expectedResultsFromCompletion.length, i);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -63,7 +63,7 @@ public class DataRepositorySymbolProviderTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleReppositorySymbol() throws Exception {
|
||||
public void testSimpleRepositorySymbol() throws Exception {
|
||||
String docUri = directory.toPath().resolve("src/main/java/org/test/CustomerRepository.java").toUri().toString();
|
||||
List<? extends SymbolInformation> symbols = indexer.getSymbols(docUri);
|
||||
assertEquals(1, symbols.size());
|
||||
|
||||
@@ -238,6 +238,80 @@ public class BeanInjectedIntoHoverProviderTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanWithOneInjectionAndWiring() throws Exception {
|
||||
LiveBeansModel beans = LiveBeansModel.builder()
|
||||
.add(LiveBean.builder()
|
||||
.id("fooImplementation")
|
||||
.type("hello.FooImplementation")
|
||||
.dependencies("message")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("myController")
|
||||
.type("hello.MyController")
|
||||
.dependencies("fooImplementation")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("message")
|
||||
.type("java.lang.String")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("irrelevantBean")
|
||||
.type("com.example.IrrelevantBean")
|
||||
.dependencies("myController")
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
mockAppProvider.builder()
|
||||
.isSpringBootApp(true)
|
||||
.processId("111")
|
||||
.processName("the-app")
|
||||
.beans(beans)
|
||||
.build();
|
||||
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA,
|
||||
"package hello;\n" +
|
||||
"\n" +
|
||||
"import org.springframework.context.annotation.Bean;\n" +
|
||||
"import org.springframework.context.annotation.Configuration;\n" +
|
||||
"import org.springframework.context.annotation.Profile;\n" +
|
||||
"\n" +
|
||||
"@Configuration\n" +
|
||||
"public class LocalConfig {\n" +
|
||||
" \n" +
|
||||
" @Bean(\"fooImplementation\")\n" +
|
||||
" Foo someFoo(String msg) {\n" +
|
||||
" return new FooImplementation();\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
);
|
||||
// !!! 2 highlights over @Bean. 1 for injected beans CodeLens, 1 for wired beans CodeLens
|
||||
editor.assertHighlights("@Bean", "@Bean", "msg");
|
||||
editor.assertTrimmedHover("@Bean",
|
||||
"**→ `MyController`**\n" +
|
||||
"- Bean: `myController` \n" +
|
||||
" Type: `hello.MyController`\n" +
|
||||
" \n" +
|
||||
"**← `String`**\n" +
|
||||
"- Bean: `message` \n" +
|
||||
" Type: `java.lang.String`\n" +
|
||||
" \n" +
|
||||
"Bean id: `fooImplementation` \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
editor.assertTrimmedHover("msg",
|
||||
"**← `String`**\n" +
|
||||
"- Bean: `message` \n" +
|
||||
" Type: `java.lang.String`\n" +
|
||||
" \n" +
|
||||
"Bean id: `fooImplementation` \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanFromInnerClassWithOneInjection() throws Exception {
|
||||
LiveBeansModel beans = LiveBeansModel.builder()
|
||||
@@ -549,12 +623,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",
|
||||
"**← `DependencyA`**\n" +
|
||||
"- Bean: `depA` \n" +
|
||||
@@ -563,6 +637,16 @@ public class BeanInjectedIntoHoverProviderTest {
|
||||
"Bean id: `fooImplementation` \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
|
||||
editor.assertTrimmedHover("depA",
|
||||
"**← `DependencyA`**\n" +
|
||||
"- Bean: `depA` \n" +
|
||||
" Type: `hello.DependencyA`\n" +
|
||||
" \n" +
|
||||
"Bean id: `fooImplementation` \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -603,12 +687,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",
|
||||
"**← `DependencyA` `DependencyB`**\n" +
|
||||
"- Bean: `depA` \n" +
|
||||
@@ -619,6 +703,25 @@ public class BeanInjectedIntoHoverProviderTest {
|
||||
"Bean id: `fooImplementation` \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
|
||||
editor.assertTrimmedHover("depA",
|
||||
"**← `DependencyA`**\n" +
|
||||
"- Bean: `depA` \n" +
|
||||
" Type: `hello.DependencyA`\n" +
|
||||
" \n" +
|
||||
"Bean id: `fooImplementation` \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
|
||||
editor.assertTrimmedHover("depB",
|
||||
"**← `DependencyB`**\n" +
|
||||
"- Bean: `depB` \n" +
|
||||
" Type: `hello.DependencyB`\n" +
|
||||
" \n" +
|
||||
"Bean id: `fooImplementation` \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -664,7 +767,7 @@ public class BeanInjectedIntoHoverProviderTest {
|
||||
" }\n" +
|
||||
"}"
|
||||
);
|
||||
editor.assertHighlights("@Bean");
|
||||
editor.assertHighlights("@Bean", "deps");
|
||||
editor.assertTrimmedHover("@Bean",
|
||||
"**← `DependencyA` `DependencyB`**\n" +
|
||||
"- Bean: `depA` \n" +
|
||||
@@ -675,7 +778,18 @@ public class BeanInjectedIntoHoverProviderTest {
|
||||
"Bean id: `fooImplementation` \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
}
|
||||
|
||||
editor.assertTrimmedHover("deps",
|
||||
"**← `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 +829,7 @@ public class BeanInjectedIntoHoverProviderTest {
|
||||
" }\n" +
|
||||
"}"
|
||||
);
|
||||
editor.assertHighlights("@Bean");
|
||||
editor.assertHighlights("@Bean", "deps");
|
||||
editor.assertTrimmedHover("@Bean",
|
||||
"**← `DependencyB`**\n" +
|
||||
"- Bean: `depB` \n" +
|
||||
@@ -724,5 +838,15 @@ public class BeanInjectedIntoHoverProviderTest {
|
||||
"Bean id: `fooImplementation` \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
|
||||
editor.assertTrimmedHover("deps",
|
||||
"**← `DependencyB`**\n" +
|
||||
"- Bean: `depB` \n" +
|
||||
" Type: `hello.DependencyB`\n" +
|
||||
" \n" +
|
||||
"Bean id: `fooImplementation` \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,7 +501,7 @@ public class ComponentInjectionsHoverProviderTest {
|
||||
" }\n" +
|
||||
"}\n"
|
||||
);
|
||||
editor.assertHighlights("@Component", "AutowiredClass");
|
||||
editor.assertHighlights("@Component", "AutowiredClass", "depA", "depB");
|
||||
editor.assertTrimmedHover("@Component",
|
||||
"**← `DependencyA` `DependencyB`**\n" +
|
||||
"- Bean: `dependencyA` \n" +
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface TestCustomerRepositoryForCompletions extends CrudRepository<Customer, Long> {
|
||||
}
|
||||
Reference in New Issue
Block a user