PT #151991870: first rough implementation for live hovers for components without autowired annotation
This commit is contained in:
@@ -19,6 +19,7 @@ import org.eclipse.lsp4j.InitializeParams;
|
||||
import org.eclipse.lsp4j.InitializeResult;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.beans.ComponentHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.beans.ComponentSymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaCodeLensEngine;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaCompletionEngine;
|
||||
@@ -235,6 +236,7 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_PATCH_MAPPING, new RequestMappingHoverProvider());
|
||||
|
||||
providers.put(org.springframework.ide.vscode.boot.java.autowired.Constants.SPRING_AUTOWIRED, new AutowiredHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.beans.Constants.SPRING_COMPONENT, new ComponentHoverProvider());
|
||||
|
||||
return new BootJavaHoverProvider(this, javaProjectFinder, providers);
|
||||
}
|
||||
|
||||
@@ -36,30 +36,40 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
@Override
|
||||
public CompletableFuture<Hover> provideHover(ASTNode node, Annotation annotation,
|
||||
ITypeBinding type, int offset, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
|
||||
SpringBootAppProvider[] bootApps = new SpringBootAppProvider[runningApps.length];
|
||||
for (int i = 0; i < runningApps.length; i++) {
|
||||
bootApps[i] = new SpringBootAppProviderImpl(runningApps[i]);
|
||||
}
|
||||
return provideHover(node, annotation, type, offset, doc, bootApps);
|
||||
}
|
||||
|
||||
public CompletableFuture<Hover> provideHover(ASTNode node, Annotation annotation,
|
||||
ITypeBinding type, int offset, TextDocument doc, SpringBootAppProvider[] runningApps) {
|
||||
try {
|
||||
List<Either<String, MarkedString>> hoverContent = new ArrayList<>();
|
||||
|
||||
if (runningApps.length > 0) {
|
||||
for (SpringBootApp bootApp : runningApps) {
|
||||
try {
|
||||
String liveBeans = bootApp.getBeans();
|
||||
if (liveBeans != null && liveBeans.length() > 0) {
|
||||
addLiveHoverContent(annotation, doc, liveBeans, bootApp, hoverContent);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
for (SpringBootAppProvider bootApp : runningApps) {
|
||||
try {
|
||||
String liveBeans = bootApp.getBeans();
|
||||
if (liveBeans != null && liveBeans.length() > 0) {
|
||||
addLiveHoverContent(annotation, doc, liveBeans, bootApp, hoverContent);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
Hover hover = new Hover();
|
||||
if (hoverContent.size() > 0) {
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
Hover hover = new Hover();
|
||||
|
||||
hover.setContents(hoverContent);
|
||||
hover.setRange(hoverRange);
|
||||
hover.setContents(hoverContent);
|
||||
hover.setRange(hoverRange);
|
||||
|
||||
return CompletableFuture.completedFuture(hover);
|
||||
return CompletableFuture.completedFuture(hover);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
@@ -70,20 +80,18 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
@Override
|
||||
public Range getLiveHoverHint(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
try {
|
||||
if (runningApps.length > 0) {
|
||||
for (SpringBootApp bootApp : runningApps) {
|
||||
try {
|
||||
String liveBeans = bootApp.getBeans();
|
||||
if (liveBeans != null && liveBeans.length() > 0) {
|
||||
Range range = getLiveHoverHint(annotation, doc, liveBeans);
|
||||
if (range != null) {
|
||||
return range;
|
||||
}
|
||||
for (SpringBootApp bootApp : runningApps) {
|
||||
try {
|
||||
String liveBeans = bootApp.getBeans();
|
||||
if (liveBeans != null && liveBeans.length() > 0) {
|
||||
Range range = getLiveHoverHint(annotation, doc, liveBeans);
|
||||
if (range != null) {
|
||||
return range;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +123,7 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addLiveHoverContent(Annotation annotation, TextDocument doc, String liveBeansJSON, SpringBootApp bootApp, List<Either<String, MarkedString>> hoverContent) {
|
||||
public void addLiveHoverContent(Annotation annotation, TextDocument doc, String liveBeansJSON, SpringBootAppProvider bootApp, List<Either<String, MarkedString>> hoverContent) {
|
||||
String type = findDeclaredType(annotation);
|
||||
if (type != null && liveBeansJSON != null) {
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.autowired;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public interface SpringBootAppProvider {
|
||||
|
||||
public String getBeans() throws Exception;
|
||||
public String getProcessID();
|
||||
public String getProcessName();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.autowired;
|
||||
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class SpringBootAppProviderImpl implements SpringBootAppProvider {
|
||||
|
||||
private SpringBootApp bootApp;
|
||||
|
||||
public SpringBootAppProviderImpl(SpringBootApp bootApp) {
|
||||
this.bootApp = bootApp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBeans() throws Exception {
|
||||
return bootApp.getBeans();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProcessID() {
|
||||
return bootApp.getProcessID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProcessName() {
|
||||
return bootApp.getProcessName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.beans;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MarkerAnnotation;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.MarkedString;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.Constants;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.LiveBean;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.LiveBeansModel;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.SpringBootAppProvider;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.SpringBootAppProviderImpl;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class ComponentHoverProvider implements HoverProvider {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Hover> provideHover(ASTNode node, Annotation annotation,
|
||||
ITypeBinding type, int offset, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
SpringBootAppProvider[] bootApps = new SpringBootAppProvider[runningApps.length];
|
||||
for (int i = 0; i < runningApps.length; i++) {
|
||||
bootApps[i] = new SpringBootAppProviderImpl(runningApps[i]);
|
||||
}
|
||||
return provideHover(node, annotation, type, offset, doc, bootApps);
|
||||
}
|
||||
|
||||
public CompletableFuture<Hover> provideHover(ASTNode node, Annotation annotation,
|
||||
ITypeBinding type, int offset, TextDocument doc, SpringBootAppProvider[] runningApps) {
|
||||
try {
|
||||
Range range = null;
|
||||
|
||||
TypeDeclaration typeDecl = findDeclaredType(annotation);
|
||||
if (typeDecl != null) {
|
||||
MethodDeclaration constructor = findConstructor(typeDecl);
|
||||
|
||||
if (constructor != null && !hasAutowiredAnnotation(constructor)) {
|
||||
range = doc.toRange(constructor.getName().getStartPosition(), constructor.getName().getLength());
|
||||
|
||||
List<Either<String, MarkedString>> hoverContent = new ArrayList<>();
|
||||
for (SpringBootAppProvider bootApp : runningApps) {
|
||||
try {
|
||||
String liveBeans = bootApp.getBeans();
|
||||
if (liveBeans != null && liveBeans.length() > 0) {
|
||||
addLiveHoverContent(typeDecl, doc, liveBeans, bootApp, hoverContent);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (hoverContent.size() > 0) {
|
||||
Hover hover = new Hover();
|
||||
|
||||
hover.setContents(hoverContent);
|
||||
hover.setRange(range);
|
||||
|
||||
return CompletableFuture.completedFuture(hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Range getLiveHoverHint(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
try {
|
||||
for (SpringBootApp bootApp : runningApps) {
|
||||
try {
|
||||
String liveBeans = bootApp.getBeans();
|
||||
if (liveBeans != null && liveBeans.length() > 0) {
|
||||
Range range = getLiveHoverHint(annotation, doc, liveBeans);
|
||||
if (range != null) {
|
||||
return range;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Range getLiveHoverHint(Annotation annotation, TextDocument doc, String liveBeansJSON) {
|
||||
try {
|
||||
TypeDeclaration type = findDeclaredType(annotation);
|
||||
if (type != null && liveBeansJSON != null) {
|
||||
String typeName = type.resolveBinding().getQualifiedName();
|
||||
|
||||
LiveBeansModel beansModel = LiveBeansModel.parse(liveBeansJSON);
|
||||
LiveBean[] beansOfType = beansModel.getBeansOfType(typeName);
|
||||
|
||||
if (beansOfType.length > 0) {
|
||||
MethodDeclaration constructor = findConstructor(type);
|
||||
if (constructor != null && !hasAutowiredAnnotation(constructor)) {
|
||||
Range hoverRange = doc.toRange(constructor.getName().getStartPosition(), constructor.getName().getLength());
|
||||
return hoverRange;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (BadLocationException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean hasAutowiredAnnotation(MethodDeclaration constructor) {
|
||||
List<?> modifiers = constructor.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof MarkerAnnotation) {
|
||||
ITypeBinding typeBinding = ((MarkerAnnotation) modifier).resolveTypeBinding();
|
||||
if (typeBinding != null && typeBinding.getQualifiedName().equals(Constants.SPRING_AUTOWIRED)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void addLiveHoverContent(TypeDeclaration declaringType, TextDocument doc, String liveBeansJSON, SpringBootAppProvider bootApp, List<Either<String, MarkedString>> hoverContent) {
|
||||
String type = declaringType.resolveBinding().getQualifiedName();
|
||||
if (type != null && liveBeansJSON != null) {
|
||||
|
||||
LiveBeansModel beansModel = LiveBeansModel.parse(liveBeansJSON);
|
||||
LiveBean[] beansOfType = beansModel.getBeansOfType(type);
|
||||
|
||||
if (beansOfType.length > 0) {
|
||||
String processId = bootApp.getProcessID();
|
||||
String processName = bootApp.getProcessName();
|
||||
|
||||
for (LiveBean liveBean : beansOfType) {
|
||||
String[] dependencies = liveBean.getDependencies();
|
||||
|
||||
if (dependencies != null && dependencies.length > 0) {
|
||||
hoverContent.add(Either.forLeft("bean: " + liveBean.getId()));
|
||||
hoverContent.add(Either.forLeft("injected beans:"));
|
||||
|
||||
for (String dependency : dependencies) {
|
||||
LiveBean[] dependencyBeans = beansModel.getBeansOfName(dependency);
|
||||
for (LiveBean dependencyBean : dependencyBeans) {
|
||||
hoverContent.add(Either.forLeft("- '" + dependencyBean.getId() + "' - from: " + dependencyBean.getResource()));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: no dependencies found
|
||||
}
|
||||
}
|
||||
|
||||
hoverContent.add(Either.forLeft("Process ID: " + processId));
|
||||
hoverContent.add(Either.forLeft("Process Name: " + processName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TypeDeclaration findDeclaredType(Annotation annotation) {
|
||||
ASTNode node = annotation;
|
||||
while (node != null && !(node instanceof TypeDeclaration)) {
|
||||
node = node.getParent();
|
||||
}
|
||||
|
||||
return node != null ? (TypeDeclaration) node : null;
|
||||
}
|
||||
|
||||
private MethodDeclaration findConstructor(TypeDeclaration typeDecl) {
|
||||
MethodDeclaration[] methods = typeDecl.getMethods();
|
||||
for (MethodDeclaration methodDeclaration : methods) {
|
||||
if (methodDeclaration.isConstructor()) {
|
||||
return methodDeclaration;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,14 +13,17 @@ package org.springframework.ide.vscode.boot.java.autowired.test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
@@ -30,12 +33,16 @@ import org.eclipse.jdt.core.dom.ASTParser;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.NodeFinder;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.MarkedString;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.SpringBootAppProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.CompositeJavaProjectManager;
|
||||
@@ -147,6 +154,58 @@ public class AutowiredHoverProviderTest {
|
||||
assertNull(hint);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLiveHoverContentForAutowiredOnConstructor() throws Exception {
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-autowired/").toURI());
|
||||
harness.intialize(directory);
|
||||
|
||||
String docURI = "file://" + directory.getAbsolutePath() + "/src/main/java/org/test/MyAutowiredComponent.java";
|
||||
IJavaProject project = projectManager.find(directory);
|
||||
TextDocument document = createTempTextDocument(docURI);
|
||||
|
||||
CompilationUnit cu = parse(document, project);
|
||||
|
||||
int offset = document.toOffset(new Position(11, 4));
|
||||
ASTNode node = NodeFinder.perform(cu, offset, 0).getParent();
|
||||
|
||||
AutowiredHoverProvider provider = new AutowiredHoverProvider();
|
||||
String beansJSON = new String(Files.readAllBytes(new File(directory, "runtime-bean-information.json").toPath()));
|
||||
|
||||
SpringBootAppProvider bootApp = new SpringBootAppProvider() {
|
||||
@Override
|
||||
public String getProcessName() {
|
||||
return "test process name";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProcessID() {
|
||||
return "test process id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBeans() throws Exception {
|
||||
return beansJSON;
|
||||
}
|
||||
};
|
||||
CompletableFuture<Hover> hoverFuture = provider.provideHover(null, (Annotation)node, null, offset, document, new SpringBootAppProvider[] {bootApp});
|
||||
Hover hover = hoverFuture.get();
|
||||
assertNotNull(hover);
|
||||
|
||||
assertEquals(11, hover.getRange().getStart().getLine());
|
||||
assertEquals(1, hover.getRange().getStart().getCharacter());
|
||||
assertEquals(11, hover.getRange().getEnd().getLine());
|
||||
assertEquals(11, hover.getRange().getEnd().getCharacter());
|
||||
|
||||
List<Either<String, MarkedString>> contents = hover.getContents();
|
||||
assertEquals(6, contents.size());
|
||||
|
||||
assertTrue(contents.get(0).getLeft().contains("myAutowiredComponent"));
|
||||
assertTrue(contents.get(2).getLeft().contains("dependencyA"));
|
||||
assertTrue(contents.get(3).getLeft().contains("dependencyB"));
|
||||
assertTrue(contents.get(4).getLeft().contains("test process id"));
|
||||
assertTrue(contents.get(5).getLeft().contains("test process name"));
|
||||
}
|
||||
|
||||
private TextDocument createTempTextDocument(String docURI) throws Exception {
|
||||
Path path = Paths.get(new URI(docURI));
|
||||
String content = new String(Files.readAllBytes(path));
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.beans.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jdt.core.dom.AST;
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.ASTParser;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.NodeFinder;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.MarkedString;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.SpringBootAppProvider;
|
||||
import org.springframework.ide.vscode.boot.java.beans.ComponentHoverProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.CompositeJavaProjectManager;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectManager;
|
||||
import org.springframework.ide.vscode.commons.maven.MavenCore;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenProjectManager;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.BasicFileObserver;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
import org.springframework.ide.vscode.project.harness.PropertyIndexHarness;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class ComponentHoverProviderTest {
|
||||
|
||||
private JavaProjectManager projectManager;
|
||||
private LanguageServerHarness<BootJavaLanguageServer> harness;
|
||||
private PropertyIndexHarness indexHarness;
|
||||
private BasicFileObserver fileObserver;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
projectManager = new CompositeJavaProjectManager(new JavaProjectManager[] {new MavenProjectManager(MavenCore.getDefault())});
|
||||
fileObserver = new BasicFileObserver();
|
||||
projectManager.setFileObserver(fileObserver);
|
||||
|
||||
indexHarness = new PropertyIndexHarness();
|
||||
harness = new LanguageServerHarness<BootJavaLanguageServer>(new Callable<BootJavaLanguageServer>() {
|
||||
@Override
|
||||
public BootJavaLanguageServer call() throws Exception {
|
||||
BootJavaLanguageServer server = new BootJavaLanguageServer(projectManager, indexHarness.getIndexProvider());
|
||||
return server;
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
protected String getFileExtension() {
|
||||
return ".java";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLiveHoverHintForAutomaicallywiredConstructor() throws Exception {
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-autowired/").toURI());
|
||||
harness.intialize(directory);
|
||||
|
||||
String docURI = "file://" + directory.getAbsolutePath() + "/src/main/java/org/test/MyAutomaticallyWiredComponent.java";
|
||||
IJavaProject project = projectManager.find(directory);
|
||||
TextDocument document = createTempTextDocument(docURI);
|
||||
|
||||
CompilationUnit cu = parse(document, project);
|
||||
|
||||
int offset = document.toOffset(new Position(4, 2));
|
||||
ASTNode node = NodeFinder.perform(cu, offset, 0).getParent();
|
||||
|
||||
ComponentHoverProvider provider = new ComponentHoverProvider();
|
||||
String beansJSON = new String(Files.readAllBytes(new File(directory, "runtime-bean-information-automatically-wired.json").toPath()));
|
||||
|
||||
Range hint = provider.getLiveHoverHint((Annotation)node, document, beansJSON);
|
||||
assertNotNull(hint);
|
||||
|
||||
assertEquals(10, hint.getStart().getLine());
|
||||
assertEquals(8, hint.getStart().getCharacter());
|
||||
assertEquals(10, hint.getEnd().getLine());
|
||||
assertEquals(37, hint.getEnd().getCharacter());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoLiveHoverHintForComponentWhenAutowiredAnnotationIsUsed() throws Exception {
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-autowired/").toURI());
|
||||
harness.intialize(directory);
|
||||
|
||||
String docURI = "file://" + directory.getAbsolutePath() + "/src/main/java/org/test/MyAutowiredComponent.java";
|
||||
IJavaProject project = projectManager.find(directory);
|
||||
TextDocument document = createTempTextDocument(docURI);
|
||||
|
||||
CompilationUnit cu = parse(document, project);
|
||||
|
||||
int offset = document.toOffset(new Position(5, 2));
|
||||
ASTNode node = NodeFinder.perform(cu, offset, 0).getParent();
|
||||
|
||||
ComponentHoverProvider provider = new ComponentHoverProvider();
|
||||
String beansJSON = new String(Files.readAllBytes(new File(directory, "runtime-bean-information.json").toPath()));
|
||||
|
||||
Range hint = provider.getLiveHoverHint((Annotation)node, document, beansJSON);
|
||||
assertNull(hint);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLiveHoverContentForAutomaicallywiredConstructor() throws Exception {
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-autowired/").toURI());
|
||||
harness.intialize(directory);
|
||||
|
||||
String docURI = "file://" + directory.getAbsolutePath() + "/src/main/java/org/test/MyAutomaticallyWiredComponent.java";
|
||||
IJavaProject project = projectManager.find(directory);
|
||||
TextDocument document = createTempTextDocument(docURI);
|
||||
|
||||
CompilationUnit cu = parse(document, project);
|
||||
|
||||
int offset = document.toOffset(new Position(4, 2));
|
||||
ASTNode node = NodeFinder.perform(cu, offset, 0).getParent();
|
||||
|
||||
ComponentHoverProvider provider = new ComponentHoverProvider();
|
||||
String beansJSON = new String(Files.readAllBytes(new File(directory, "runtime-bean-information-automatically-wired.json").toPath()));
|
||||
|
||||
SpringBootAppProvider bootApp = new SpringBootAppProvider() {
|
||||
@Override
|
||||
public String getProcessName() {
|
||||
return "test process name";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProcessID() {
|
||||
return "test process id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBeans() throws Exception {
|
||||
return beansJSON;
|
||||
}
|
||||
};
|
||||
CompletableFuture<Hover> hoverFuture = provider.provideHover(null, (Annotation) node, null, 0, document, new SpringBootAppProvider[] {bootApp});
|
||||
Hover hover = hoverFuture.get();
|
||||
|
||||
assertNotNull(hover);
|
||||
|
||||
assertEquals(10, hover.getRange().getStart().getLine());
|
||||
assertEquals(8, hover.getRange().getStart().getCharacter());
|
||||
assertEquals(10, hover.getRange().getEnd().getLine());
|
||||
assertEquals(37, hover.getRange().getEnd().getCharacter());
|
||||
|
||||
List<Either<String, MarkedString>> contents = hover.getContents();
|
||||
assertEquals(6, contents.size());
|
||||
|
||||
assertTrue(contents.get(0).getLeft().contains("myAutomaticallyWiredComponent"));
|
||||
assertTrue(contents.get(2).getLeft().contains("dependencyA"));
|
||||
assertTrue(contents.get(3).getLeft().contains("dependencyB"));
|
||||
assertTrue(contents.get(4).getLeft().contains("test process id"));
|
||||
assertTrue(contents.get(5).getLeft().contains("test process name"));
|
||||
}
|
||||
|
||||
private TextDocument createTempTextDocument(String docURI) throws Exception {
|
||||
Path path = Paths.get(new URI(docURI));
|
||||
String content = new String(Files.readAllBytes(path));
|
||||
|
||||
TextDocument doc = new TextDocument(docURI, LanguageId.PLAINTEXT, 0, content);
|
||||
return doc;
|
||||
}
|
||||
|
||||
private CompilationUnit parse(TextDocument document, IJavaProject project)
|
||||
throws Exception, BadLocationException {
|
||||
ASTParser parser = ASTParser.newParser(AST.JLS8);
|
||||
Map<String, String> options = JavaCore.getOptions();
|
||||
JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options);
|
||||
parser.setCompilerOptions(options);
|
||||
parser.setKind(ASTParser.K_COMPILATION_UNIT);
|
||||
parser.setStatementsRecovery(true);
|
||||
parser.setBindingsRecovery(true);
|
||||
parser.setResolveBindings(true);
|
||||
|
||||
String[] classpathEntries = getClasspathEntries(project);
|
||||
String[] sourceEntries = new String[] {};
|
||||
parser.setEnvironment(classpathEntries, sourceEntries, null, true);
|
||||
|
||||
String docURI = document.getUri();
|
||||
String unitName = docURI.substring(docURI.lastIndexOf("/"));
|
||||
parser.setUnitName(unitName);
|
||||
parser.setSource(document.get(0, document.getLength()).toCharArray());
|
||||
|
||||
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
|
||||
return cu;
|
||||
}
|
||||
|
||||
private String[] getClasspathEntries(IJavaProject project) throws Exception {
|
||||
IClasspath classpath = project.getClasspath();
|
||||
Stream<Path> classpathEntries = classpath.getClasspathEntries();
|
||||
return classpathEntries
|
||||
.filter(path -> path.toFile().exists())
|
||||
.map(path -> path.toAbsolutePath().toString()).toArray(String[]::new);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils.test;
|
||||
package org.springframework.ide.vscode.boot.java.beans.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -8,7 +8,7 @@
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.completions.test;
|
||||
package org.springframework.ide.vscode.boot.java.scope.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -8,7 +8,7 @@
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.completions.test;
|
||||
package org.springframework.ide.vscode.boot.java.value.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -8,7 +8,7 @@
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.hover.test;
|
||||
package org.springframework.ide.vscode.boot.java.value.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
@@ -0,0 +1,35 @@
|
||||
[
|
||||
{
|
||||
"context": "application",
|
||||
"parent": null,
|
||||
"beans": [
|
||||
{
|
||||
"bean": "dependencyA",
|
||||
"aliases": [],
|
||||
"scope": "singleton",
|
||||
"type": "org.test.DependencyA",
|
||||
"resource": "file [/Users/mlippert/Entwicklung/vmware/projects/sts4/headless-services/boot-java-language-server/src/test/resources/test-projects/test-annotation-indexing-autowired/target/classes/org/test/DependencyA.class]",
|
||||
"dependencies": []
|
||||
},
|
||||
{
|
||||
"bean": "dependencyB",
|
||||
"aliases": [],
|
||||
"scope": "singleton",
|
||||
"type": "org.test.DependencyB",
|
||||
"resource": "file [/Users/mlippert/Entwicklung/vmware/projects/sts4/headless-services/boot-java-language-server/src/test/resources/test-projects/test-annotation-indexing-autowired/target/classes/org/test/DependencyB.class]",
|
||||
"dependencies": []
|
||||
},
|
||||
{
|
||||
"bean": "myAutomaticallyWiredComponent",
|
||||
"aliases": [],
|
||||
"scope": "singleton",
|
||||
"type": "org.test.MyAutomaticallyWiredComponent",
|
||||
"resource": "file [/Users/mlippert/Entwicklung/vmware/projects/sts4/headless-services/boot-java-language-server/src/test/resources/test-projects/test-annotation-indexing-autowired/target/classes/org/test/MyAutomaticallyWiredComponent.class]",
|
||||
"dependencies": [
|
||||
"dependencyA",
|
||||
"dependencyB"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.test;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class MyAutomaticallyWiredComponent {
|
||||
|
||||
private DependencyA depA;
|
||||
private DependencyB depB;
|
||||
|
||||
public MyAutomaticallyWiredComponent(DependencyA depA, DependencyB depB) {
|
||||
this.depA = depA;
|
||||
this.depB = depB;
|
||||
}
|
||||
|
||||
public DependencyA getDepA() {
|
||||
return depA;
|
||||
}
|
||||
|
||||
public DependencyB getDepB() {
|
||||
return depB;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user