PT #159866173: Add autowired beans for @Bean hover and codelens
This commit is contained in:
@@ -172,7 +172,10 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
|
||||
public static List<LiveBean> getRelevantAutowiredBeans(IJavaProject project, ASTNode declarationNode, SpringBootApp app, LiveBean definedBean) {
|
||||
List<LiveBean> relevantBeans = LiveHoverUtils.findRelevantBeans(app, definedBean);
|
||||
return getRelevantAutowiredBeans(project, declarationNode, app, relevantBeans);
|
||||
}
|
||||
|
||||
public static List<LiveBean> getRelevantAutowiredBeans(IJavaProject project, ASTNode declarationNode, SpringBootApp app, List<LiveBean> relevantBeans) {
|
||||
if (!relevantBeans.isEmpty()) {
|
||||
List<LiveBean> allDependencyBeans = LiveHoverUtils.findAllDependencyBeans(app, relevantBeans);
|
||||
|
||||
@@ -199,12 +202,7 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
return ((List<Object>)methodDeclaration.parameters()).stream()
|
||||
.filter(p -> p instanceof SingleVariableDeclaration)
|
||||
.map(p -> (SingleVariableDeclaration)p)
|
||||
.map(singleVariableDeclaration -> {
|
||||
// Supposed to be a list of one bean for the variable declaration
|
||||
List<LiveBean> matches = findAutowiredBeans(project, singleVariableDeclaration, beans);
|
||||
return matches.isEmpty() ? null : matches.get(0);
|
||||
})
|
||||
.filter(matchedBean -> matchedBean != null)
|
||||
.flatMap(singleVariableDeclaration -> findAutowiredBeans(project, singleVariableDeclaration, beans).stream())
|
||||
.collect(Collectors.toList());
|
||||
} else if (declarationNode instanceof FieldDeclaration) {
|
||||
FieldDeclaration fieldDeclaration = (FieldDeclaration)declarationNode;
|
||||
|
||||
@@ -64,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(), ASTUtils.getAnnotatedType(annotation) != null);
|
||||
List<CodeLens> codeLenses = assembleCodeLenses(project, runningApps, definedBean, nameRange.get(), annotation);
|
||||
return codeLenses.isEmpty() ? ImmutableList.of(new CodeLens(nameRange.get())) : codeLenses;
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
|
||||
LiveBean definedBean = getDefinedBean(annotation);
|
||||
if (definedBean != null) {
|
||||
Hover hover = assembleHover(project, runningApps, definedBean, ASTUtils.getAnnotatedType(annotation) != null);
|
||||
Hover hover = assembleHover(project, runningApps, definedBean, annotation);
|
||||
if (hover != null) {
|
||||
Optional<Range> nameRange = ASTUtils.nameRange(doc, annotation);
|
||||
if (nameRange.isPresent()) {
|
||||
@@ -96,7 +96,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
protected List<CodeLens> assembleCodeLenses(IJavaProject project, SpringBootApp[] runningApps, LiveBean definedBean, Range range, boolean includeWiredBeans) {
|
||||
protected List<CodeLens> assembleCodeLenses(IJavaProject project, SpringBootApp[] runningApps, LiveBean definedBean, Range range, ASTNode astNode) {
|
||||
List<CodeLens> codeLensList = new ArrayList<>();
|
||||
for (SpringBootApp app : runningApps) {
|
||||
|
||||
@@ -108,24 +108,26 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
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, MAX_INLINE_BEANS_STRING_LENGTH, INLINE_BEANS_STRING_SEPARATOR);
|
||||
builder.addAll(injectedCodeLenses == null ? ImmutableList.of(new CodeLens(range)) : injectedCodeLenses);
|
||||
}
|
||||
if (includeWiredBeans) {
|
||||
List<LiveBean> allDependencyBeans = LiveHoverUtils.findAllDependencyBeans(app, relevantBeans);
|
||||
List<CodeLens> wiredCodeLenses = LiveHoverUtils.createCodeLensesForBeans(range, allDependencyBeans,
|
||||
AutowiredHoverProvider.BEANS_PREFIX, MAX_INLINE_BEANS_STRING_LENGTH,
|
||||
INLINE_BEANS_STRING_SEPARATOR);
|
||||
if (wiredCodeLenses != null) {
|
||||
builder.addAll(wiredCodeLenses);
|
||||
}
|
||||
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, MAX_INLINE_BEANS_STRING_LENGTH,
|
||||
INLINE_BEANS_STRING_SEPARATOR));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
return codeLensList;
|
||||
}
|
||||
|
||||
protected Hover assembleHover(IJavaProject project, SpringBootApp[] runningApps, LiveBean definedBean, boolean includeWiredBeans) {
|
||||
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;
|
||||
@@ -170,11 +172,9 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
hover.append("\n \n");
|
||||
}
|
||||
|
||||
if (includeWiredBeans) {
|
||||
List<LiveBean> allDependencyBeans = LiveHoverUtils.findAllDependencyBeans(app, relevantBeans);
|
||||
if (!allDependencyBeans.isEmpty()) {
|
||||
AutowiredHoverProvider.createHoverContentForBeans(server, definedBean, project, hover, allDependencyBeans);
|
||||
}
|
||||
List<LiveBean> wiredBeans = findWiredBeans(project, app, relevantBeans, astNode);
|
||||
if (!wiredBeans.isEmpty()) {
|
||||
AutowiredHoverProvider.createHoverContentForBeans(server, definedBean, project, hover, wiredBeans);
|
||||
}
|
||||
|
||||
hover.append(LiveHoverUtils.niceAppName(app));
|
||||
|
||||
@@ -10,13 +10,19 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider;
|
||||
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.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.Optionals;
|
||||
|
||||
public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProvider {
|
||||
@@ -66,4 +72,15 @@ public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProv
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<LiveBean> findWiredBeans(IJavaProject project, SpringBootApp app, List<LiveBean> relevantBeans, ASTNode astNode) {
|
||||
if (astNode instanceof Annotation) {
|
||||
MethodDeclaration beanMethod = ASTUtils.getAnnotatedMethod((Annotation) astNode);
|
||||
if (beanMethod != null) {
|
||||
return AutowiredHoverProvider.getRelevantAutowiredBeans(project, beanMethod, app, relevantBeans);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
package org.springframework.ide.vscode.boot.java.livehover;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -110,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(), true);
|
||||
List<CodeLens> codeLenses = assembleCodeLenses(project, runningApps, definedBean, nameRange.get(), typeDeclaration);
|
||||
return codeLenses.isEmpty() ? ImmutableList.of(new CodeLens(nameRange.get())) : codeLenses;
|
||||
}
|
||||
}
|
||||
@@ -130,7 +131,7 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
|
||||
LiveBean definedBean = getDefinedBeanForType(typeDeclaration, null);
|
||||
if (definedBean != null) {
|
||||
Hover hover = assembleHover(project, runningApps, definedBean, true);
|
||||
Hover hover = assembleHover(project, runningApps, definedBean, typeDeclaration);
|
||||
if (hover != null) {
|
||||
SimpleName name = typeDeclaration.getName();
|
||||
try {
|
||||
@@ -145,6 +146,20 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected List<LiveBean> findWiredBeans(IJavaProject project, SpringBootApp app, List<LiveBean> relevantBeans,
|
||||
ASTNode astNode) {
|
||||
TypeDeclaration typeDeclaration = null;
|
||||
if (astNode instanceof TypeDeclaration) {
|
||||
typeDeclaration = (TypeDeclaration) astNode;
|
||||
} else if (astNode instanceof Annotation) {
|
||||
typeDeclaration = ASTUtils.getAnnotatedType((Annotation) astNode);
|
||||
}
|
||||
return typeDeclaration == null ? Collections.emptyList() : LiveHoverUtils.findAllDependencyBeans(app, relevantBeans);
|
||||
}
|
||||
|
||||
private boolean isComponentAnnotatedType(TypeDeclaration typeDeclaration) {
|
||||
List<?> modifiers = typeDeclaration.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
|
||||
@@ -39,6 +39,28 @@ public class BeanInjectedIntoHoverProviderTest {
|
||||
" void doSomeFoo();\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
p.createType("hello.IDependency",
|
||||
"package hello;\n" +
|
||||
"\n" +
|
||||
"public interface IDependency {\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
p.createType("hello.DependencyA",
|
||||
"package hello;\n" +
|
||||
"\n" +
|
||||
"public class DependencyA implements IDependency {\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
p.createType("hello.DependencyB",
|
||||
"package hello;\n" +
|
||||
"\n" +
|
||||
"public class DependencyB implements IDependency {\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
private BootJavaLanguageServerHarness harness;
|
||||
@@ -484,4 +506,214 @@ public class BeanInjectedIntoHoverProviderTest {
|
||||
editor.assertHighlights(/*NONE*/);
|
||||
editor.assertNoHover("@Bean");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanWithOneWiring() throws Exception {
|
||||
LiveBeansModel beans = LiveBeansModel.builder()
|
||||
.add(LiveBean.builder()
|
||||
.id("fooImplementation")
|
||||
.type("hello.FooImplementation")
|
||||
.dependencies("depA")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("depA")
|
||||
.type("hello.DependencyA")
|
||||
.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(DependencyA a) {\n" +
|
||||
" return new FooImplementation();\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
);
|
||||
editor.assertHighlights("@Bean");
|
||||
editor.assertTrimmedHover("@Bean",
|
||||
"**Injected `fooImplementation` → _not injected anywhere_** \n" +
|
||||
"**Autowired `fooImplementation` ← `depA`**\n" +
|
||||
"- Bean: `depA` \n" +
|
||||
" Type: `hello.DependencyA`\n" +
|
||||
" \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanWithMultipleWirings() throws Exception {
|
||||
LiveBeansModel beans = LiveBeansModel.builder()
|
||||
.add(LiveBean.builder()
|
||||
.id("fooImplementation")
|
||||
.type("hello.FooImplementation")
|
||||
.dependencies("depA", "depB")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("depA")
|
||||
.type("hello.DependencyA")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("depB")
|
||||
.type("hello.DependencyB")
|
||||
.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(DependencyA a, DependencyB b) {\n" +
|
||||
" return new FooImplementation();\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
);
|
||||
editor.assertHighlights("@Bean");
|
||||
editor.assertTrimmedHover("@Bean",
|
||||
"**Injected `fooImplementation` → _not injected anywhere_** \n" +
|
||||
"**Autowired `fooImplementation` ← `depA` `depB`**\n" +
|
||||
"- Bean: `depA` \n" +
|
||||
" Type: `hello.DependencyA`\n" +
|
||||
"- Bean: `depB` \n" +
|
||||
" Type: `hello.DependencyB`\n" +
|
||||
" \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanWithCollectionWiring() throws Exception {
|
||||
LiveBeansModel beans = LiveBeansModel.builder()
|
||||
.add(LiveBean.builder()
|
||||
.id("fooImplementation")
|
||||
.type("hello.FooImplementation")
|
||||
.dependencies("depA", "depB")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("depA")
|
||||
.type("hello.DependencyA")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("depB")
|
||||
.type("hello.DependencyB")
|
||||
.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(IDependency[] deps) {\n" +
|
||||
" return new FooImplementation();\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
);
|
||||
editor.assertHighlights("@Bean");
|
||||
editor.assertTrimmedHover("@Bean",
|
||||
"**Injected `fooImplementation` → _not injected anywhere_** \n" +
|
||||
"**Autowired `fooImplementation` ← `depA` `depB`**\n" +
|
||||
"- Bean: `depA` \n" +
|
||||
" Type: `hello.DependencyA`\n" +
|
||||
"- Bean: `depB` \n" +
|
||||
" Type: `hello.DependencyB`\n" +
|
||||
" \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanWithQualifierWiring() throws Exception {
|
||||
LiveBeansModel beans = LiveBeansModel.builder()
|
||||
.add(LiveBean.builder()
|
||||
.id("fooImplementation")
|
||||
.type("hello.FooImplementation")
|
||||
.dependencies("depA", "depB")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("depB")
|
||||
.type("hello.DependencyB")
|
||||
.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(@Qualifier(\"depB\") IDependency[] deps) {\n" +
|
||||
" return new FooImplementation();\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
);
|
||||
editor.assertHighlights("@Bean");
|
||||
editor.assertTrimmedHover("@Bean",
|
||||
"**Injected `fooImplementation` → _not injected anywhere_** \n" +
|
||||
"**Autowired `fooImplementation` ← `depB`**\n" +
|
||||
"- Bean: `depB` \n" +
|
||||
" Type: `hello.DependencyB`\n" +
|
||||
" \n" +
|
||||
"Process [PID=111, name=`the-app`]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user