PT #159444911: Support for @Autowired + @Qualifier
This commit is contained in:
@@ -26,6 +26,8 @@ public class Annotations {
|
||||
public static final String AUTOWIRED = "org.springframework.beans.factory.annotation.Autowired";
|
||||
public static final String INJECT = "javax.inject.Inject";
|
||||
|
||||
public static final String QUALIFIER = "org.springframework.beans.factory.annotation.Qualifier";
|
||||
|
||||
public static final String SPRING_REQUEST_MAPPING = "org.springframework.web.bind.annotation.RequestMapping";
|
||||
public static final String SPRING_GET_MAPPING = "org.springframework.web.bind.annotation.GetMapping";
|
||||
public static final String SPRING_POST_MAPPING = "org.springframework.web.bind.annotation.PostMapping";
|
||||
|
||||
@@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.java.autowired;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
@@ -198,20 +199,34 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
return ((List<Object>)methodDeclaration.parameters()).stream()
|
||||
.filter(p -> p instanceof SingleVariableDeclaration)
|
||||
.map(p -> (SingleVariableDeclaration)p)
|
||||
.map(singleVariableDeclaration -> matchBeanByType(project, beans, singleVariableDeclaration.getType().resolveBinding()))
|
||||
.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)
|
||||
.collect(Collectors.toList());
|
||||
} else if (declarationNode instanceof FieldDeclaration) {
|
||||
FieldDeclaration fieldDeclaration = (FieldDeclaration)declarationNode;
|
||||
LiveBean matchedBean = matchBeanByType(project, beans, fieldDeclaration.getType().resolveBinding());
|
||||
if (matchedBean != null) {
|
||||
return ImmutableList.of(matchedBean);
|
||||
Optional<String> beanId = ASTUtils.beanId(fieldDeclaration.modifiers());
|
||||
if (beanId.isPresent()) {
|
||||
return beans.stream().filter(b -> beanId.get().equals(b.getId())).findFirst().map(b -> ImmutableList.of(b)).orElseGet(() -> ImmutableList.of());
|
||||
} else {
|
||||
LiveBean matchedBean = matchBeanByType(project, beans, fieldDeclaration.getType().resolveBinding());
|
||||
if (matchedBean != null) {
|
||||
return ImmutableList.of(matchedBean);
|
||||
}
|
||||
}
|
||||
} else if (declarationNode instanceof SingleVariableDeclaration) {
|
||||
SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration)declarationNode;
|
||||
LiveBean matchedBean = matchBeanByType(project, beans, singleVariableDeclaration.getType().resolveBinding());
|
||||
if (matchedBean != null) {
|
||||
return ImmutableList.of(matchedBean);
|
||||
Optional<String> beanId = ASTUtils.beanId(singleVariableDeclaration.modifiers());
|
||||
if (beanId.isPresent()) {
|
||||
return beans.stream().filter(b -> beanId.get().equals(b.getId())).findFirst().map(b -> ImmutableList.of(b)).orElseGet(() -> ImmutableList.of());
|
||||
} else {
|
||||
LiveBean matchedBean = matchBeanByType(project, beans, singleVariableDeclaration.getType().resolveBinding());
|
||||
if (matchedBean != null) {
|
||||
return ImmutableList.of(matchedBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
|
||||
@@ -30,8 +30,10 @@ import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.commons.util.CollectorUtil;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
@@ -39,6 +41,8 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class ASTUtils {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ASTUtils.class);
|
||||
|
||||
public static DocumentRegion nameRegion(TextDocument doc, Annotation annotation) {
|
||||
int start = annotation.getTypeName().getStartPosition();
|
||||
int end = start + annotation.getTypeName().getLength();
|
||||
@@ -52,7 +56,7 @@ public class ASTUtils {
|
||||
try {
|
||||
return Optional.of(nameRegion(doc, annotation).asRange());
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
log.error("", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@@ -96,7 +100,7 @@ public class ASTUtils {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
log.error("", e);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
@@ -239,6 +243,23 @@ public class ASTUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static Optional<String> beanId(List<Object> modifiers) {
|
||||
return modifiers.stream()
|
||||
.filter(m -> m instanceof SingleMemberAnnotation)
|
||||
.map(m -> (SingleMemberAnnotation) m)
|
||||
.filter(m -> {
|
||||
ITypeBinding typeBinding = m.resolveTypeBinding();
|
||||
if (typeBinding != null) {
|
||||
return Annotations.QUALIFIER.equals(typeBinding.getQualifiedName());
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.findFirst()
|
||||
.map(a -> a.getValue())
|
||||
.filter(e -> e != null)
|
||||
.map(e -> e.resolveConstantExpressionValue())
|
||||
.filter(o -> o instanceof String)
|
||||
.map(o -> (String) o);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -667,6 +667,163 @@ public class AutowiredHoverProviderTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qualifierParameterWiredBean() 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.Qualifier;\n" +
|
||||
"import org.springframework.stereotype.Component;\n" +
|
||||
"\n" +
|
||||
"@Component\n" +
|
||||
"public class SomeComponent {\n" +
|
||||
"\n" +
|
||||
" private IDependency a;\n" +
|
||||
" private IDependency b;\n" +
|
||||
"\n" +
|
||||
" public SomeComponent(@Qualifier(\"dependencyA\") IDependency a, @Qualifier(\"dependencyB\") IDependency b) {\n" +
|
||||
" this.a = a;\n" +
|
||||
" this.b = b;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
editor.assertHighlights("@Component", "SomeComponent");
|
||||
editor.assertTrimmedHover("SomeComponent", 2,
|
||||
"**Autowired `someComponent` ← `dependencyA` `dependencyB`**\n" +
|
||||
"- Bean: `dependencyA` \n" +
|
||||
" Type: `com.example.DependencyA`\n" +
|
||||
"- Bean: `dependencyB` \n" +
|
||||
" Type: `com.example.DependencyB`\n" +
|
||||
" \n" +
|
||||
"Process [PID=111, name=`the-app`]\n"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qualifierFieldWiredBean() 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()
|
||||
)
|
||||
.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.beans.factory.annotation.Qualifier;\n" +
|
||||
"import org.springframework.stereotype.Component;\n" +
|
||||
"\n" +
|
||||
"@Component\n" +
|
||||
"public class SomeComponent {\n" +
|
||||
"\n" +
|
||||
" @Autowired\n" +
|
||||
" @Qualifier(\"dependencyA\")\n" +
|
||||
" private IDependency a;\n" +
|
||||
"\n" +
|
||||
" public SomeComponent() {\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
editor.assertHighlights("@Component", "@Autowired");
|
||||
editor.assertTrimmedHover("@Autowired", 1,
|
||||
"**Autowired `someComponent` ← `dependencyA`**\n" +
|
||||
"- Bean: `dependencyA` \n" +
|
||||
" Type: `com.example.DependencyA`\n" +
|
||||
" \n" +
|
||||
"Process [PID=111, name=`the-app`]\n"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qualifierNotFoundWiredBean() 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()
|
||||
)
|
||||
.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.beans.factory.annotation.Qualifier;\n" +
|
||||
"import org.springframework.stereotype.Component;\n" +
|
||||
"\n" +
|
||||
"@Component\n" +
|
||||
"public class SomeComponent {\n" +
|
||||
"\n" +
|
||||
" @Autowired\n" +
|
||||
" @Qualifier(\"X\")\n" +
|
||||
" private IDependency a;\n" +
|
||||
"\n" +
|
||||
" public SomeComponent() {\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
editor.assertHighlights("@Component");
|
||||
editor.assertNoHover("@Autowired");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void anonymousInnerClassBeanWiring() throws Exception {
|
||||
LiveBeansModel beans = LiveBeansModel.builder()
|
||||
|
||||
Reference in New Issue
Block a user