Improve @Autowired for hover inside of @Component class.

This commit is contained in:
Kris De Volder
2017-11-03 13:45:25 -07:00
parent 546a81c3ce
commit b1d03ed36e
5 changed files with 123 additions and 21 deletions

View File

@@ -22,7 +22,9 @@ import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Hover;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
import org.springframework.ide.vscode.boot.java.livehover.ComponentInjectionsHoverProvider;
import org.springframework.ide.vscode.boot.java.livehover.LiveHoverUtils;
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
@@ -106,7 +108,6 @@ public class AutowiredHoverProvider implements HoverProvider {
}
}
if (hasInterestingApp && hasAutowiring) {
System.out.println(hover);
return CompletableFuture
.completedFuture(new Hover(ImmutableList.of(Either.forLeft(hover.toString()))));
}
@@ -115,25 +116,31 @@ public class AutowiredHoverProvider implements HoverProvider {
return null;
}
private LiveBean getDefinedBean(Annotation annotation) {
TypeDeclaration declaringType = ASTUtils.findDeclaringType(annotation);
private LiveBean getDefinedBean(Annotation autowiredAnnotation) {
TypeDeclaration declaringType = ASTUtils.findDeclaringType(autowiredAnnotation);
if (declaringType != null) {
ITypeBinding beanType = declaringType.resolveBinding();
if (beanType != null) {
String id = getBeanId(declaringType, beanType);
if (StringUtil.hasText(id)) {
return LiveBean.builder().id(id).type(beanType.getQualifiedName()).build();
for (Annotation annotation : ASTUtils.getAnnotations(declaringType)) {
String annotationType = ASTUtils.getAnnotationType(annotation);
switch (annotationType) {
case Annotations.COMPONENT:
return ComponentInjectionsHoverProvider.getDefinedBeanForComponent(annotation);
default:
break;
}
}
}
return null;
}
private String getBeanId(TypeDeclaration declaringType, ITypeBinding beanType) {
// TODO: take specific bean declarations into account like @Component at declaring type
String typeName = beanType.getName();
if (StringUtil.hasText(typeName)) {
return Character.toLowerCase(typeName.charAt(0)) + typeName.substring(1);
//TODO: handler below is an attempt to do something that may work in many cases, but is probably
// missing logics for special cases where annotation attributes on the declaring type matter.
ITypeBinding beanType = declaringType.resolveBinding();
if (beanType!=null) {
String beanTypeName = beanType.getName();
if (StringUtil.hasText(beanTypeName)) {
return LiveBean.builder()
.id(Character.toLowerCase(beanTypeName.charAt(0)) + beanTypeName.substring(1))
.type(beanTypeName)
.build();
}
}
return null;
}
return null;
}

View File

@@ -87,7 +87,6 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
}
}
if (hasInterestingApp) {
System.out.println(hover);
return CompletableFuture
.completedFuture(new Hover(ImmutableList.of(Either.forLeft(hover.toString()))));
}

View File

@@ -68,6 +68,11 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
@Override
protected LiveBean getDefinedBean(Annotation annotation) {
return getDefinedBeanForComponent(annotation);
}
public static LiveBean getDefinedBeanForComponent(Annotation annotation) {
//Move to ASTUtils?
TypeDeclaration declaringType = ASTUtils.getAnnotatedType(annotation);
if (declaringType != null) {
ITypeBinding beanType = declaringType.resolveBinding();
@@ -81,7 +86,7 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
return null;
}
private String getBeanId(Annotation annotation, ITypeBinding beanType) {
private static String getBeanId(Annotation annotation, ITypeBinding beanType) {
return ASTUtils.getAttribute(annotation, "value").flatMap(ASTUtils::getFirstString)
.orElseGet(() -> {
String typeName = beanType.getName();

View File

@@ -11,14 +11,17 @@
package org.springframework.ide.vscode.boot.java.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.NormalAnnotation;
@@ -32,6 +35,8 @@ import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import com.google.common.collect.ImmutableList;
public class ASTUtils {
public static DocumentRegion nameRegion(TextDocument doc, Annotation annotation) {
@@ -161,8 +166,7 @@ public class ASTUtils {
}
@SuppressWarnings("unchecked")
public
static String[] getExpressionValueAsArray(Expression exp) {
public static String[] getExpressionValueAsArray(Expression exp) {
if (exp instanceof ArrayInitializer) {
ArrayInitializer array = (ArrayInitializer) exp;
return ((List<Expression>) array.expressions()).stream().map(e -> getExpressionValueAsString(e))
@@ -176,4 +180,28 @@ public class ASTUtils {
return null;
}
public static Collection<Annotation> getAnnotations(TypeDeclaration declaringType) {
Object modifiersObj = declaringType.getStructuralProperty(TypeDeclaration.MODIFIERS2_PROPERTY);
if (modifiersObj instanceof List) {
ImmutableList.Builder<Annotation> annotations = ImmutableList.builder();
for (Object node : (List<?>)modifiersObj) {
if (node instanceof Annotation) {
annotations.add((Annotation) node);
}
}
return annotations.build();
}
return ImmutableList.of();
}
public static String getAnnotationType(Annotation annotation) {
ITypeBinding binding = annotation.resolveTypeBinding();
if (binding!=null) {
return binding.getQualifiedName();
}
return null;
}
}

View File

@@ -241,4 +241,67 @@ public class AutowiredHoverProviderTest {
editor.assertNoHover("@Autowired");
}
@Test public void bug_152553935() throws Exception {
//https://www.pivotaltracker.com/story/show/152553935
LiveBeansModel beans = LiveBeansModel.builder()
.add(LiveBean.builder()
.id("defaultFoo")
.type("com.example.FooImplementation")
.dependencies("defaultFoo")
.dependencies("otherBean")
.build()
)
.add(LiveBean.builder()
.id("otherBean")
.type("com.example.DependencyA")
.build()
)
.build();
mockAppProvider.builder()
.isSpringBootApp(true)
.processId("111")
.processName("the-app")
.beans(beans)
.build();
Editor editor = harness.newEditor(
"package com.example;\n" +
"\n" +
"import org.springframework.beans.factory.annotation.Autowired;\n" +
"import org.springframework.scheduling.TaskScheduler;\n" +
"import org.springframework.stereotype.Component;\n" +
"\n" +
"@Component(\"defaultFoo\")\n" +
"public class FooImplementation implements Foo {\n" +
" \n" +
" private TaskScheduler scheduler;\n" +
" \n" +
" @Autowired Foo self;\n" +
" \n" +
" @Override\n" +
" public void doSomeFoo() {\n" +
" scheduler.scheduleWithFixedDelay(() -> {\n" +
" System.out.println(\"Doo Done done!\");\n" +
" }, 1000);\n" +
" System.out.println(\"Foo do do do do!\");\n" +
" }\n" +
"\n" +
" @Autowired\n" +
" public void setScheduler(TaskScheduler scheduler) {\n" +
" this.scheduler = scheduler;\n" +
" }\n" +
"\n" +
"}"
);
editor.assertHighlights("@Component", "@Autowired", "@Autowired");
for (int i = 1; i <= 2; i++) {
editor.assertHoverContains("@Autowired", 1,
"Bean [id: defaultFoo, type: `com.example.FooImplementation`] got autowired with:\n" +
"\n" +
"- Bean: otherBean \n" +
" Type: `com.example.DependencyA`");
}
}
}