diff --git a/atom-extensions/atom-spring-boot/properties.json b/atom-extensions/atom-spring-boot/properties.json
index 97c16b6ea..2a4f68698 100644
--- a/atom-extensions/atom-spring-boot/properties.json
+++ b/atom-extensions/atom-spring-boot/properties.json
@@ -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"
}
diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF
index 750db8342..e0dc5a925 100644
--- a/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF
+++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF
@@ -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",
diff --git a/eclipse-language-servers/org.springframework.tooling.bosh.ls/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.bosh.ls/META-INF/MANIFEST.MF
index 8342bf7df..85fe36bb5 100644
--- a/eclipse-language-servers/org.springframework.tooling.bosh.ls/META-INF/MANIFEST.MF
+++ b/eclipse-language-servers/org.springframework.tooling.bosh.ls/META-INF/MANIFEST.MF
@@ -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",
diff --git a/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/Constants.java b/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/Constants.java
index eb24fc5a1..5486b8c90 100644
--- a/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/Constants.java
+++ b/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/Constants.java
@@ -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";
}
diff --git a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/META-INF/MANIFEST.MF
index e71c0d208..0d024d5b8 100644
--- a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/META-INF/MANIFEST.MF
+++ b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/META-INF/MANIFEST.MF
@@ -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",
diff --git a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/Constants.java b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/Constants.java
index 8ff6afa62..f9c56a9a6 100644
--- a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/Constants.java
+++ b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/Constants.java
@@ -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";
}
diff --git a/eclipse-language-servers/org.springframework.tooling.concourse.ls/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.concourse.ls/META-INF/MANIFEST.MF
index 17fcc0f95..ec7aa2ac3 100644
--- a/eclipse-language-servers/org.springframework.tooling.concourse.ls/META-INF/MANIFEST.MF
+++ b/eclipse-language-servers/org.springframework.tooling.concourse.ls/META-INF/MANIFEST.MF
@@ -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",
diff --git a/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/Constants.java b/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/Constants.java
index d8863c7a7..ecc4e9784 100644
--- a/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/Constants.java
+++ b/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/Constants.java
@@ -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";
}
diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LocalSpringBootApp.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LocalSpringBootApp.java
index a83f640a0..bd80cf64e 100644
--- a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LocalSpringBootApp.java
+++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LocalSpringBootApp.java
@@ -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
diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java
index f75377567..67bbb4b63 100644
--- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java
+++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java
@@ -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 queue, Set 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 allSuperTypesOf(IType type) {
+ Queue queue = new LinkedList<>();
+ HashSet 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;
+ });
+ }
+
}
diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/TypeImpl.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/TypeImpl.java
index aa4bf012f..c66b2d82c 100644
--- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/TypeImpl.java
+++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/TypeImpl.java
@@ -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);
+ }
+
}
diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathIndex.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathIndex.java
index 38b5b46a6..6a098726c 100644
--- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathIndex.java
+++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathIndex.java
@@ -27,6 +27,7 @@ public interface ClasspathIndex extends Disposable {
Flux> fuzzySearchTypes(String searchTerm, Predicate typeFilter);
Flux> fuzzySearchPackages(String searchTerm);
Flux allSubtypesOf(IType type);
+ Flux allSuperTypesOf(IType type);
Optional findClasspathResourceContainer(String fqName);
//Maybe the stuff below is another interface? Something that provides operations
diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IJavaProject.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IJavaProject.java
index 85d6468e3..205702ce5 100644
--- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IJavaProject.java
+++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IJavaProject.java
@@ -41,6 +41,10 @@ public interface IJavaProject {
return getIndex().allSubtypesOf(targetType);
}
+ default Flux allSuperTypesOf(IType targetType) {
+ return getIndex().allSuperTypesOf(targetType);
+ }
+
default Flux> fuzzySearchTypes(String searchTerm, Predicate typeFilter) {
return getIndex().fuzzySearchTypes(searchTerm, typeFilter);
}
diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IType.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IType.java
index d5e1e22cf..8322eebac 100644
--- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IType.java
+++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IType.java
@@ -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.
*
*
@@ -86,13 +86,17 @@ public interface IType extends IMember {
* For binary types, this may include the special <clinit> method
* and synthetic methods.
*
- * 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.
*
*
* @return the methods and constructors declared by this type
*/
Stream getMethods();
+ String getSuperclassName();
+
+ String[] getSuperInterfaceNames();
+
// /**
// * Resolves the given type name within the context of this type (depending on the type hierarchy
// * and its imports).
diff --git a/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java b/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java
index 665872e3f..c17b2207f 100644
--- a/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java
+++ b/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/JavaIndexTest.java
@@ -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 actual = project.allSuperTypesOf(type).map(t -> t.getFullyQualifiedName()).collect(Collectors.toSet()).block();
+ Set 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);
+ }
}
diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java
index 418bce5b6..aedb86d9e 100644
--- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java
+++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java
@@ -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 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 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 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 → ");
+ 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 findAutowiredBeans(IJavaProject project, ASTNode declarationNode, Collection beans) {
+ if (declarationNode instanceof MethodDeclaration) {
+ MethodDeclaration methodDeclaration = (MethodDeclaration)declarationNode;
+ return ((List