diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java index 3285f967b..7ea6dcd5c 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java @@ -28,6 +28,7 @@ import org.springframework.ide.vscode.boot.java.utils.ASTUtils; 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.Log; import org.springframework.ide.vscode.commons.util.StringUtil; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -73,7 +74,7 @@ public class AutowiredHoverProvider implements HoverProvider { @Override public CompletableFuture provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset, - TextDocument doc, SpringBootApp[] runningApps) { + TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) { if (runningApps.length > 0) { StringBuilder hover = new StringBuilder(); @@ -100,7 +101,7 @@ public class AutowiredHoverProvider implements HoverProvider { for (LiveBean bean : relevantBeans) { hover.append("\n\n"); - hasAutowiring |= addAutomaticallyWired(hover, annotation, beans, bean); + hasAutowiring |= addAutomaticallyWired(hover, annotation, beans, bean, project); } } } @@ -137,7 +138,7 @@ public class AutowiredHoverProvider implements HoverProvider { return null; } - private boolean addAutomaticallyWired(StringBuilder hover, Annotation annotation, LiveBeansModel beans, LiveBean bean) { + private boolean addAutomaticallyWired(StringBuilder hover, Annotation annotation, LiveBeansModel beans, LiveBean bean, IJavaProject project) { boolean result = false; String[] dependencies = bean.getDependencies(); @@ -152,7 +153,7 @@ public class AutowiredHoverProvider implements HoverProvider { } List dependencyBeans = beans.getBeansOfName(injectedBean); for (LiveBean dependencyBean : dependencyBeans) { - hover.append("- " + LiveHoverUtils.showBean(dependencyBean)); + hover.append("- " + LiveHoverUtils.showBeanWithResource(dependencyBean, " ", project)); } firstDependency = false; } diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java index bd09eea96..19adceff4 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java @@ -32,6 +32,7 @@ import org.json.JSONObject; import org.springframework.ide.vscode.boot.java.handlers.HoverProvider; import org.springframework.ide.vscode.boot.java.utils.HoverContentUtils; import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; +import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -47,7 +48,7 @@ public class ConditionalsLiveHoverProvider implements HoverProvider { @Override public CompletableFuture provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset, - TextDocument doc, SpringBootApp[] runningApps) { + TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) { return provideHover(annotation, doc, runningApps); } diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java index 78b26ff24..51099c297 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java @@ -185,7 +185,7 @@ public class BootJavaHoverProvider implements HoverHandler { SpringBootApp[] runningApps = getRunningSpringApps(project); if (runningApps.length>0) { if (hasActuatorDependency(project)) { - return provider.provideHover(node, annotation, type, offset, doc, runningApps); + return provider.provideHover(node, annotation, type, offset, doc, project, runningApps); } else { DocumentRegion region = ASTUtils.nameRegion(doc, annotation); if (region.containsOffset(offset)) { diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/HoverProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/HoverProvider.java index 117dfda75..71d60ebb2 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/HoverProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/HoverProvider.java @@ -19,6 +19,7 @@ import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.Range; import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; +import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.util.text.TextDocument; /** @@ -26,7 +27,7 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument; */ public interface HoverProvider { - CompletableFuture provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset, TextDocument doc, SpringBootApp[] runningApps); + CompletableFuture provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset, TextDocument doc, IJavaProject project, SpringBootApp[] runningApps); Collection getLiveHoverHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps); } diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/AbstractInjectedIntoHoverProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/AbstractInjectedIntoHoverProvider.java index f1f8eddd8..557561e9c 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/AbstractInjectedIntoHoverProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/AbstractInjectedIntoHoverProvider.java @@ -28,6 +28,7 @@ import org.springframework.ide.vscode.boot.java.utils.ASTUtils; 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.Log; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -58,7 +59,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider @Override public CompletableFuture provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset, - TextDocument doc, SpringBootApp[] runningApps) { + TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) { if (runningApps.length > 0) { LiveBean definedBean = getDefinedBean(annotation); @@ -80,7 +81,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider hover.append(LiveHoverUtils.niceAppName(app) + ":"); for (LiveBean bean : relevantBeans) { - addInjectedInto(definedBean, hover, beans, bean); + addInjectedInto(definedBean, hover, beans, bean, project); addAutomaticallyWiredContructor(hover, annotation, beans, bean); } } @@ -103,7 +104,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider //This does nothing by default as its really only relevant to @Component annotation report. } - protected void addInjectedInto(LiveBean definedBean, StringBuilder hover, LiveBeansModel beans, LiveBean bean) { + protected void addInjectedInto(LiveBean definedBean, StringBuilder hover, LiveBeansModel beans, LiveBean bean, IJavaProject project) { hover.append("\n\n"); List dependers = beans.getBeansDependingOn(bean.getId()); if (dependers.isEmpty()) { @@ -115,7 +116,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider if (!firstDependency) { hover.append("\n"); } - hover.append("- " + LiveHoverUtils.showBean(dependingBean)); + hover.append("- " + LiveHoverUtils.showBeanWithResource(dependingBean, " ", project)); firstDependency = false; } } diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ActiveProfilesProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ActiveProfilesProvider.java index 091737177..3a72e2ca6 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ActiveProfilesProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ActiveProfilesProvider.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.livehover; -import static org.springframework.ide.vscode.boot.java.utils.ASTUtils.*; +import static org.springframework.ide.vscode.boot.java.utils.ASTUtils.nameRange; import java.util.Collection; import java.util.List; @@ -29,6 +29,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.springframework.ide.vscode.boot.java.handlers.HoverProvider; import org.springframework.ide.vscode.boot.java.utils.ASTUtils; import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; +import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -47,7 +48,7 @@ public class ActiveProfilesProvider implements HoverProvider { Annotation annotation, ITypeBinding type, int offset, - TextDocument doc, SpringBootApp[] runningApps + TextDocument doc, IJavaProject project, SpringBootApp[] runningApps ) { if (runningApps.length>0) { StringBuilder markdown = new StringBuilder(); diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java index ac1f96887..53f2a1c45 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java @@ -12,9 +12,12 @@ package org.springframework.ide.vscode.boot.java.livehover; import java.util.stream.Stream; +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.StringUtil; public class LiveHoverUtils { @@ -28,6 +31,28 @@ public class LiveHoverUtils { return buf.toString(); } + public static String showBeanWithResource(LiveBean bean, String indentStr, IJavaProject project) { + String newline = " \n"+indentStr; //Note: the double space before newline makes markdown see it as a real line break + StringBuilder buf = new StringBuilder("Bean: "); + buf.append(bean.getId()); + String type = bean.getType(); + if (type!=null) { + buf.append(newline); + buf.append("Type: `"+type+"`"); + } + String resource = bean.getResource(); + if (StringUtil.hasText(resource)) { + buf.append(newline); + buf.append("Resource: "); + buf.append(showResource(resource, project)); + } + return buf.toString(); + } + + public static String showResource(String resource, IJavaProject project) { + return new SpringResource(resource, project).toMarkdown(); + } + public static String niceAppName(SpringBootApp app) { return "Process [PID=" + app.getProcessID() + ", name=`" + app.getProcessName() + "`]"; } diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingHoverProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingHoverProvider.java index ab7b4da6b..449163e24 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingHoverProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingHoverProvider.java @@ -31,6 +31,7 @@ import org.springframework.ide.vscode.boot.java.handlers.HoverProvider; import org.springframework.ide.vscode.boot.java.utils.HoverContentUtils; import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.RequestMapping; +import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.Renderable; @@ -49,7 +50,7 @@ public class RequestMappingHoverProvider implements HoverProvider { @Override public CompletableFuture provideHover(ASTNode node, Annotation annotation, - ITypeBinding type, int offset, TextDocument doc, SpringBootApp[] runningApps) { + ITypeBinding type, int offset, TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) { return provideHover(annotation, doc, runningApps); } diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringResource.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringResource.java new file mode 100644 index 000000000..60d1e0b21 --- /dev/null +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringResource.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2017 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.utils; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.springframework.ide.vscode.commons.java.IClasspath; +import org.springframework.ide.vscode.commons.java.IJavaProject; + +/** + * Helper class, represents parsed info from a Resource, and provide method(s) to + * display it somehow. + */ +public class SpringResource { + + private static final String FILE = "file"; + private static final String CLASS_PATH_RESOURCE = "class path resource"; + + private String type; + private String path; + private IJavaProject project; + + private static final Pattern BRACKETS = Pattern.compile("\\[[^\\]]*\\]"); + + public SpringResource(String toParse, IJavaProject project) { + this.project = project; + Matcher matcher = BRACKETS.matcher(toParse); + if (matcher.find()) { + type = toParse.substring(0, matcher.start()).trim(); + path = toParse.substring(matcher.start()+1, matcher.end()-1); + } else { + path = toParse; + } + } + + public String toMarkdown() { + if (type==null) { + return path; //path is just the raw text in this case + } + switch (type) { + case FILE: + return "`"+projectRelativePath(path)+"`"; + case CLASS_PATH_RESOURCE: + return "`"+path+"`"; + default: + return path; + } + } + + private String projectRelativePath(String pathStr) { + Path path = Paths.get(pathStr); + IClasspath classpath = project.getClasspath(); + Path outputFolder = classpath.getOutputFolder(); + System.out.println("outf = "+outputFolder); + System.out.println("path = "+pathStr); + if (path.startsWith(outputFolder)) { + return outputFolder.relativize(path).toString(); + } + return pathStr; + } + +} diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueHoverProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueHoverProvider.java index debd85594..3d034e081 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueHoverProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueHoverProvider.java @@ -28,6 +28,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.json.JSONObject; import org.springframework.ide.vscode.boot.java.handlers.HoverProvider; import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; +import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.util.text.TextDocument; /** @@ -37,7 +38,7 @@ public class ValueHoverProvider implements HoverProvider { @Override public CompletableFuture provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset, - TextDocument doc, SpringBootApp[] runningApps) { + TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) { try { // case: @Value("prefix<*>") diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/autowired/test/AutowiredHoverProviderTest.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/autowired/test/AutowiredHoverProviderTest.java index b9f8f717f..18b3f707e 100644 --- a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/autowired/test/AutowiredHoverProviderTest.java +++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/autowired/test/AutowiredHoverProviderTest.java @@ -127,8 +127,10 @@ public class AutowiredHoverProviderTest { "\n" + "Bean [id: autowiredClass, type: `com.example.AutowiredClass`] got autowired with:\n" + "\n" + - "- Bean [id: dependencyA, type: `com.example.DependencyA`]\n" + - "- Bean [id: dependencyB, type: `com.example.DependencyB`]\n" + "- Bean: dependencyA \n" + + " Type: `com.example.DependencyA`\n" + + "- Bean: dependencyB \n" + + " Type: `com.example.DependencyB`\n" ); } diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/BeanInjectedIntoHoverProviderTest.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/BeanInjectedIntoHoverProviderTest.java index 5314e5d52..694886cc3 100644 --- a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/BeanInjectedIntoHoverProviderTest.java +++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/BeanInjectedIntoHoverProviderTest.java @@ -12,12 +12,15 @@ package org.springframework.ide.vscode.boot.java.livehover.test; import static org.junit.Assert.assertTrue; +import java.nio.file.Path; import java.time.Duration; +import java.util.Optional; import org.junit.Before; import org.junit.Test; 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.maven.java.MavenJavaProject; import org.springframework.ide.vscode.commons.util.text.LanguageId; import org.springframework.ide.vscode.languageserver.testharness.Editor; @@ -213,10 +216,125 @@ public class BeanInjectedIntoHoverProviderTest { "\n" + "Bean [id: fooImplementation, type: `hello.FooImplementation`] injected into:\n" + "\n" + - "- Bean [id: myController, type: `hello.MyController`]\n" + "- Bean: myController \n" + + " Type: `hello.MyController`\n" ); } + @Test + public void beanWithFileResource() throws Exception { + Path of = getOutputFolder(); + LiveBeansModel beans = LiveBeansModel.builder() + .add(LiveBean.builder() + .id("fooImplementation") + .type("hello.FooImplementation") + .fileResource("should/not/matter") + .build() + ) + .add(LiveBean.builder() + .id("myController") + .type("hello.MyController") + .fileResource(of+"/hello/MyController.class") + .dependencies("fooImplementation") + .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() {\n" + + " return new FooImplementation();\n" + + " }\n" + + "}" + ); + editor.assertHighlights("@Bean"); + editor.assertTrimmedHover("@Bean", + "**Injection report for Bean [id: fooImplementation]**\n" + + "\n" + + "Process [PID=111, name=`the-app`]:\n" + + "\n" + + "Bean [id: fooImplementation, type: `hello.FooImplementation`] injected into:\n" + + "\n" + + "- Bean: myController \n" + + " Type: `hello.MyController` \n" + + " Resource: `hello/MyController.class`" + ); + } + + @Test + public void beanWithClasspathResource() throws Exception { + Path of = getOutputFolder(); + LiveBeansModel beans = LiveBeansModel.builder() + .add(LiveBean.builder() + .id("fooImplementation") + .type("hello.FooImplementation") + .fileResource("should/not/matter") + .build() + ) + .add(LiveBean.builder() + .id("myController") + .type("hello.MyController") + .classpathResource("hello/MyController.class") + .dependencies("fooImplementation") + .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() {\n" + + " return new FooImplementation();\n" + + " }\n" + + "}" + ); + editor.assertHighlights("@Bean"); + editor.assertTrimmedHover("@Bean", + "**Injection report for Bean [id: fooImplementation]**\n" + + "\n" + + "Process [PID=111, name=`the-app`]:\n" + + "\n" + + "Bean [id: fooImplementation, type: `hello.FooImplementation`] injected into:\n" + + "\n" + + "- Bean: myController \n" + + " Type: `hello.MyController` \n" + + " Resource: `hello/MyController.class`" + ); + } + + private Path getOutputFolder() { + return harness.getProjectFinder().find(null).get().getClasspath().getOutputFolder(); + } + @Test public void beanWithMultipleInjections() throws Exception { LiveBeansModel beans = LiveBeansModel.builder() @@ -269,8 +387,10 @@ public class BeanInjectedIntoHoverProviderTest { "\n" + "Bean [id: fooImplementation, type: `hello.FooImplementation`] injected into:\n" + "\n" + - "- Bean [id: myController, type: `hello.MyController`]\n" + - "- Bean [id: otherBean, type: `hello.OtherBean`]\n" + "- Bean: myController \n" + + " Type: `hello.MyController`\n" + + "- Bean: otherBean \n" + + " Type: `hello.OtherBean`\n" ); } diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/ComponentInjectionsHoverProviderTest.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/ComponentInjectionsHoverProviderTest.java index 76047d3d4..cd80f9dc0 100644 --- a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/ComponentInjectionsHoverProviderTest.java +++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/livehover/test/ComponentInjectionsHoverProviderTest.java @@ -164,7 +164,8 @@ public class ComponentInjectionsHoverProviderTest { "\n" + "Bean [id: fooImplementation, type: `com.example.FooImplementation`] injected into:\n" + "\n" + - "- Bean [id: myController, type: `com.example.MyController`]\n" + "- Bean: myController \n" + + " Type: `com.example.MyController`" ); } @@ -218,8 +219,10 @@ public class ComponentInjectionsHoverProviderTest { "\n" + "Bean [id: fooImplementation, type: `com.example.FooImplementation`] injected into:\n" + "\n" + - "- Bean [id: myController, type: `com.example.MyController`]\n" + - "- Bean [id: otherBean, type: `com.example.OtherBean`]\n" + "- Bean: myController \n" + + " Type: `com.example.MyController`\n" + + "- Bean: otherBean \n" + + " Type: `com.example.OtherBean`" ); } @@ -275,15 +278,19 @@ public class ComponentInjectionsHoverProviderTest { "\n" + "Bean [id: fooImplementation, type: `com.example.FooImplementation`] injected into:\n" + "\n" + - "- Bean [id: myController, type: `com.example.MyController`]\n" + - "- Bean [id: otherBean, type: `com.example.OtherBean`]\n" + + "- Bean: myController \n" + + " Type: `com.example.MyController`\n" + + "- Bean: otherBean \n" + + " Type: `com.example.OtherBean`\n" + "\n" + "Process [PID=1002, name=`app-instance-2`]:\n" + "\n" + "Bean [id: fooImplementation, type: `com.example.FooImplementation`] injected into:\n" + "\n" + - "- Bean [id: myController, type: `com.example.MyController`]\n" + - "- Bean [id: otherBean, type: `com.example.OtherBean`]\n" + "- Bean: myController \n" + + " Type: `com.example.MyController`\n" + + "- Bean: otherBean \n" + + " Type: `com.example.OtherBean`\n" ); } @@ -342,7 +349,8 @@ public class ComponentInjectionsHoverProviderTest { "\n" + "Bean [id: fooImplementation, type: `com.example.FooImplementation`] injected into:\n" + "\n" + - "- Bean [id: myController, type: `com.example.MyController`]" + "- Bean: myController \n" + + " Type: `com.example.MyController`" ); } @@ -401,7 +409,8 @@ public class ComponentInjectionsHoverProviderTest { "\n" + "Bean [id: alternateFooImplementation, type: `com.example.FooImplementation`] injected into:\n" + "\n" + - "- Bean [id: otherBean, type: `com.example.OtherBean`]\n" + "- Bean: otherBean \n" + + " Type: `com.example.OtherBean`\n" ); } diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/livebean/LiveBean.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/livebean/LiveBean.java index 58e35b18c..9600b3778 100644 --- a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/livebean/LiveBean.java +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/livebean/LiveBean.java @@ -51,6 +51,20 @@ public class LiveBean { this.dependencies = deps; return this; } + + private Builder resource(String resource) { + this.resource = resource; + return this; + } + + public Builder fileResource(String path) { + return resource("file ["+path+"]"); + } + + public Builder classpathResource(String path) { + return resource("class path resource ["+path+"]"); + } + } protected LiveBean(String id, String[] aliases, String scope, String type, String resource, String[] dependencies) { diff --git a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/StringUtil.java b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/StringUtil.java index 6761a65ba..343a2c9ca 100644 --- a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/StringUtil.java +++ b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/StringUtil.java @@ -17,6 +17,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -208,4 +209,12 @@ public class StringUtil { pieces.add(string.substring(start)); return pieces.toArray(new String[pieces.size()]); } + + public static Optional findFirst(String searchIn, Pattern pattern) { + Matcher matcher = pattern.matcher(searchIn); + if (matcher.find()) { + return Optional.of(searchIn.substring(matcher.start(), matcher.end())); + } + return Optional.empty(); + } }