PT #159465021: Unmatched bean for boot hints
This commit is contained in:
@@ -47,6 +47,8 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
* @author Alex Boyko
|
||||
@@ -196,42 +198,53 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
return ((List<Object>)methodDeclaration.parameters()).stream()
|
||||
.filter(p -> p instanceof SingleVariableDeclaration)
|
||||
.map(p -> (SingleVariableDeclaration)p)
|
||||
.flatMap(p -> findAutowiredBeans(project, p, beans).stream())
|
||||
.map(singleVariableDeclaration -> matchBeanByType(project, beans, singleVariableDeclaration.getType().resolveBinding()))
|
||||
.filter(matchedBean -> matchedBean != null)
|
||||
.collect(Collectors.toList());
|
||||
} else if (declarationNode instanceof FieldDeclaration) {
|
||||
FieldDeclaration fieldDeclaration = (FieldDeclaration)declarationNode;
|
||||
return matchBeans(project, beans, fieldDeclaration.getType().resolveBinding());
|
||||
LiveBean matchedBean = matchBeanByType(project, beans, fieldDeclaration.getType().resolveBinding());
|
||||
if (matchedBean != null) {
|
||||
return ImmutableList.of(matchedBean);
|
||||
}
|
||||
} else if (declarationNode instanceof SingleVariableDeclaration) {
|
||||
SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration)declarationNode;
|
||||
return matchBeans(project, beans, singleVariableDeclaration.getType().resolveBinding());
|
||||
LiveBean matchedBean = matchBeanByType(project, beans, singleVariableDeclaration.getType().resolveBinding());
|
||||
if (matchedBean != null) {
|
||||
return ImmutableList.of(matchedBean);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static List<LiveBean> matchBeans(IJavaProject project, Collection<LiveBean> beans, ITypeBinding type) {
|
||||
List<LiveBean> relevant = Collections.emptyList();
|
||||
private static LiveBean matchBeanByType(IJavaProject project, Collection<LiveBean> beans, ITypeBinding type) {
|
||||
if (type != null) {
|
||||
String fqName = type.getQualifiedName();
|
||||
if (fqName != null) {
|
||||
relevant = matchBeans(project, beans, fqName, true);
|
||||
if (relevant.isEmpty()) {
|
||||
List<LiveBean> matches = matchBeansByFQName(project, beans, fqName, true);
|
||||
if (!matches.isEmpty()) {
|
||||
return matches.size() == 1 ? matches.get(0) : LiveHoverUtils.CANT_MATCH_PROPER_BEAN;
|
||||
} else {
|
||||
IType indexType = project.findType(fqName);
|
||||
if (indexType != null) {
|
||||
relevant = project.allSubtypesOf(indexType)
|
||||
.map(subType -> matchBeans(project, beans, subType.getFullyQualifiedName(), false))
|
||||
matches = project.allSubtypesOf(indexType)
|
||||
.map(subType -> matchBeansByFQName(project, beans, subType.getFullyQualifiedName(), false))
|
||||
.filter(relevantBeans -> !relevantBeans.isEmpty())
|
||||
.flatMap(bs -> Flux.fromIterable(bs))
|
||||
.buffer(2)
|
||||
.blockFirst();
|
||||
if (relevant == null) {
|
||||
relevant = Collections.emptyList();
|
||||
|
||||
if (!matches.isEmpty()) {
|
||||
return matches.size() == 1 ? matches.get(0) : LiveHoverUtils.CANT_MATCH_PROPER_BEAN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return relevant;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<LiveBean> matchBeans(IJavaProject project, Collection<LiveBean> beans, String fqName, boolean allDots) {
|
||||
private static List<LiveBean> matchBeansByFQName(IJavaProject project, Collection<LiveBean> beans, String fqName, boolean allDots) {
|
||||
if (fqName != null) {
|
||||
if (allDots) {
|
||||
return beans.stream().filter(b -> fqName.equals(b.getType(true).replace('$', '.'))).collect(Collectors.toList());
|
||||
|
||||
@@ -35,6 +35,8 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class LiveHoverUtils {
|
||||
|
||||
public static final LiveBean CANT_MATCH_PROPER_BEAN = LiveBean.builder().id("UNKNOWN").build();
|
||||
|
||||
public static String showBean(LiveBean bean) {
|
||||
StringBuilder buf = new StringBuilder("Bean [id: " + bean.getId());
|
||||
String type = bean.getType(true);
|
||||
@@ -48,55 +50,68 @@ public class LiveHoverUtils {
|
||||
public static String showBeanWithResource(BootJavaLanguageServerComponents server, 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
|
||||
|
||||
String type = bean.getType(true);
|
||||
if (bean == CANT_MATCH_PROPER_BEAN) {
|
||||
return "(Cannot find precise information for the bean)";
|
||||
} else {
|
||||
String type = bean.getType(true);
|
||||
|
||||
StringBuilder buf = new StringBuilder("Bean: ");
|
||||
buf.append('`');
|
||||
buf.append(bean.getId());
|
||||
buf.append('`');
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(server);
|
||||
if (type != null) {
|
||||
// Try creating a URL link to open source for the type
|
||||
buf.append(newline);
|
||||
buf.append("Type: ");
|
||||
Optional<String> url = sourceLinks.sourceLinkUrlForFQName(project, type);
|
||||
if (url.isPresent()) {
|
||||
buf.append(Renderables.link(type, url.get()).toMarkdown());
|
||||
} else {
|
||||
buf.append("`" + type + "`");
|
||||
StringBuilder buf = new StringBuilder("Bean: ");
|
||||
buf.append('`');
|
||||
buf.append(bean.getId());
|
||||
buf.append('`');
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(server);
|
||||
if (type != null) {
|
||||
// Try creating a URL link to open source for the type
|
||||
buf.append(newline);
|
||||
buf.append("Type: ");
|
||||
Optional<String> url = sourceLinks.sourceLinkUrlForFQName(project, type);
|
||||
if (url.isPresent()) {
|
||||
buf.append(Renderables.link(type, url.get()).toMarkdown());
|
||||
} else {
|
||||
buf.append("`" + type + "`");
|
||||
}
|
||||
}
|
||||
String resource = bean.getResource();
|
||||
if (StringUtil.hasText(resource)) {
|
||||
buf.append(newline);
|
||||
buf.append("Resource: ");
|
||||
buf.append(showResource(sourceLinks, resource, project));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
String resource = bean.getResource();
|
||||
if (StringUtil.hasText(resource)) {
|
||||
buf.append(newline);
|
||||
buf.append("Resource: ");
|
||||
buf.append(showResource(sourceLinks, resource, project));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String getShortDisplayType(LiveBean bean) {
|
||||
String type = bean.getType(true);
|
||||
int idx = type.lastIndexOf('.');
|
||||
return idx < 0 || idx == type.length() - 1 ? type : type.substring(idx + 1);
|
||||
if (bean == CANT_MATCH_PROPER_BEAN) {
|
||||
return CANT_MATCH_PROPER_BEAN.getId();
|
||||
} else {
|
||||
String type = bean.getType(true);
|
||||
int idx = type.lastIndexOf('.');
|
||||
String typeStr = idx < 0 || idx == type.length() - 1 ? type : type.substring(idx + 1);
|
||||
return typeStr;
|
||||
}
|
||||
}
|
||||
|
||||
public static String showBeanInline(BootJavaLanguageServerComponents server, IJavaProject project, LiveBean bean) {
|
||||
String id = bean.getId();
|
||||
String type = bean.getType(true);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('`');
|
||||
sb.append(id);
|
||||
sb.append('`');
|
||||
String displayId = sb.toString();
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(server);
|
||||
if (type != null) {
|
||||
Optional<String> url = sourceLinks.sourceLinkUrlForFQName(project, type);
|
||||
if (url.isPresent()) {
|
||||
return Renderables.link(displayId, url.get()).toMarkdown();
|
||||
if (bean == CANT_MATCH_PROPER_BEAN) {
|
||||
return CANT_MATCH_PROPER_BEAN.getId();
|
||||
} else {
|
||||
String id = bean.getId();
|
||||
String type = bean.getType(true);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('`');
|
||||
sb.append(id);
|
||||
sb.append('`');
|
||||
String displayId = sb.toString();
|
||||
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(server);
|
||||
if (type != null) {
|
||||
Optional<String> url = sourceLinks.sourceLinkUrlForFQName(project, type);
|
||||
if (url.isPresent()) {
|
||||
return Renderables.link(displayId, url.get()).toMarkdown();
|
||||
}
|
||||
}
|
||||
return displayId;
|
||||
}
|
||||
return displayId;
|
||||
}
|
||||
|
||||
public static boolean doBeansFitInline(Collection<LiveBean> beans, int maxLength, String delimiter) {
|
||||
@@ -214,4 +229,5 @@ public class LiveHoverUtils {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,17 +72,24 @@ public class AutowiredHoverProviderTest {
|
||||
"}\n"
|
||||
);
|
||||
|
||||
p.createType("com.examle.IDependency",
|
||||
"package com.example;\n" +
|
||||
"\n" +
|
||||
"public interface IDependency {\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
p.createType("com.examle.DependencyA",
|
||||
"package com.example;\n" +
|
||||
"\n" +
|
||||
"public class DependencyA {\n" +
|
||||
"public class DependencyA implements IDependency {\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
p.createType("com.examle.DependencyB",
|
||||
"package com.example;\n" +
|
||||
"\n" +
|
||||
"public class DependencyB {\n" +
|
||||
"public class DependencyB implements IDependency {\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
@@ -606,6 +613,60 @@ public class AutowiredHoverProviderTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unableToMatchWiredBean() throws Exception {
|
||||
LiveBeansModel beans = LiveBeansModel.builder()
|
||||
.add(LiveBean.builder()
|
||||
.id("someComponent")
|
||||
.type("com.example.SomeComponent")
|
||||
.dependencies("dependencyA", "dependencyB")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("dependencyA")
|
||||
.type("com.example.DependencyA")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("dependencyB")
|
||||
.type("com.example.DependencyB")
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
mockAppProvider.builder()
|
||||
.isSpringBootApp(true)
|
||||
.processId("111")
|
||||
.processName("the-app")
|
||||
.beans(beans)
|
||||
.build();
|
||||
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA,
|
||||
"package com.example;\n" +
|
||||
"\n" +
|
||||
"import org.springframework.beans.factory.annotation.Autowired;\n" +
|
||||
"import org.springframework.stereotype.Component;\n" +
|
||||
"\n" +
|
||||
"@Component\n" +
|
||||
"public class SomeComponent {\n" +
|
||||
"\n" +
|
||||
" @Autowired\n" +
|
||||
" private IDependency dep;\n" +
|
||||
"\n" +
|
||||
" public SomeComponent() {\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
editor.assertHighlights("@Component", "@Autowired");
|
||||
editor.assertTrimmedHover("@Autowired", 1,
|
||||
"**Autowired `someComponent` ← UNKNOWN**\n" +
|
||||
"- (Cannot find precise information for the bean)\n" +
|
||||
" \n" +
|
||||
"Process [PID=111, name=`the-app`]\n"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void anonymousInnerClassBeanWiring() throws Exception {
|
||||
LiveBeansModel beans = LiveBeansModel.builder()
|
||||
|
||||
Reference in New Issue
Block a user