From 52ee072a0b3a6e9e6c1efe9d2ae93047779953b1 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Wed, 20 Sep 2017 11:19:23 +0200 Subject: [PATCH] PT #150797637: added initial support to extract specific symbols for function beans --- .../boot/java/beans/BeansSymbolProvider.java | 91 ++++++++++++++++--- .../utils/test/SpringIndexerBeansTest.java | 12 +++ .../src/main/java/org/test/FunctionClass.java | 16 ++++ 3 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 headless-services/boot-java-language-server/src/test/resources/test-projects/test-annotation-indexing-beans/src/main/java/org/test/FunctionClass.java diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java index 784884ba1..34163e053 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java @@ -10,13 +10,21 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.beans; +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; +import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.ParameterizedType; +import org.eclipse.jdt.core.dom.Type; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.SymbolInformation; import org.eclipse.lsp4j.SymbolKind; import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider; +import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.text.TextDocument; /** @@ -24,24 +32,19 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument; */ 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(); + @Override public SymbolInformation getSymbol(Annotation node, TextDocument doc) { try { - StringBuilder symbolLabel = new StringBuilder(); - symbolLabel.append("@+ "); - - String beanName = getBeanName(node); - String beanType = getBeanType(node); - - symbolLabel.append('\''); - symbolLabel.append(beanName); - symbolLabel.append('\''); - symbolLabel.append(" (@Bean) "); - symbolLabel.append(beanType); - - SymbolInformation symbol = new SymbolInformation(symbolLabel.toString(), SymbolKind.Interface, - new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()))); - return symbol; + if (isFunctionBean(node)) { + return createFunctionSymbol(node, doc); + } + else { + return createRegularBeanSymbol(node, doc); + } } catch (Exception e) { e.printStackTrace(); @@ -49,6 +52,64 @@ public class BeansSymbolProvider implements SymbolProvider { return null; } + private boolean isFunctionBean(Annotation node) { + ASTNode parent = node.getParent(); + if (parent instanceof MethodDeclaration) { + MethodDeclaration method = (MethodDeclaration) parent; + + String returnType = null; + if (method.getReturnType2().isParameterizedType()) { + ParameterizedType paramType = (ParameterizedType) method.getReturnType2(); + Type type = paramType.getType(); + ITypeBinding typeBinding = type.resolveBinding(); + returnType = typeBinding.getBinaryName(); + } + else { + returnType = method.getReturnType2().resolveBinding().getQualifiedName(); + } + + return FUNCTION_FUNCTION_TYPE.equals(returnType) || FUNCTION_CONSUMER_TYPE.equals(returnType) + || FUNCTION_SUPPLIER_TYPE.equals(returnType); + } + return false; + } + + private SymbolInformation createFunctionSymbol(Annotation node, TextDocument doc) throws BadLocationException { + StringBuilder symbolLabel = new StringBuilder(); + symbolLabel.append("@> "); + + String beanName = getBeanName(node); + String beanType = getBeanType(node); + + symbolLabel.append('\''); + symbolLabel.append(beanName); + symbolLabel.append('\''); + symbolLabel.append(" (@Bean) "); + symbolLabel.append(beanType); + + SymbolInformation symbol = new SymbolInformation(symbolLabel.toString(), SymbolKind.Interface, + new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()))); + return symbol; + } + + private SymbolInformation createRegularBeanSymbol(Annotation node, TextDocument doc) throws BadLocationException { + StringBuilder symbolLabel = new StringBuilder(); + symbolLabel.append("@+ "); + + String beanName = getBeanName(node); + String beanType = getBeanType(node); + + symbolLabel.append('\''); + symbolLabel.append(beanName); + symbolLabel.append('\''); + symbolLabel.append(" (@Bean) "); + symbolLabel.append(beanType); + + SymbolInformation symbol = new SymbolInformation(symbolLabel.toString(), SymbolKind.Interface, + new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()))); + return symbol; + } + private String getBeanName(Annotation node) { ASTNode parent = node.getParent(); if (parent instanceof MethodDeclaration) { diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerBeansTest.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerBeansTest.java index 39211dc8b..e7840b3f2 100644 --- a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerBeansTest.java +++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerBeansTest.java @@ -84,6 +84,18 @@ public class SpringIndexerBeansTest { assertTrue(containsSymbol(symbols, "@+ 'simpleBean' (@Bean) BeanClass", uriPrefix + "/src/main/java/org/test/SimpleConfiguration.java", 8, 1, 8, 8)); } + @Test + public void testScanSimpleFunctionBean() throws Exception { + SpringIndexer indexer = new SpringIndexer(harness.getServer(), projectFinder, symbolProviders); + File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-beans/").toURI()); + indexer.scanFiles(directory); + + String uriPrefix = "file://" + directory.getAbsolutePath(); + List symbols = indexer.getSymbols(uriPrefix + "/src/main/java/org/test/FunctionClass.java"); + assertEquals(2, symbols.size()); + assertTrue(containsSymbol(symbols, "@> 'uppercase' (@Bean) Function", uriPrefix + "/src/main/java/org/test/FunctionClass.java", 10, 1, 10, 6)); + } + @Test public void testScanSimpleComponentClass() throws Exception { SpringIndexer indexer = new SpringIndexer(harness.getServer(), projectFinder, symbolProviders); diff --git a/headless-services/boot-java-language-server/src/test/resources/test-projects/test-annotation-indexing-beans/src/main/java/org/test/FunctionClass.java b/headless-services/boot-java-language-server/src/test/resources/test-projects/test-annotation-indexing-beans/src/main/java/org/test/FunctionClass.java new file mode 100644 index 000000000..d4b51b165 --- /dev/null +++ b/headless-services/boot-java-language-server/src/test/resources/test-projects/test-annotation-indexing-beans/src/main/java/org/test/FunctionClass.java @@ -0,0 +1,16 @@ +package org.test; + +import java.util.function.Function; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class FunctionClass { + + @Bean + public Function uppercase() { + return str -> str.toUpperCase(); + } + +}