added bean wiring hover information for scanned functions without annotations involved

This commit is contained in:
Martin Lippert
2018-01-05 11:07:03 +01:00
parent 916ab89152
commit e79659abc7
13 changed files with 478 additions and 120 deletions

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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"+

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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`"
);
}
}