PT #151052858: added simple hover content for autowired annotation live hovers
This commit is contained in:
@@ -17,6 +17,7 @@ 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.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.MarkedString;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
@@ -35,64 +36,22 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
@Override
|
||||
public CompletableFuture<Hover> provideHover(ASTNode node, Annotation annotation,
|
||||
ITypeBinding type, int offset, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
return provideHover(annotation, doc, runningApps);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Range getLiveHoverHint(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
try {
|
||||
if (runningApps.length > 0) {
|
||||
List<Either<String, MarkedString>> hoverContent = new ArrayList<>();
|
||||
|
||||
List<String> liveBeanInfo = new ArrayList<>();
|
||||
if (runningApps.length > 0) {
|
||||
for (SpringBootApp bootApp : runningApps) {
|
||||
try {
|
||||
String liveBeans = bootApp.getBeans();
|
||||
if (liveBeans != null && liveBeans.length() > 0) {
|
||||
liveBeanInfo.add(liveBeans);
|
||||
addLiveHoverContent(annotation, doc, liveBeans, bootApp, hoverContent);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (!liveBeanInfo.isEmpty()) {
|
||||
return getLiveHoverHint(annotation, doc, liveBeanInfo.toArray(new String[liveBeanInfo.size()]));
|
||||
}
|
||||
|
||||
// TODO: real work
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
return hoverRange;
|
||||
}
|
||||
}
|
||||
catch (BadLocationException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Range getLiveHoverHint(Annotation annotation, TextDocument doc, String[] liveBeanJSON) {
|
||||
try {
|
||||
if (liveBeanJSON.length > 0) {
|
||||
// TODO: real work
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
return hoverRange;
|
||||
}
|
||||
}
|
||||
catch (BadLocationException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private CompletableFuture<Hover> provideHover(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
|
||||
try {
|
||||
List<Either<String, MarkedString>> hoverContent = new ArrayList<>();
|
||||
|
||||
// TODO: real work
|
||||
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
Hover hover = new Hover();
|
||||
@@ -108,4 +67,103 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Range getLiveHoverHint(Annotation annotation, TextDocument doc, String liveBeansJSON) {
|
||||
try {
|
||||
String type = findDeclaredType(annotation);
|
||||
if (type != null && liveBeansJSON != null) {
|
||||
|
||||
LiveBeansModel beansModel = LiveBeansModel.parse(liveBeansJSON);
|
||||
LiveBean[] beansOfType = beansModel.getBeansOfType(type);
|
||||
|
||||
if (beansOfType.length > 0) {
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
return hoverRange;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (BadLocationException e) {
|
||||
Log.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addLiveHoverContent(Annotation annotation, TextDocument doc, String liveBeansJSON, SpringBootApp bootApp, List<Either<String, MarkedString>> hoverContent) {
|
||||
String type = findDeclaredType(annotation);
|
||||
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 String findDeclaredType(Annotation annotation) {
|
||||
ASTNode node = annotation;
|
||||
while (node != null && !(node instanceof TypeDeclaration)) {
|
||||
node = node.getParent();
|
||||
}
|
||||
|
||||
if (node != null) {
|
||||
TypeDeclaration typeDecl = (TypeDeclaration) node;
|
||||
return typeDecl.resolveBinding().getQualifiedName();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*******************************************************************************
|
||||
* 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.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class LiveBean {
|
||||
|
||||
public static LiveBean parse(JSONObject beansJSON) {
|
||||
String id = beansJSON.optString("bean");
|
||||
String type = beansJSON.optString("type");
|
||||
String scope = beansJSON.optString("scope");
|
||||
String resource = beansJSON.optString("resource");
|
||||
|
||||
JSONArray aliasesJSON = beansJSON.getJSONArray("aliases");
|
||||
String[] aliases = new String[aliasesJSON.length()];
|
||||
for (int i = 0; i < aliasesJSON.length(); i++) {
|
||||
aliases[i] = aliasesJSON.optString(i);
|
||||
}
|
||||
|
||||
JSONArray dependenciesJSON = beansJSON.getJSONArray("dependencies");
|
||||
String[] dependencies = new String[dependenciesJSON.length()];
|
||||
for (int i = 0; i < dependenciesJSON.length(); i++) {
|
||||
dependencies[i] = dependenciesJSON.optString(i);
|
||||
}
|
||||
|
||||
return new LiveBean(id, aliases, scope, type, resource, dependencies);
|
||||
}
|
||||
|
||||
private final String id;
|
||||
private final String[] aliases;
|
||||
private final String scope;
|
||||
private final String type;
|
||||
private final String resource;
|
||||
private final String[] dependencies;
|
||||
|
||||
protected LiveBean(String id, String[] aliases, String scope, String type, String resource, String[] dependencies) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.aliases = aliases;
|
||||
this.scope = scope;
|
||||
this.type = type;
|
||||
this.resource = resource;
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String[] getAliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public String[] getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*******************************************************************************
|
||||
* 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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class LiveBeansModel {
|
||||
|
||||
public static LiveBeansModel parse(String json) {
|
||||
LiveBeansModel model = new LiveBeansModel();
|
||||
|
||||
try {
|
||||
JSONArray mainArray = new JSONArray(json);
|
||||
|
||||
for (int i = 0; i < mainArray.length(); i++) {
|
||||
JSONObject appContext = mainArray.getJSONObject(i);
|
||||
if (appContext == null) continue;
|
||||
|
||||
JSONArray beansArray = appContext.optJSONArray("beans");
|
||||
if (beansArray == null) continue;
|
||||
|
||||
for (int j = 0; j < beansArray.length(); j++) {
|
||||
JSONObject beanObject = beansArray.getJSONObject(j);
|
||||
if (beanObject == null) continue;
|
||||
|
||||
LiveBean bean = LiveBean.parse(beanObject);
|
||||
if (bean != null) {
|
||||
model.add(bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private final ConcurrentMap<String, List<LiveBean>> beansViaType;
|
||||
private final ConcurrentMap<String, List<LiveBean>> beansViaName;
|
||||
|
||||
protected LiveBeansModel() {
|
||||
this.beansViaType = new ConcurrentHashMap<>();
|
||||
this.beansViaName = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public LiveBean[] getBeansOfType(String fullyQualifiedType) {
|
||||
List<LiveBean> result = beansViaType.get(fullyQualifiedType);
|
||||
return result != null ? result.toArray(new LiveBean[result.size()]) : new LiveBean[0];
|
||||
}
|
||||
|
||||
public LiveBean[] getBeansOfName(String beanName) {
|
||||
List<LiveBean> result = beansViaName.get(beanName);
|
||||
return result != null ? result.toArray(new LiveBean[result.size()]) : new LiveBean[0];
|
||||
}
|
||||
|
||||
protected void add(LiveBean bean) {
|
||||
String type = bean.getType();
|
||||
if (type != null) {
|
||||
beansViaType.computeIfAbsent(type, (t) -> new ArrayList<>()).add(bean);
|
||||
}
|
||||
|
||||
String name = bean.getId();
|
||||
if (name != null) {
|
||||
beansViaName.computeIfAbsent(name, (n) -> new ArrayList<>()).add(bean);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class AutowiredHoverProviderTest {
|
||||
AutowiredHoverProvider provider = new AutowiredHoverProvider();
|
||||
String beansJSON = new String(Files.readAllBytes(new File(directory, "runtime-bean-information.json").toPath()));
|
||||
|
||||
Range hint = provider.getLiveHoverHint((Annotation)node, document, new String[] {beansJSON});
|
||||
Range hint = provider.getLiveHoverHint((Annotation)node, document, beansJSON);
|
||||
assertNotNull(hint);
|
||||
|
||||
assertEquals(11, hint.getStart().getLine());
|
||||
@@ -122,10 +122,10 @@ public class AutowiredHoverProviderTest {
|
||||
ASTNode node = NodeFinder.perform(cu, offset, 0).getParent();
|
||||
|
||||
AutowiredHoverProvider provider = new AutowiredHoverProvider();
|
||||
Range hint = provider.getLiveHoverHint((Annotation)node, document, new String[] {});
|
||||
Range hint = provider.getLiveHoverHint((Annotation)node, document, (String)null);
|
||||
assertNull(hint);
|
||||
}
|
||||
/**
|
||||
|
||||
@Test
|
||||
public void testNoLiveHoverHintForAutowiredOnConstructorWithWrongLiveAppData() throws Exception {
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-autowired/").toURI());
|
||||
@@ -141,12 +141,12 @@ public class AutowiredHoverProviderTest {
|
||||
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()));
|
||||
String beansJSON = new String(Files.readAllBytes(new File(directory, "wrong-runtime-bean-information.json").toPath()));
|
||||
|
||||
Range hint = provider.getLiveHoverHint((Annotation)node, document, new String[] {beansJSON});
|
||||
Range hint = provider.getLiveHoverHint((Annotation)node, document, beansJSON);
|
||||
assertNull(hint);
|
||||
}
|
||||
*/
|
||||
|
||||
private TextDocument createTempTextDocument(String docURI) throws Exception {
|
||||
Path path = Paths.get(new URI(docURI));
|
||||
String content = new String(Files.readAllBytes(path));
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*******************************************************************************
|
||||
* 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.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.LiveBean;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.LiveBeansModel;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class LiveBeansModelTest {
|
||||
|
||||
@Test
|
||||
public void testSimpleModel() throws Exception {
|
||||
String json = IOUtils.toString(ProjectsHarness.class.getResourceAsStream("/live-beans-models/simple-live-beans-model.json"));
|
||||
LiveBeansModel model = LiveBeansModel.parse(json);
|
||||
|
||||
LiveBean[] bean = model.getBeansOfType("org.test.DependencyA");
|
||||
assertEquals(1, bean.length);
|
||||
assertEquals("dependencyA", bean[0].getId());
|
||||
assertEquals("singleton", bean[0].getScope());
|
||||
assertEquals("org.test.DependencyA", bean[0].getType());
|
||||
assertEquals("file [/test-projects/classes/org/test/DependencyA.class]", bean[0].getResource());
|
||||
assertEquals(0, bean[0].getAliases().length);
|
||||
assertEquals(0, bean[0].getDependencies().length);
|
||||
|
||||
bean = model.getBeansOfName("dependencyB");
|
||||
assertEquals(1, bean.length);
|
||||
assertEquals("dependencyB", bean[0].getId());
|
||||
assertEquals("singleton", bean[0].getScope());
|
||||
assertEquals("org.test.DependencyB", bean[0].getType());
|
||||
assertEquals("file [/test-projects/classes/org/test/DependencyB.class]", bean[0].getResource());
|
||||
assertEquals(0, bean[0].getAliases().length);
|
||||
assertEquals(0, bean[0].getDependencies().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyModel() throws Exception {
|
||||
String json = IOUtils.toString(ProjectsHarness.class.getResourceAsStream("/live-beans-models/empty-live-beans-model.json"));
|
||||
LiveBeansModel model = LiveBeansModel.parse(json);
|
||||
|
||||
LiveBean[] bean = model.getBeansOfType("org.test.DependencyA");
|
||||
assertEquals(0, bean.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTotallyEmptyModel() throws Exception {
|
||||
String json = IOUtils.toString(ProjectsHarness.class.getResourceAsStream("/live-beans-models/totally-empty-live-beans-model.json"));
|
||||
LiveBeansModel model = LiveBeansModel.parse(json);
|
||||
|
||||
LiveBean[] bean = model.getBeansOfType("org.test.DependencyA");
|
||||
assertEquals(0, bean.length);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"context": "application",
|
||||
"parent": null,
|
||||
"beans": [
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,35 @@
|
||||
[
|
||||
{
|
||||
"context": "application",
|
||||
"parent": null,
|
||||
"beans": [
|
||||
{
|
||||
"bean": "dependencyA",
|
||||
"aliases": [],
|
||||
"scope": "singleton",
|
||||
"type": "org.test.DependencyA",
|
||||
"resource": "file [/test-projects/classes/org/test/DependencyA.class]",
|
||||
"dependencies": []
|
||||
},
|
||||
{
|
||||
"bean": "dependencyB",
|
||||
"aliases": [],
|
||||
"scope": "singleton",
|
||||
"type": "org.test.DependencyB",
|
||||
"resource": "file [/test-projects/classes/org/test/DependencyB.class]",
|
||||
"dependencies": []
|
||||
},
|
||||
{
|
||||
"bean": "myAutowiredComponent",
|
||||
"aliases": [],
|
||||
"scope": "singleton",
|
||||
"type": "org.test.MyAutowiredComponent",
|
||||
"resource": "file [/test-projects/classes/org/test/MyAutowiredComponent.class]",
|
||||
"dependencies": [
|
||||
"dependencyA",
|
||||
"dependencyB"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user