added bean wiring hover information for scanned functions without annotations involved
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 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
|
||||
@@ -42,7 +42,6 @@ import com.google.common.collect.ImmutableList;
|
||||
*/
|
||||
public class AutowiredHoverProvider implements HoverProvider {
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
try {
|
||||
@@ -164,4 +163,16 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(TypeDeclaration typeDeclaration, TextDocument doc,
|
||||
SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
package org.springframework.ide.vscode.boot.java.beans;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
@@ -28,6 +25,7 @@ import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.eclipse.lsp4j.SymbolKind;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.FunctionUtils;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
@@ -45,10 +43,6 @@ import reactor.util.function.Tuples;
|
||||
*/
|
||||
public class BeansSymbolProvider implements SymbolProvider {
|
||||
|
||||
private static final String FUNCTION_FUNCTION_TYPE = Function.class.getName();
|
||||
private static final String FUNCTION_CONSUMER_TYPE = Consumer.class.getName();
|
||||
private static final String FUNCTION_SUPPLIER_TYPE = Supplier.class.getName();
|
||||
|
||||
private static final String[] NAME_ATTRIBUTES = {"value", "name"};
|
||||
|
||||
@Override
|
||||
@@ -74,7 +68,7 @@ public class BeansSymbolProvider implements SymbolProvider {
|
||||
@Override
|
||||
public Collection<SymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc) {
|
||||
// this checks function beans that are defined as implementations of Function interfaces
|
||||
Tuple3<String, String, DocumentRegion> functionBean = getFunctionBean(typeDeclaration, doc);
|
||||
Tuple3<String, String, DocumentRegion> functionBean = FunctionUtils.getFunctionBean(typeDeclaration, doc);
|
||||
if (functionBean != null) {
|
||||
try {
|
||||
SymbolInformation symbol = new SymbolInformation(
|
||||
@@ -89,54 +83,6 @@ public class BeansSymbolProvider implements SymbolProvider {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
protected Tuple3<String, String, DocumentRegion> getFunctionBean(TypeDeclaration typeDeclaration, TextDocument doc) {
|
||||
ITypeBinding resolvedType = typeDeclaration.resolveBinding();
|
||||
if (resolvedType != null) {
|
||||
return getFunctionBean(typeDeclaration, doc, resolvedType);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Tuple3<String, String, DocumentRegion> getFunctionBean(TypeDeclaration typeDeclaration, TextDocument doc,
|
||||
ITypeBinding resolvedType) {
|
||||
|
||||
ITypeBinding[] interfaces = resolvedType.getInterfaces();
|
||||
for (ITypeBinding resolvedInterface : interfaces) {
|
||||
String simplifiedType = null;
|
||||
if (resolvedInterface.isParameterizedType()) {
|
||||
simplifiedType = resolvedInterface.getBinaryName();
|
||||
}
|
||||
else {
|
||||
simplifiedType = resolvedType.getQualifiedName();
|
||||
}
|
||||
|
||||
if (FUNCTION_FUNCTION_TYPE.equals(simplifiedType) || FUNCTION_CONSUMER_TYPE.equals(simplifiedType)
|
||||
|| FUNCTION_SUPPLIER_TYPE.equals(simplifiedType)) {
|
||||
String beanName = getBeanName(typeDeclaration);
|
||||
String beanType = resolvedInterface.getName();
|
||||
DocumentRegion region = ASTUtils.nodeRegion(doc, typeDeclaration.getName());
|
||||
|
||||
return Tuples.of(beanName, beanType, region);
|
||||
}
|
||||
else {
|
||||
Tuple3<String, String, DocumentRegion> result = getFunctionBean(typeDeclaration, doc, resolvedInterface);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ITypeBinding superclass = resolvedType.getSuperclass();
|
||||
if (superclass != null) {
|
||||
return getFunctionBean(typeDeclaration, doc, superclass);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected Collection<Tuple2<String, DocumentRegion>> getBeanNames(Annotation node, TextDocument doc) {
|
||||
Collection<StringLiteral> beanNameNodes = getBeanNameLiterals(node);
|
||||
|
||||
@@ -197,14 +143,6 @@ public class BeansSymbolProvider implements SymbolProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String getBeanName(TypeDeclaration typeDeclaration) {
|
||||
String beanName = typeDeclaration.getName().toString();
|
||||
if (beanName.length() > 0 && Character.isUpperCase(beanName.charAt(0))) {
|
||||
beanName = Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
|
||||
}
|
||||
return beanName;
|
||||
}
|
||||
|
||||
private boolean isFunctionBean(Annotation node) {
|
||||
ASTNode parent = node.getParent();
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
@@ -221,8 +159,8 @@ public class BeansSymbolProvider implements SymbolProvider {
|
||||
returnType = method.getReturnType2().resolveBinding().getQualifiedName();
|
||||
}
|
||||
|
||||
return FUNCTION_FUNCTION_TYPE.equals(returnType) || FUNCTION_CONSUMER_TYPE.equals(returnType)
|
||||
|| FUNCTION_SUPPLIER_TYPE.equals(returnType);
|
||||
return FunctionUtils.FUNCTION_FUNCTION_TYPE.equals(returnType) || FunctionUtils.FUNCTION_CONSUMER_TYPE.equals(returnType)
|
||||
|| FunctionUtils.FUNCTION_SUPPLIER_TYPE.equals(returnType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 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
|
||||
@@ -155,4 +155,16 @@ public class ConditionalsLiveHoverProvider implements HoverProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(TypeDeclaration typeDeclaration, TextDocument doc,
|
||||
SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 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
|
||||
@@ -22,7 +22,9 @@ import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MarkerAnnotation;
|
||||
import org.eclipse.jdt.core.dom.NodeFinder;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
@@ -86,10 +88,22 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
try {
|
||||
if (cu != null) {
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(TypeDeclaration node) {
|
||||
try {
|
||||
extractLiveHintsForType(node, document, runningBootApps, result);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SingleMemberAnnotation node) {
|
||||
try {
|
||||
extractLiveHints(node, document, runningBootApps, result);
|
||||
extractLiveHintsForAnnotation(node, document, runningBootApps, result);
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
@@ -100,7 +114,7 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation node) {
|
||||
try {
|
||||
extractLiveHints(node, document, runningBootApps, result);
|
||||
extractLiveHintsForAnnotation(node, document, runningBootApps, result);
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
@@ -111,7 +125,7 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
@Override
|
||||
public boolean visit(MarkerAnnotation node) {
|
||||
try {
|
||||
extractLiveHints(node, document, runningBootApps, result);
|
||||
extractLiveHintsForAnnotation(node, document, runningBootApps, result);
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
@@ -127,10 +141,29 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
});
|
||||
}
|
||||
|
||||
protected void extractLiveHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps, Collection<Range> result) {
|
||||
protected void extractLiveHintsForType(TypeDeclaration typeDeclaration, TextDocument doc, SpringBootApp[] runningApps, Collection<Range> result) {
|
||||
Collection<HoverProvider> providers = this.hoverProviders.getAll();
|
||||
if (!providers.isEmpty()) {
|
||||
for (HoverProvider provider : providers) {
|
||||
getProject(doc).ifPresent(project -> {
|
||||
if (hasActuatorDependency(project)) {
|
||||
Collection<Range> hints = provider.getLiveHoverHints(typeDeclaration, doc, runningApps);
|
||||
if (hints!=null) {
|
||||
result.addAll(hints);
|
||||
}
|
||||
} else {
|
||||
//Do nothing... we don't want a highlight for the 'no actuator warning'
|
||||
//ASTUtils.nameRange(doc, annotation).ifPresent(result::add);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void extractLiveHintsForAnnotation(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps, Collection<Range> result) {
|
||||
ITypeBinding type = annotation.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
if (runningApps.length>0) {
|
||||
if (runningApps.length > 0) {
|
||||
for (HoverProvider provider : this.hoverProviders.get(type)) {
|
||||
getProject(doc).ifPresent(project -> {
|
||||
if (hasActuatorDependency(project)) {
|
||||
@@ -154,7 +187,7 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
return server.getCompilationUnitCache().withCompilationUnit(document, cu -> {
|
||||
ASTNode node = NodeFinder.perform(cu, offset, 0);
|
||||
if (node != null) {
|
||||
return provideHoverForAnnotation(node, offset, document, project);
|
||||
return provideHover(node, offset, document, project);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
@@ -162,32 +195,42 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Hover provideHoverForAnnotation(ASTNode node, int offset, TextDocument doc, IJavaProject project) {
|
||||
Annotation annotation = null;
|
||||
private Hover provideHover(ASTNode node, int offset, TextDocument doc, IJavaProject project) {
|
||||
|
||||
while (node != null && !(node instanceof Annotation)) {
|
||||
node = node.getParent();
|
||||
// look for spring annotations first
|
||||
ASTNode annotationNode = node;
|
||||
while (annotationNode != null && !(annotationNode instanceof Annotation)) {
|
||||
annotationNode = annotationNode.getParent();
|
||||
}
|
||||
if (annotationNode != null) {
|
||||
return provideHoverForAnnotation(node, (Annotation) annotationNode, offset, doc, project);
|
||||
}
|
||||
|
||||
if (node != null) {
|
||||
annotation = (Annotation) node;
|
||||
ITypeBinding type = annotation.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
SpringBootApp[] runningApps = getRunningSpringApps(project);
|
||||
if (runningApps.length>0) {
|
||||
for (HoverProvider provider : this.hoverProviders.get(type)) {
|
||||
Hover hover = provider.provideHover(node, annotation, type, offset, doc, project, runningApps);
|
||||
if (hover!=null) {
|
||||
//TODO: compose multiple hovers somehow instead of just returning the first one?
|
||||
return hover;
|
||||
}
|
||||
// then do additional AST node coverage
|
||||
if (node instanceof SimpleName && node.getParent() instanceof TypeDeclaration) {
|
||||
return provideHoverForTypeDeclaration(node, (TypeDeclaration) node.getParent(), offset, doc, project);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Hover provideHoverForAnnotation(ASTNode exactNode, Annotation annotation, int offset, TextDocument doc, IJavaProject project) {
|
||||
ITypeBinding type = annotation.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
SpringBootApp[] runningApps = getRunningSpringApps(project);
|
||||
if (runningApps.length > 0) {
|
||||
for (HoverProvider provider : this.hoverProviders.get(type)) {
|
||||
Hover hover = provider.provideHover(exactNode, annotation, type, offset, doc, project, runningApps);
|
||||
if (hover!=null) {
|
||||
//TODO: compose multiple hovers somehow instead of just returning the first one?
|
||||
return hover;
|
||||
}
|
||||
//Only reaching here if we didn't get a hover.
|
||||
if (!hasActuatorDependency(project)) {
|
||||
DocumentRegion region = ASTUtils.nameRegion(doc, annotation);
|
||||
if (region.containsOffset(offset)) {
|
||||
return actuatorWarning(project);
|
||||
}
|
||||
}
|
||||
//Only reaching here if we didn't get a hover.
|
||||
if (!hasActuatorDependency(project)) {
|
||||
DocumentRegion region = ASTUtils.nameRegion(doc, annotation);
|
||||
if (region.containsOffset(offset)) {
|
||||
return actuatorWarning(project);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,6 +238,22 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Hover provideHoverForTypeDeclaration(ASTNode exactNode, TypeDeclaration typeDeclaration, int offset, TextDocument doc, IJavaProject project) {
|
||||
SpringBootApp[] runningApps = getRunningSpringApps(project);
|
||||
if (runningApps.length > 0) {
|
||||
ITypeBinding type = typeDeclaration.resolveBinding();
|
||||
|
||||
for (HoverProvider provider : this.hoverProviders.getAll()) {
|
||||
Hover hover = provider.provideHover(exactNode, typeDeclaration, type, offset, doc, project, runningApps);
|
||||
if (hover!=null) {
|
||||
//TODO: compose multiple hovers somehow instead of just returning the first one?
|
||||
return hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Hover actuatorWarning(IJavaProject project) {
|
||||
String hoverText =
|
||||
"**No live hover information available**.\n"+
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 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
|
||||
@@ -15,6 +15,7 @@ import java.util.Collection;
|
||||
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.Range;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
@@ -27,6 +28,9 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
public interface HoverProvider {
|
||||
|
||||
Hover provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset, TextDocument doc, IJavaProject project, SpringBootApp[] runningApps);
|
||||
Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset, TextDocument doc, IJavaProject project, SpringBootApp[] runningApps);
|
||||
|
||||
Collection<Range> getLiveHoverHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps);
|
||||
Collection<Range> getLiveHoverHints(TypeDeclaration typeDeclaration, TextDocument doc, SpringBootApp[] runningApps);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 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
|
||||
@@ -22,6 +22,7 @@ import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
@@ -132,4 +133,17 @@ public class ActiveProfilesProvider implements HoverProvider {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(TypeDeclaration typeDeclaration, TextDocument doc,
|
||||
SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 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
|
||||
@@ -10,13 +10,22 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
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.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
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.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.Optionals;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProvider {
|
||||
|
||||
@@ -61,4 +70,16 @@ public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProv
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(TypeDeclaration typeDeclaration, TextDocument doc,
|
||||
SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 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
|
||||
@@ -10,19 +10,36 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.FunctionUtils;
|
||||
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.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.util.function.Tuple3;
|
||||
|
||||
public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverProvider {
|
||||
|
||||
@@ -76,6 +93,10 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
public static LiveBean getDefinedBeanForComponent(Annotation annotation) {
|
||||
//Move to ASTUtils?
|
||||
TypeDeclaration declaringType = ASTUtils.getAnnotatedType(annotation);
|
||||
return getDefinedBeanForType(declaringType, annotation);
|
||||
}
|
||||
|
||||
private static LiveBean getDefinedBeanForType(TypeDeclaration declaringType, Annotation annotation) {
|
||||
if (declaringType != null) {
|
||||
ITypeBinding beanType = declaringType.resolveBinding();
|
||||
if (beanType != null) {
|
||||
@@ -106,4 +127,63 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(TypeDeclaration typeDeclaration, TextDocument doc,
|
||||
SpringBootApp[] runningApps) {
|
||||
Tuple3<String, String, DocumentRegion> functionBean = FunctionUtils.getFunctionBean(typeDeclaration, doc);
|
||||
if (functionBean != null && runningApps.length > 0) {
|
||||
try {
|
||||
LiveBean definedBean = getDefinedBeanForType(typeDeclaration, null);
|
||||
if (definedBean != null) {
|
||||
if (Stream.of(runningApps).anyMatch(app -> LiveHoverUtils.hasRelevantBeans(app, definedBean))) {
|
||||
Optional<Range> nameRange = Optional.of(ASTUtils.nodeRegion(doc, typeDeclaration.getName()).asRange());
|
||||
if (nameRange.isPresent()) {
|
||||
return ImmutableList.of(nameRange.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
|
||||
Tuple3<String, String, DocumentRegion> functionBean = FunctionUtils.getFunctionBean(typeDeclaration, doc);
|
||||
if (functionBean != null && runningApps.length > 0) {
|
||||
|
||||
LiveBean definedBean = getDefinedBeanForType(typeDeclaration, null);
|
||||
if (definedBean != null) {
|
||||
StringBuilder hover = new StringBuilder();
|
||||
hover.append("**Injection report for " + LiveHoverUtils.showBean(definedBean) + "**\n\n");
|
||||
|
||||
boolean hasInterestingApp = 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) + ":");
|
||||
|
||||
for (LiveBean bean : relevantBeans) {
|
||||
addInjectedInto(definedBean, hover, beans, bean, project);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasInterestingApp) {
|
||||
return new Hover(ImmutableList.of(Either.forLeft(hover.toString())));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 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
|
||||
@@ -22,6 +22,7 @@ import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.IMethodBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
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;
|
||||
@@ -178,4 +179,17 @@ public class RequestMappingHoverProvider implements HoverProvider {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(TypeDeclaration typeDeclaration, TextDocument doc,
|
||||
SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 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
|
||||
@@ -77,26 +77,28 @@ public class ASTUtils {
|
||||
}
|
||||
|
||||
public static Optional<Expression> getAttribute(Annotation annotation, String name) {
|
||||
try {
|
||||
if (annotation.isSingleMemberAnnotation() && name.equals("value")) {
|
||||
SingleMemberAnnotation sma = (SingleMemberAnnotation) annotation;
|
||||
return Optional.ofNullable(sma.getValue());
|
||||
} else if (annotation.isNormalAnnotation()) {
|
||||
NormalAnnotation na = (NormalAnnotation) annotation;
|
||||
Object attributeObjs = na.getStructuralProperty(NormalAnnotation.VALUES_PROPERTY);
|
||||
if (attributeObjs instanceof List) {
|
||||
for (Object atrObj : (List<?>)attributeObjs) {
|
||||
if (atrObj instanceof MemberValuePair) {
|
||||
MemberValuePair mvPair = (MemberValuePair) atrObj;
|
||||
if (name.equals(mvPair.getName().getIdentifier())) {
|
||||
return Optional.ofNullable(mvPair.getValue());
|
||||
if (annotation != null) {
|
||||
try {
|
||||
if (annotation.isSingleMemberAnnotation() && name.equals("value")) {
|
||||
SingleMemberAnnotation sma = (SingleMemberAnnotation) annotation;
|
||||
return Optional.ofNullable(sma.getValue());
|
||||
} else if (annotation.isNormalAnnotation()) {
|
||||
NormalAnnotation na = (NormalAnnotation) annotation;
|
||||
Object attributeObjs = na.getStructuralProperty(NormalAnnotation.VALUES_PROPERTY);
|
||||
if (attributeObjs instanceof List) {
|
||||
for (Object atrObj : (List<?>)attributeObjs) {
|
||||
if (atrObj instanceof MemberValuePair) {
|
||||
MemberValuePair mvPair = (MemberValuePair) atrObj;
|
||||
if (name.equals(mvPair.getName().getIdentifier())) {
|
||||
return Optional.ofNullable(mvPair.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import reactor.util.function.Tuple3;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
public class FunctionUtils {
|
||||
|
||||
public static final String FUNCTION_FUNCTION_TYPE = Function.class.getName();
|
||||
public static final String FUNCTION_CONSUMER_TYPE = Consumer.class.getName();
|
||||
public static final String FUNCTION_SUPPLIER_TYPE = Supplier.class.getName();
|
||||
|
||||
public static Tuple3<String, String, DocumentRegion> getFunctionBean(TypeDeclaration typeDeclaration, TextDocument doc) {
|
||||
ITypeBinding resolvedType = typeDeclaration.resolveBinding();
|
||||
if (resolvedType != null) {
|
||||
return getFunctionBean(typeDeclaration, doc, resolvedType);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Tuple3<String, String, DocumentRegion> getFunctionBean(TypeDeclaration typeDeclaration, TextDocument doc,
|
||||
ITypeBinding resolvedType) {
|
||||
|
||||
ITypeBinding[] interfaces = resolvedType.getInterfaces();
|
||||
for (ITypeBinding resolvedInterface : interfaces) {
|
||||
String simplifiedType = null;
|
||||
if (resolvedInterface.isParameterizedType()) {
|
||||
simplifiedType = resolvedInterface.getBinaryName();
|
||||
}
|
||||
else {
|
||||
simplifiedType = resolvedType.getQualifiedName();
|
||||
}
|
||||
|
||||
if (FUNCTION_FUNCTION_TYPE.equals(simplifiedType) || FUNCTION_CONSUMER_TYPE.equals(simplifiedType)
|
||||
|| FUNCTION_SUPPLIER_TYPE.equals(simplifiedType)) {
|
||||
String beanName = getBeanName(typeDeclaration);
|
||||
String beanType = resolvedInterface.getName();
|
||||
DocumentRegion region = ASTUtils.nodeRegion(doc, typeDeclaration.getName());
|
||||
|
||||
return Tuples.of(beanName, beanType, region);
|
||||
}
|
||||
else {
|
||||
Tuple3<String, String, DocumentRegion> result = getFunctionBean(typeDeclaration, doc, resolvedInterface);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ITypeBinding superclass = resolvedType.getSuperclass();
|
||||
if (superclass != null) {
|
||||
return getFunctionBean(typeDeclaration, doc, superclass);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected static String getBeanName(TypeDeclaration typeDeclaration) {
|
||||
String beanName = typeDeclaration.getName().toString();
|
||||
if (beanName.length() > 0 && Character.isUpperCase(beanName.charAt(0))) {
|
||||
beanName = Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
|
||||
}
|
||||
return beanName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 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
|
||||
@@ -21,6 +21,7 @@ import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.NodeFinder;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
@@ -199,4 +200,16 @@ public class ValueHoverProvider implements HoverProvider {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(TypeDeclaration typeDeclaration, TextDocument doc,
|
||||
SpringBootApp[] runningApps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover.test;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
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.maven.java.MavenJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.MockRunningAppProvider;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
|
||||
public class FunctionInjectionsHoverProviderTest {
|
||||
|
||||
private BootLanguageServerHarness harness;
|
||||
private ProjectsHarness projects = ProjectsHarness.INSTANCE;
|
||||
|
||||
private MockRunningAppProvider mockAppProvider;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
mockAppProvider = new MockRunningAppProvider();
|
||||
harness = BootLanguageServerHarness.builder()
|
||||
.mockDefaults()
|
||||
.runningAppProvider(mockAppProvider.provider)
|
||||
.watchDogInterval(Duration.ofMillis(100))
|
||||
.build();
|
||||
|
||||
MavenJavaProject jp = projects.mavenProject("empty-boot-15-web-app");
|
||||
harness.useProject(jp);
|
||||
harness.intialize(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void componentWithNoInjections() throws Exception {
|
||||
LiveBeansModel beans = LiveBeansModel.builder()
|
||||
.add(LiveBean.builder()
|
||||
.id("scannedFunctionClass")
|
||||
.type("com.example.ScannedFunctionClass")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration")
|
||||
.type("org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration")
|
||||
.dependencies("scannedFunctionClass")
|
||||
.build()
|
||||
)
|
||||
.add(LiveBean.builder()
|
||||
.id("irrelevantBean")
|
||||
.type("com.example.IrrelevantBean")
|
||||
.dependencies("myController")
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
mockAppProvider.builder()
|
||||
.isSpringBootApp(true)
|
||||
.processId("111")
|
||||
.processName("the-app")
|
||||
.beans(beans)
|
||||
.build();
|
||||
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA,
|
||||
"package com.example;\n" +
|
||||
"\n" +
|
||||
"import java.util.function.Function;\n" +
|
||||
"\n" +
|
||||
"public class ScannedFunctionClass implements Function<String, String> {\n" +
|
||||
"\n" +
|
||||
" @Override\n" +
|
||||
" public String apply(String t) {\n" +
|
||||
" return t.toUpperCase();\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
"}\n" +
|
||||
""
|
||||
);
|
||||
editor.assertHighlights("ScannedFunctionClass");
|
||||
editor.assertTrimmedHover("ScannedFunctionClass",
|
||||
"**Injection report for Bean [id: scannedFunctionClass, type: `com.example.ScannedFunctionClass`]**\n" +
|
||||
"\n" +
|
||||
"Process [PID=111, name=`the-app`]:\n" +
|
||||
"\n" +
|
||||
"Bean [id: scannedFunctionClass, type: `com.example.ScannedFunctionClass`] injected into:\n" +
|
||||
"\n" +
|
||||
"- Bean: org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration \n" +
|
||||
" Type: `org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration`"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user