PT #159307292: Autowired reports optics, content specific to AST node

This commit is contained in:
BoykoAlex
2018-07-26 21:19:03 -04:00
parent 5506d2fb2d
commit eb34b0210f
22 changed files with 345 additions and 140 deletions

View File

@@ -1,3 +1,3 @@
{
"jarUrl": "https://s3-us-west-1.amazonaws.com/s3-test.spring.io/sts4/fatjars/snapshots/spring-boot-language-server-0.2.1-201805111942.jar"
"jarUrl": "https://s3-us-west-1.amazonaws.com/s3-test.spring.io/sts4/fatjars/snapshots/spring-boot-language-server-0.4.0-201807190033.jar"
}

View File

@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: Spring Boot Language Server
Bundle-Vendor: Pivotal, Inc.
Bundle-SymbolicName: org.springframework.tooling.boot.ls;singleton:=true
Bundle-Version: 0.3.2.qualifier
Bundle-Version: 0.4.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0",
org.eclipse.core.runtime;bundle-version="3.12.0",

View File

@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: BOSH Manifest Language Server
Bundle-Vendor: Pivotal, Inc.
Bundle-SymbolicName: org.springframework.tooling.bosh.ls;singleton:=true
Bundle-Version: 0.3.2.qualifier
Bundle-Version: 0.4.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0",
org.eclipse.core.runtime;bundle-version="3.12.0",

View File

@@ -16,6 +16,6 @@ package org.springframework.tooling.bosh.ls;
public class Constants {
public static final String PLUGIN_ID = "org.springframework.tooling.bosh.ls";
public static final String LANGUAGE_SERVER_VERSION = "0.3.2-SNAPSHOT";
public static final String LANGUAGE_SERVER_VERSION = "0.4.0-SNAPSHOT";
}

View File

@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: Cloud Foundry Manifest Language Server
Bundle-Vendor: Pivotal, Inc.
Bundle-SymbolicName: org.springframework.tooling.cloudfoundry.manifest.ls;singleton:=true
Bundle-Version: 0.3.2.qualifier
Bundle-Version: 0.4.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.8.0",
org.eclipse.core.runtime;bundle-version="3.12.0",

View File

@@ -16,6 +16,6 @@ package org.springframework.tooling.cloudfoundry.manifest.ls;
public class Constants {
public static final String PLUGIN_ID = "org.springframework.tooling.cloudfoundry.manifest.ls";
public static final String LANGUAGE_SERVER_VERSION = "0.3.2-SNAPSHOT.jar";
public static final String LANGUAGE_SERVER_VERSION = "0.4.0-SNAPSHOT.jar";
}

View File

@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: Concourse Pipeline Language Server
Bundle-Vendor: Pivotal, Inc.
Bundle-SymbolicName: org.springframework.tooling.concourse.ls;singleton:=true
Bundle-Version: 0.3.2.qualifier
Bundle-Version: 0.4.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0",
org.eclipse.core.runtime;bundle-version="3.12.0",

View File

@@ -16,6 +16,6 @@ package org.springframework.tooling.concourse.ls;
public class Constants {
public static final String PLUGIN_ID = "org.springframework.tooling.concourse.ls";
public static final String LANGUAGE_SERVER_VERSION = "0.3.2-SNAPSHOT";
public static final String LANGUAGE_SERVER_VERSION = "0.4.0-SNAPSHOT";
}

View File

@@ -81,7 +81,9 @@ public class LocalSpringBootApp extends AbstractSpringBootApp {
@Override
public String getProcessName() {
return vmd.displayName();
String rawName = vmd.displayName();
int firstSpace = rawName.indexOf(' ');
return firstSpace < 0 ? rawName : rawName.substring(0, firstSpace);
}
@Override

View File

@@ -16,8 +16,12 @@ import java.net.URL;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -174,4 +178,40 @@ public final class JandexClasspath implements ClasspathIndex {
.collect(CollectorUtil.toImmutableList());
}
private static void updateQueue(Queue<String> queue, Set<String> exclusion, IType type) {
for (String t : type.getSuperInterfaceNames()) {
if (!exclusion.contains(t)) {
queue.add(t);
exclusion.add(t);
}
}
String superClass = type.getSuperclassName();
if (superClass != null && !exclusion.contains(superClass)) {
queue.add(superClass);
exclusion.add(superClass);
}
}
@Override
public Flux<IType> allSuperTypesOf(IType type) {
Queue<String> queue = new LinkedList<>();
HashSet<String> visited = new HashSet<>();
updateQueue(queue, visited, type);
return Flux.generate(() -> queue, (state, sink) -> {
IType nextType = null;
while (nextType == null && state.peek() != null) {
String typeName = state.poll();
nextType = findType(typeName);
if (nextType != null) {
sink.next(nextType);
updateQueue(state, visited, nextType);
}
}
if (state.peek() == null) {
sink.complete();
}
return state;
});
}
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016-2017 Pivotal, Inc.
* Copyright (c) 2016, 2018 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
@@ -163,4 +163,15 @@ class TypeImpl implements IType {
return info.toString();
}
@Override
public String getSuperclassName() {
DotName name = info.superName();
return name == null ? null : name.toString();
}
@Override
public String[] getSuperInterfaceNames() {
return info.interfaceNames().stream().map(DotName::toString).toArray(String[]::new);
}
}

View File

@@ -27,6 +27,7 @@ public interface ClasspathIndex extends Disposable {
Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, Predicate<IType> typeFilter);
Flux<Tuple2<String, Double>> fuzzySearchPackages(String searchTerm);
Flux<IType> allSubtypesOf(IType type);
Flux<IType> allSuperTypesOf(IType type);
Optional<File> findClasspathResourceContainer(String fqName);
//Maybe the stuff below is another interface? Something that provides operations

View File

@@ -41,6 +41,10 @@ public interface IJavaProject {
return getIndex().allSubtypesOf(targetType);
}
default Flux<IType> allSuperTypesOf(IType targetType) {
return getIndex().allSuperTypesOf(targetType);
}
default Flux<Tuple2<IType, Double>> fuzzySearchTypes(String searchTerm, Predicate<IType> typeFilter) {
return getIndex().fuzzySearchTypes(searchTerm, typeFilter);
}

View File

@@ -54,7 +54,7 @@ public interface IType extends IMember {
IField getField(String name);
/**
* Returns the fields declared by this type in the order in which they appear
* Returns the fields declared by this type in the order in which they appear
* in the source or class file. For binary types, this includes synthetic fields.
*
* @return the fields declared by this type
@@ -71,7 +71,7 @@ public interface IType extends IMember {
* The type signatures may be either unresolved (for source types)
* or resolved (for binary types), and either basic (for basic types)
* or rich (for parameterized types). See {@link Signature} for details.
* Note that the parameter type signatures for binary methods are expected
* Note that the parameter type signatures for binary methods are expected
* to be dot-based.
* </p>
*
@@ -86,13 +86,17 @@ public interface IType extends IMember {
* For binary types, this may include the special <code>&lt;clinit&gt;</code> method
* and synthetic methods.
* <p>
* The results are listed in the order in which they appear in the source or class file.
* The results are listed in the order in which they appear in the source or class file.
* </p>
*
* @return the methods and constructors declared by this type
*/
Stream<IMethod> getMethods();
String getSuperclassName();
String[] getSuperInterfaceNames();
// /**
// * Resolves the given type name within the context of this type (depending on the type hierarchy
// * and its imports).

View File

@@ -20,9 +20,12 @@ import static org.springframework.ide.vscode.languageserver.testharness.Classpat
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -164,4 +167,24 @@ public class JavaIndexTest {
assertTrue(file.get().exists());
assertEquals(getOutputFolder(project).toString(), file.get().toString());
}
@Test
public void testFindAllSuperTypes() throws Exception {
MavenJavaProject project = mavenProjectsCache.get("gs-rest-service-cors-boot-1.4.1-with-classpath-file");
IType type = project.findType("java.util.ArrayList");
assertNotNull(type);
Set<String> actual = project.allSuperTypesOf(type).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block();
Set<String> expected = new HashSet<>(Arrays.asList(
"java.util.List",
"java.util.RandomAccess",
"java.lang.Cloneable",
"java.io.Serializable",
"java.util.AbstractList",
"java.util.Collection",
"java.lang.Object",
"java.util.AbstractCollection",
"java.lang.Iterable"
));
assertEquals(expected, actual);
}
}

View File

@@ -10,13 +10,18 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.autowired;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Hover;
import org.eclipse.lsp4j.Range;
@@ -34,6 +39,7 @@ 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.java.IType;
import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -41,11 +47,15 @@ import com.google.common.collect.ImmutableList;
/**
* @author Martin Lippert
* @author Alex Boyko
*/
public class AutowiredHoverProvider implements HoverProvider {
final static Logger log = LoggerFactory.getLogger(AutowiredHoverProvider.class);
private static final int MAX_INLINE_BEANS_STRING_LENGTH = 50;
private static final String INLINE_BEANS_STRING_SEPARATOR = " ";
private BootJavaLanguageServerComponents server;
public AutowiredHoverProvider(BootJavaLanguageServerComponents server) {
@@ -94,30 +104,61 @@ public class AutowiredHoverProvider implements HoverProvider {
LiveBean definedBean = getDefinedBean(annotation);
if (definedBean != null) {
hover.append("**Injection report for " + LiveHoverUtils.showBean(definedBean) + "**\n\n");
boolean hasInterestingApp = false;
boolean hasAutowiring = false;
boolean hasContent = false;
for (SpringBootApp app : runningApps) {
LiveBeansModel beans = app.getBeans();
List<LiveBean> relevantBeans = LiveHoverUtils.findRelevantBeans(app, definedBean).collect(Collectors.toList());
if (!relevantBeans.isEmpty()) {
if (!hasInterestingApp) {
hasInterestingApp = true;
} else {
hover.append("\n\n");
}
hover.append(LiveHoverUtils.niceAppName(app) + ":");
List<LiveBean> allDependencyBeans = relevantBeans.stream()
.flatMap(b -> Arrays.stream(b.getDependencies()))
.distinct()
.flatMap(d -> beans.getBeansOfName(d).stream())
.collect(Collectors.toList());
for (LiveBean bean : relevantBeans) {
hover.append("\n\n");
hasAutowiring |= addAutomaticallyWired(hover, annotation, beans, bean, project);
if (!allDependencyBeans.isEmpty()) {
// parent is marker node, grandparent is some field, method, variable declaration node.
ASTNode declarationNode = node.getParent().getParent();
List<LiveBean> autowiredBeans = findAutowiredBeans(project, declarationNode, allDependencyBeans);
if (autowiredBeans.isEmpty()) {
// Show all relevant dependency beans
autowiredBeans = allDependencyBeans;
}
if (!autowiredBeans.isEmpty()) {
if (!hasContent) {
hasContent = true;
} else {
hover.append(" \n \n");
}
hover.append("**Autowired &rarr; ");
if (LiveHoverUtils.doBeansFitInline(autowiredBeans, MAX_INLINE_BEANS_STRING_LENGTH, INLINE_BEANS_STRING_SEPARATOR)) {
hover.append(autowiredBeans.stream().map(b -> LiveHoverUtils.showBeanInline(server, project, b)).collect(Collectors.joining(INLINE_BEANS_STRING_SEPARATOR)));
hover.append("**\n");
} else {
hover.append(autowiredBeans.size());
hover.append(" beans**\n");
}
// if (autowiredBeans.size() == 1) {
// hover.append(LiveHoverUtils.showBeanIdAndTypeInline(server, project, autowiredBeans.get(0)));
// } else {
// hover.append(autowiredBeans.size());
// hover.append(" beans**\n");
// }
hover.append(autowiredBeans.stream()
.map(b -> "- " + LiveHoverUtils.showBeanWithResource(server, b, " ", project))
.collect(Collectors.joining("\n"))
);
hover.append("\n \n");
hover.append(LiveHoverUtils.niceAppName(app));
}
}
}
}
if (hasInterestingApp && hasAutowiring) {
if (hasContent) {
return new Hover(ImmutableList.of(Either.forLeft(hover.toString())));
}
}
@@ -125,6 +166,53 @@ public class AutowiredHoverProvider implements HoverProvider {
return null;
}
@SuppressWarnings("unchecked")
private List<LiveBean> findAutowiredBeans(IJavaProject project, ASTNode declarationNode, Collection<LiveBean> beans) {
if (declarationNode instanceof MethodDeclaration) {
MethodDeclaration methodDeclaration = (MethodDeclaration)declarationNode;
return ((List<Object>)methodDeclaration.parameters()).stream()
.filter(p -> p instanceof SingleVariableDeclaration)
.map(p -> (SingleVariableDeclaration)p)
.flatMap(p -> findAutowiredBeans(project, p, beans).stream())
.collect(Collectors.toList());
} else if (declarationNode instanceof FieldDeclaration) {
FieldDeclaration fieldDeclaration = (FieldDeclaration)declarationNode;
return matchBeans(project, beans, fieldDeclaration.getType().resolveBinding());
} else if (declarationNode instanceof SingleVariableDeclaration) {
SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration)declarationNode;
return matchBeans(project, beans, singleVariableDeclaration.getType().resolveBinding());
}
return Collections.emptyList();
}
private List<LiveBean> matchBeans(IJavaProject project, Collection<LiveBean> beans, ITypeBinding type) {
List<LiveBean> relevant = Collections.emptyList();
if (type != null) {
String fqName = type.getQualifiedName();
if (fqName != null) {
relevant = matchBeans(project, beans, fqName);
if (relevant.isEmpty()) {
IType indexType = project.findType(fqName);
if (indexType != null) {
relevant = project.allSubtypesOf(indexType)
.map(subType -> matchBeans(project, beans, subType.getFullyQualifiedName()))
.filter(relevantBeans -> !relevantBeans.isEmpty())
.blockFirst();
}
}
}
}
return relevant;
}
private List<LiveBean> matchBeans(IJavaProject project, Collection<LiveBean> beans, String fqName) {
if (fqName != null) {
return beans.stream().filter(b -> fqName.equals(b.getType(true))).collect(Collectors.toList());
} else {
return Collections.emptyList();
}
}
private LiveBean getDefinedBean(Annotation autowiredAnnotation) {
TypeDeclaration declaringType = ASTUtils.findDeclaringType(autowiredAnnotation);
if (declaringType != null) {
@@ -150,29 +238,6 @@ public class AutowiredHoverProvider implements HoverProvider {
return null;
}
private boolean addAutomaticallyWired(StringBuilder hover, Annotation annotation, LiveBeansModel beans, LiveBean bean, IJavaProject project) {
boolean result = false;
String[] dependencies = bean.getDependencies();
if (dependencies != null && dependencies.length > 0) {
result = true;
hover.append(LiveHoverUtils.showBean(bean) + " got autowired with:\n\n");
boolean firstDependency = true;
for (String injectedBean : dependencies) {
if (!firstDependency) {
hover.append("\n");
}
List<LiveBean> dependencyBeans = beans.getBeansOfName(injectedBean);
for (LiveBean dependencyBean : dependencyBeans) {
hover.append("- " + LiveHoverUtils.showBeanWithResource(server, dependencyBean, " ", project));
}
firstDependency = false;
}
}
return result;
}
@Override
public Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset,
TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {

View File

@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.livehover;
import java.util.Collection;
import java.util.Optional;
import java.util.stream.Stream;
@@ -21,7 +22,6 @@ 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.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.util.Renderables;
import org.springframework.ide.vscode.commons.util.StringUtil;
@@ -43,7 +43,9 @@ public class LiveHoverUtils {
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
@@ -65,6 +67,65 @@ public class LiveHoverUtils {
return buf.toString();
}
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();
}
}
return displayId;
}
public static boolean doBeansFitInline(Collection<LiveBean> beans, int maxLength, String delimiter) {
int length = 0;
for (LiveBean bean : beans) {
if (length != 0) {
length += delimiter.length();
}
length += bean.getId().length();
if (length > maxLength) {
return false;
}
}
return true;
}
public static String showBeanIdAndTypeInline(BootJavaLanguageServerComponents server, IJavaProject project, LiveBean bean) {
String id = bean.getId();
String type = bean.getType(true);
SourceLinks sourceLinks = SourceLinkFactory.createSourceLinks(server);
String displayType = type;
if (type != null) {
int lastDotIdx = type.lastIndexOf('.');
if (lastDotIdx >= 0 && lastDotIdx < type.length() - 1) {
displayType = "`" + type.substring(lastDotIdx + 1) + "`";
}
Optional<String> url = sourceLinks.sourceLinkUrlForFQName(project, type);
if (url.isPresent()) {
displayType = Renderables.link(displayType, url.get()).toMarkdown();
}
}
StringBuilder sb = new StringBuilder();
sb.append('`');
sb.append(id);
sb.append('`');
if (displayType != null) {
sb.append(' ');
sb.append(displayType);
}
return sb.toString();
}
public static String showResource(SourceLinks sourceLinks, String resource, IJavaProject project) {
return new SpringResource(sourceLinks, resource, project).toMarkdown();
}

View File

@@ -156,14 +156,7 @@ public class RequestMappingHoverProvider implements HoverProvider {
List<Renderable> renderableUrls = Arrays.stream(mappingMethod.getT1().getSplitPath()).flatMap(path -> {
String url = UrlUtil.createUrl(host, port, path);
StringBuilder builder = new StringBuilder();
builder.append("[");
builder.append(url);
builder.append("]");
builder.append("(");
builder.append(url);
builder.append(")");
return Stream.of(Renderables.text(builder.toString()), Renderables.lineBreak());
return Stream.of(Renderables.link(url, url), Renderables.lineBreak());
})
.collect(Collectors.toList());

View File

@@ -33,6 +33,34 @@ import org.springframework.ide.vscode.project.harness.ProjectsHarness.ProjectCus
*/
public class AutowiredHoverProviderTest {
private static final String FOO_IMPL_CONTENTS = "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" +
"}";
private static final ProjectCustomizer FOO_INTERFACE = (CustomizableProjectContent p) -> {
p.createType("com.examle.Foo",
"package com.example;\n" +
@@ -55,6 +83,8 @@ public class AutowiredHoverProviderTest {
"public class DependencyB {\n" +
"}\n"
);
p.createType("com.example.FooImplementation", FOO_IMPL_CONTENTS);
};
private BootJavaLanguageServerHarness harness;
@@ -73,7 +103,7 @@ public class AutowiredHoverProviderTest {
MavenJavaProject jp = projects.mavenProject("empty-boot-15-web-app", FOO_INTERFACE);
assertTrue(jp.findType("com.example.Foo").exists());
harness.useProject(projects.mavenProject("empty-boot-15-web-app"));
harness.useProject(jp);
harness.intialize(null);
}
@@ -116,15 +146,12 @@ public class AutowiredHoverProviderTest {
editor.assertHighlights("@Component", "@Inject");
editor.assertTrimmedHover("@Inject",
"**Injection report for Bean [id: autowiredClass, type: `com.example.AutowiredClass`]**\n" +
"\n" +
"Process [PID=111, name=`the-app`]:\n" +
"\n" +
"Bean [id: autowiredClass, type: `com.example.AutowiredClass`] got autowired with:\n" +
"\n" +
"- Bean: dependencyA \n" +
"**Autowired &rarr; `dependencyA`**\n" +
"- Bean: `dependencyA` \n" +
" Type: `com.example.DependencyA` \n" +
" Resource: `" + Paths.get("com/example/DependencyA.class") + "`"
" Resource: `" + Paths.get("com/example/DependencyA.class") + "`\n" +
" \n" +
"Process [PID=111, name=`the-app`]"
);
}
@@ -174,18 +201,16 @@ public class AutowiredHoverProviderTest {
editor.assertHighlights("@Component", "@Autowired");
editor.assertTrimmedHover("@Autowired",
"**Injection report for Bean [id: autowiredClass, type: `com.example.AutowiredClass`]**\n" +
"\n" +
"Process [PID=111, name=`the-app`]:\n" +
"\n" +
"Bean [id: autowiredClass, type: `com.example.AutowiredClass`] got autowired with:\n" +
"\n" +
"- Bean: dependencyA \n" +
"**Autowired &rarr; `dependencyA` `dependencyB`**\n" +
"- Bean: `dependencyA` \n" +
" Type: `com.example.DependencyA` \n" +
" Resource: `" + Paths.get("com/example/DependencyA.class") + "`\n" +
"- Bean: dependencyB \n" +
"- Bean: `dependencyB` \n" +
" Type: `com.example.DependencyB` \n" +
" Resource: `com/example/DependencyB.class`\n"
" Resource: `com/example/DependencyB.class`\n" +
" \n" +
"Process [PID=111, name=`the-app`]\n"
);
}
@@ -302,13 +327,17 @@ public class AutowiredHoverProviderTest {
.add(LiveBean.builder()
.id("defaultFoo")
.type("com.example.FooImplementation")
.dependencies("defaultFoo")
.dependencies("otherBean")
.dependencies("superBean", "scheduler")
.build()
)
.add(LiveBean.builder()
.id("otherBean")
.type("com.example.DependencyA")
.id("superBean")
.type("com.example.FooImplementation")
.build()
)
.add(LiveBean.builder()
.id("scheduler")
.type("org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler")
.build()
)
.build();
@@ -320,43 +349,16 @@ public class AutowiredHoverProviderTest {
.build();
Editor editor = harness.newEditor(LanguageId.JAVA,
"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 editor = harness.newEditor(LanguageId.JAVA, FOO_IMPL_CONTENTS);
editor.assertHighlights("@Component", "@Autowired", "@Autowired");
for (int i = 1; i <= 2; i++) {
editor.assertHoverContains("@Autowired", i,
"Bean [id: defaultFoo, type: `com.example.FooImplementation`] got autowired with:\n" +
"\n" +
"- Bean: otherBean \n" +
" Type: `com.example.DependencyA`");
}
editor.assertHoverContains("@Autowired", 1,
"**Autowired &rarr; `superBean`**\n" +
"- Bean: `superBean` \n" +
" Type: `com.example.FooImplementation`");
editor.assertHoverContains("@Autowired", 2,
"**Autowired &rarr; `scheduler`**\n" +
"- Bean: `scheduler` \n" +
" Type: `org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler`");
}
@Test public void bug_152621242_autowired_constructor_on_a_controller() throws Exception {
@@ -404,9 +406,8 @@ public class AutowiredHoverProviderTest {
);
editor.assertHighlights("@Controller", "@Autowired");
editor.assertHoverContains("@Autowired",
"Bean [id: myController, type: `com.example.MyController`] got autowired with:\n" +
"\n" +
"- Bean: restTemplate \n" +
"**Autowired &rarr; `restTemplate`**\n" +
"- Bean: `restTemplate` \n" +
" Type: `org.springframework.web.client.RestTemplate`"
);
editor.assertHoverContains("@Controller",

View File

@@ -215,7 +215,7 @@ public class BeanInjectedIntoHoverProviderTest {
"\n" +
"Bean [id: fooImplementation, type: `hello.FooImplementation`] injected into:\n" +
"\n" +
"- Bean: myController \n" +
"- Bean: `myController` \n" +
" Type: `hello.MyController`\n"
);
}
@@ -275,7 +275,7 @@ public class BeanInjectedIntoHoverProviderTest {
"\n" +
"Bean [id: fooImplementation, type: `hello.FooImplementation`] injected into:\n" +
"\n" +
"- Bean: myController \n" +
"- Bean: `myController` \n" +
" Type: `hello.MyController`\n"
);
}
@@ -329,7 +329,7 @@ public class BeanInjectedIntoHoverProviderTest {
"\n" +
"Bean [id: fooImplementation, type: `hello.FooImplementation`] injected into:\n" +
"\n" +
"- Bean: myController \n" +
"- Bean: `myController` \n" +
" Type: `hello.MyController` \n" +
" Resource: `" + Paths.get("hello/MyController.class") + "`"
);
@@ -383,7 +383,7 @@ public class BeanInjectedIntoHoverProviderTest {
"\n" +
"Bean [id: fooImplementation, type: `hello.FooImplementation`] injected into:\n" +
"\n" +
"- Bean: myController \n" +
"- Bean: `myController` \n" +
" Type: `hello.MyController` \n" +
" Resource: `hello/MyController.class`"
);
@@ -441,9 +441,9 @@ public class BeanInjectedIntoHoverProviderTest {
"\n" +
"Bean [id: fooImplementation, type: `hello.FooImplementation`] injected into:\n" +
"\n" +
"- Bean: myController \n" +
"- Bean: `myController` \n" +
" Type: `hello.MyController`\n" +
"- Bean: otherBean \n" +
"- Bean: `otherBean` \n" +
" Type: `hello.OtherBean`\n"
);
}

View File

@@ -140,7 +140,7 @@ public class BeansByTypeHoverProviderTest {
"\n" +
"Bean [id: scannedRandomClass, type: `com.example.ScannedRandomClass`] injected into:\n" +
"\n" +
"- Bean: randomOtherBean \n" +
"- Bean: `randomOtherBean` \n" +
" Type: `randomOtherBeanType`"
);
}
@@ -196,11 +196,11 @@ public class BeansByTypeHoverProviderTest {
"\n" +
"Bean [id: scannedFunctionClass, type: `com.example.ScannedFunctionClass`] injected into:\n" +
"\n" +
"- Bean: org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration \n" +
"- Bean: `org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration` \n" +
" Type: `org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration`"
);
}
@Test
public void generalBeanLiveHoverAvoidOverlapWithAnnotation() throws Exception {
LiveBeansModel beans = LiveBeansModel.builder()

View File

@@ -165,7 +165,7 @@ public class ComponentInjectionsHoverProviderTest {
"\n" +
"Bean [id: fooImplementation, type: `com.example.FooImplementation`] injected into:\n" +
"\n" +
"- Bean: myController \n" +
"- Bean: `myController` \n" +
" Type: `com.example.MyController`"
);
}
@@ -220,9 +220,9 @@ public class ComponentInjectionsHoverProviderTest {
"\n" +
"Bean [id: fooImplementation, type: `com.example.FooImplementation`] injected into:\n" +
"\n" +
"- Bean: myController \n" +
"- Bean: `myController` \n" +
" Type: `com.example.MyController`\n" +
"- Bean: otherBean \n" +
"- Bean: `otherBean` \n" +
" Type: `com.example.OtherBean`"
);
}
@@ -279,18 +279,18 @@ public class ComponentInjectionsHoverProviderTest {
"\n" +
"Bean [id: fooImplementation, type: `com.example.FooImplementation`] injected into:\n" +
"\n" +
"- Bean: myController \n" +
"- Bean: `myController` \n" +
" Type: `com.example.MyController`\n" +
"- Bean: otherBean \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: myController \n" +
"- Bean: `myController` \n" +
" Type: `com.example.MyController`\n" +
"- Bean: otherBean \n" +
"- Bean: `otherBean` \n" +
" Type: `com.example.OtherBean`\n"
);
}
@@ -350,7 +350,7 @@ public class ComponentInjectionsHoverProviderTest {
"\n" +
"Bean [id: fooImplementation, type: `com.example.FooImplementation`] injected into:\n" +
"\n" +
"- Bean: myController \n" +
"- Bean: `myController` \n" +
" Type: `com.example.MyController`"
);
}
@@ -410,7 +410,7 @@ public class ComponentInjectionsHoverProviderTest {
"\n" +
"Bean [id: alternateFooImplementation, type: `com.example.FooImplementation`] injected into:\n" +
"\n" +
"- Bean: otherBean \n" +
"- Bean: `otherBean` \n" +
" Type: `com.example.OtherBean`\n"
);
}
@@ -526,10 +526,10 @@ public class ComponentInjectionsHoverProviderTest {
"\n\n" +
"Bean [id: autowiredClass, type: `com.example.AutowiredClass`] got autowired with:\n" +
"\n" +
"- Bean: dependencyA \n" +
"- Bean: `dependencyA` \n" +
" Type: `com.example.DependencyA` \n" +
" Resource: `" + Paths.get("com/example/DependencyA.class") + "`\n" +
"- Bean: dependencyB \n" +
"- Bean: `dependencyB` \n" +
" Type: `com.example.DependencyB` \n" +
" Resource: `com/example/DependencyB.class`"
);