diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerBootApp.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerBootApp.java index d546f7cd9..13dcf6ff7 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerBootApp.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerBootApp.java @@ -41,6 +41,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.ide.vscode.boot.common.PropertyCompletionFactory; import org.springframework.ide.vscode.boot.common.RelaxedNameConfig; import org.springframework.ide.vscode.boot.java.JavaDefinitionHandler; +import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.handlers.BootJavaCodeActionProvider; import org.springframework.ide.vscode.boot.java.handlers.BootJavaProjectReconcilerScheduler; import org.springframework.ide.vscode.boot.java.handlers.BootJavaReconcileEngine; @@ -143,6 +144,11 @@ public class BootLanguageServerBootApp { return new SymbolCacheVoid(); } } + + @Bean + SpringMetamodelIndex springMetamodelIndex() { + return new SpringMetamodelIndex(); + } @Bean SpringProcessLiveDataProvider liveDataProvider(SimpleLanguageServer server) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndexerConfig.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndexerConfig.java index 6133806a5..2870699b2 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndexerConfig.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndexerConfig.java @@ -12,6 +12,7 @@ package org.springframework.ide.vscode.boot.app; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareLookup; import org.springframework.ide.vscode.boot.java.beans.BeansSymbolProvider; @@ -27,11 +28,11 @@ import org.springframework.ide.vscode.boot.java.utils.SymbolCache; public class SpringSymbolIndexerConfig { @Bean - AnnotationHierarchyAwareLookup symbolProviders(SymbolCache cache) { + AnnotationHierarchyAwareLookup symbolProviders(SymbolCache cache, SpringMetamodelIndex springIndex) { AnnotationHierarchyAwareLookup providers = new AnnotationHierarchyAwareLookup<>(); RequestMappingSymbolProvider requestMappingSymbolProvider = new RequestMappingSymbolProvider(); - BeansSymbolProvider beansSymbolProvider = new BeansSymbolProvider(); - ComponentSymbolProvider componentSymbolProvider = new ComponentSymbolProvider(); + BeansSymbolProvider beansSymbolProvider = new BeansSymbolProvider(springIndex); + ComponentSymbolProvider componentSymbolProvider = new ComponentSymbolProvider(springIndex); RestrictedDefaultSymbolProvider restrictedDefaultSymbolProvider = new RestrictedDefaultSymbolProvider(); DataRepositorySymbolProvider dataRepositorySymbolProvider = new DataRepositorySymbolProvider(); WebfluxRouterSymbolProvider webfluxRouterSymbolProvider = new WebfluxRouterSymbolProvider(); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/Bean.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/Bean.java new file mode 100644 index 000000000..077d9bf25 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/Bean.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2032 VMware, 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.index; + +import org.eclipse.lsp4j.Location; + +public class Bean { + + private final String name; + private final String type; + private final Location location; + private final InjectionPoint[] injectionPoints; + + public Bean(String name, String type, Location location, InjectionPoint[] injectionPoints) { + this.name = name; + this.type = type; + this.location = location; + + this.injectionPoints = injectionPoints; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public Location getLocation() { + return location; + } + + public InjectionPoint[] getInjectionPoints() { + return injectionPoints; + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/InjectionPoint.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/InjectionPoint.java new file mode 100644 index 000000000..70ea4bf13 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/InjectionPoint.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2032 VMware, 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.index; + +import org.eclipse.lsp4j.Location; + +public class InjectionPoint { + + private final String name; + private final String type; + private final Location location; + + public InjectionPoint(String name, String type, Location location) { + super(); + this.name = name; + this.type = type; + this.location = location; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public Location getLocation() { + return location; + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java new file mode 100644 index 000000000..10380b55e --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2032 VMware, 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.index; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.eclipse.lsp4j.Location; + +public class SpringMetamodelIndex { + + private List beans; + + public SpringMetamodelIndex() { + this.beans = new ArrayList<>(); + } + + public Bean[] getBeans(String name) { + return this.beans.stream().filter(bean -> bean.getName().equals(name)).collect(Collectors.toList()).toArray(new Bean[0]); + } + + public void registerBean(String name, String type, Location location, InjectionPoint[] injectionPoints) { + Bean bean = new Bean(name, type, location, injectionPoints); + this.beans.add(bean); + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java index 65d06f5b6..019a03376 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2022 Pivotal, Inc. + * Copyright (c) 2017, 2023 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,6 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.beans; +import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -23,12 +24,16 @@ import org.eclipse.jdt.core.dom.ParameterizedType; import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclaration; import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.SymbolKind; import org.eclipse.lsp4j.WorkspaceSymbol; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.ide.vscode.boot.index.InjectionPoint; +import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; @@ -58,6 +63,12 @@ public class BeansSymbolProvider extends AbstractSymbolProvider { private static final String[] NAME_ATTRIBUTES = {"value", "name"}; + private final SpringMetamodelIndex springIndex; + + public BeansSymbolProvider(SpringMetamodelIndex springIndex) { + this.springIndex = springIndex; + } + @Override protected void addSymbolsPass1(Annotation node, ITypeBinding annotationType, Collection metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) { if (isMethodAbstract(node)) return; @@ -67,15 +78,20 @@ public class BeansSymbolProvider extends AbstractSymbolProvider { String markerString = getAnnotations(node); for (Tuple2 nameAndRegion : getBeanNames(node, doc)) { try { + Location location = new Location(doc.getUri(), doc.toRange(nameAndRegion.getT2())); + EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation( new WorkspaceSymbol( beanLabel(isFunction, nameAndRegion.getT1(), beanType.getName(), "@Bean" + markerString), SymbolKind.Interface, - Either.forLeft(new Location(doc.getUri(), doc.toRange(nameAndRegion.getT2())))), + Either.forLeft(location)), new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(nameAndRegion.getT1(), beanType.getQualifiedName())} ); context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)); + + InjectionPoint[] injectionPoints = findInjectionPoints(node, doc); + springIndex.registerBean(nameAndRegion.getT1(), beanType.getQualifiedName(), location, injectionPoints); } catch (BadLocationException e) { log.error("", e); @@ -83,6 +99,18 @@ public class BeansSymbolProvider extends AbstractSymbolProvider { } } + private InjectionPoint[] findInjectionPoints(Annotation node, TextDocument doc) throws BadLocationException { + List result = new ArrayList<>(); + + ASTNode parent = node.getParent(); + if (parent instanceof MethodDeclaration) { + MethodDeclaration method = (MethodDeclaration) parent; + result.addAll(ASTUtils.getInjectionPointsFromMethodParams(method, doc)); + } + + return (InjectionPoint[]) result.toArray(new InjectionPoint[result.size()]); + } + @Override protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) { // this checks function beans that are defined as implementations of Function interfaces diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java index a90e9722b..0e5323bf8 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java @@ -10,27 +10,37 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.beans; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.stream.Collectors; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; +import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.SymbolKind; import org.eclipse.lsp4j.WorkspaceSymbol; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.ide.vscode.boot.index.InjectionPoint; +import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; +import org.springframework.ide.vscode.boot.java.utils.ASTUtils; import org.springframework.ide.vscode.boot.java.utils.CachedSymbol; import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext; import org.springframework.ide.vscode.commons.util.BadLocationException; +import org.springframework.ide.vscode.commons.util.text.DocumentRegion; import org.springframework.ide.vscode.commons.util.text.TextDocument; /** @@ -41,6 +51,12 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider { private static final Logger log = LoggerFactory.getLogger(ComponentSymbolProvider.class); + private final SpringMetamodelIndex springIndex; + + public ComponentSymbolProvider(SpringMetamodelIndex springIndex) { + this.springIndex = springIndex; + } + @Override protected void addSymbolsPass1(Annotation node, ITypeBinding annotationType, Collection metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) { try { @@ -62,9 +78,11 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider { String beanName = getBeanName(node); ITypeBinding beanType = getBeanType(node); + Location location = new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength())); + WorkspaceSymbol symbol = new WorkspaceSymbol( beanLabel("+", annotationTypeName, metaAnnotationNames, beanName, beanType.getName()), SymbolKind.Interface, - Either.forLeft(new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength())))); + Either.forLeft(location)); SymbolAddOnInformation[] addon = new SymbolAddOnInformation[0]; if (Annotations.CONFIGURATION.equals(annotationType.getQualifiedName()) @@ -73,10 +91,68 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider { } else { addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(beanName, beanType.getQualifiedName())}; } + + InjectionPoint[] injectionPoints = findInjectionPoints(node, doc); + springIndex.registerBean(beanName, beanType.getQualifiedName(), location, injectionPoints); return new EnhancedSymbolInformation(symbol, addon); } + private InjectionPoint[] findInjectionPoints(Annotation node, TextDocument doc) throws BadLocationException { + List result = new ArrayList<>(); + + ASTNode parent = node.getParent(); + if (parent instanceof TypeDeclaration) { + TypeDeclaration type = (TypeDeclaration) parent; + + MethodDeclaration[] methods = type.getMethods(); + for (MethodDeclaration method : methods) { + if (method.isConstructor()) { + result.addAll(ASTUtils.getInjectionPointsFromMethodParams(method, doc)); + } + } + + FieldDeclaration[] fields = type.getFields(); + for (FieldDeclaration field : fields) { + + boolean autowiredField = false; + + List modifiers = field.modifiers(); + for (Object modifier : modifiers) { + if (modifier instanceof Annotation) { + Annotation annotation = (Annotation) modifier; + + String qualifiedName = annotation.resolveTypeBinding().getQualifiedName(); + if (Annotations.AUTOWIRED.equals(qualifiedName)) { + autowiredField = true; + } + } + } + + + if (autowiredField) { + List fragments = field.fragments(); + for (Object fragment : fragments) { + if (fragment instanceof VariableDeclarationFragment) { + VariableDeclarationFragment varFragment = (VariableDeclarationFragment) fragment; + String fieldName = varFragment.getName().toString(); + + DocumentRegion region = ASTUtils.nodeRegion(doc, varFragment.getName()); + Range range = doc.toRange(region); + Location fieldLocation = new Location(doc.getUri(), range); + + String fieldType = field.getType().resolveBinding().getQualifiedName(); + + result.add(new InjectionPoint(fieldName, fieldType, fieldLocation)); + } + } + } + } + } + + return (InjectionPoint[]) result.toArray(new InjectionPoint[result.size()]); + } + protected String beanLabel(String searchPrefix, String annotationTypeName, Collection metaAnnotationNames, String beanName, String beanType) { StringBuilder symbolLabel = new StringBuilder(); symbolLabel.append("@"); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java index 08a4554dc..c042f5b59 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.utils; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; @@ -34,12 +35,16 @@ import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclaration; +import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Range; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.ide.vscode.boot.index.InjectionPoint; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.jdt.imports.ImportRewrite; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.CollectorUtil; import org.springframework.ide.vscode.commons.util.text.DocumentRegion; import org.springframework.ide.vscode.commons.util.text.IDocument; @@ -319,4 +324,24 @@ public class ASTUtils { return edit != null ? Optional.of(edit) : Optional.empty(); } + public static Collection getInjectionPointsFromMethodParams(MethodDeclaration method, TextDocument doc) throws BadLocationException { + List result = new ArrayList<>(); + + List parameters = method.parameters(); + for (Object object : parameters) { + if (object instanceof VariableDeclaration) { + VariableDeclaration variable = (VariableDeclaration) object; + String name = variable.getName().toString(); + String type = variable.resolveBinding().getType().getQualifiedName(); + + DocumentRegion region = ASTUtils.nodeRegion(doc, variable.getName()); + Range range = doc.toRange(region); + + Location location = new Location(doc.getUri(), range); + result.add(new InjectionPoint(name, type, location)); + } + } + return result; + } + } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metamodel/test/SpringMetamodelIndexerBeansTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metamodel/test/SpringMetamodelIndexerBeansTest.java new file mode 100644 index 000000000..a23574fa5 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metamodel/test/SpringMetamodelIndexerBeansTest.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2023 VMware, 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.metamodel.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.io.File; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.TextDocumentIdentifier; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Import; +import org.springframework.ide.vscode.boot.app.SpringSymbolIndex; +import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest; +import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf; +import org.springframework.ide.vscode.boot.index.Bean; +import org.springframework.ide.vscode.boot.index.InjectionPoint; +import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness; +import org.springframework.ide.vscode.project.harness.ProjectsHarness; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +/** + * @author Martin Lippert + */ +@ExtendWith(SpringExtension.class) +@BootLanguageServerTest +@Import(SymbolProviderTestConf.class) +public class SpringMetamodelIndexerBeansTest { + + @Autowired + private BootLanguageServerHarness harness; + @Autowired + private JavaProjectFinder projectFinder; + + private File directory; + @Autowired + private SpringMetamodelIndex springIndex; + @Autowired + private SpringSymbolIndex indexer; + + @BeforeEach + public void setup() throws Exception { + harness.intialize(null); + + directory = new File(ProjectsHarness.class.getResource("/test-projects/test-spring-indexing/").toURI()); + + String projectDir = directory.toURI().toString(); + + // trigger project creation + projectFinder.find(new TextDocumentIdentifier(projectDir)).get(); + + CompletableFuture initProject = indexer.waitOperation(); + initProject.get(5, TimeUnit.SECONDS); + } + + @Test + void testSpringIndexExists() throws Exception { + assertNotNull(springIndex); + } + + @Test + void testBeansNameAndTypeFromBeanAnnotatedMethod() { + Bean[] beans = springIndex.getBeans("bean1"); + + assertEquals(1, beans.length); + assertEquals("bean1", beans[0].getName()); + assertEquals("org.test.BeanClass1", beans[0].getType()); + } + + @Test + void testBeansNameAndTypeFromComponentAnnotatedClassExists() { + Bean[] beans = springIndex.getBeans("constructorInjectionService"); + + assertEquals(1, beans.length); + assertEquals("constructorInjectionService", beans[0].getName()); + assertEquals("org.test.injections.ConstructorInjectionService", beans[0].getType()); + } + + @Test + void testBeansNameAndTypeFromConfigurationAnnotatedClassExists() { + Bean[] beans = springIndex.getBeans("configurationWithoutInjection"); + + assertEquals(1, beans.length); + assertEquals("configurationWithoutInjection", beans[0].getName()); + assertEquals("org.test.injections.ConfigurationWithoutInjection", beans[0].getType()); + } + + @Test + void testBeansDefintionLocationFromBeanAnnotatedMethod() { + Bean[] beans = springIndex.getBeans("bean1"); + + String docUri = directory.toPath().resolve("src/main/java/org/test/MainClass.java").toUri().toString(); + Location location = new Location(docUri, new Range(new Position(13, 1), new Position(13, 6))); + assertEquals(location, beans[0].getLocation()); + } + + @Test + void testBeansDefintionLocationFromComponentAnnotatedClass() { + Bean[] beans = springIndex.getBeans("constructorInjectionService"); + + String docUri = directory.toPath().resolve("src/main/java/org/test/injections/ConstructorInjectionService.java").toUri().toString(); + Location location = new Location(docUri, new Range(new Position(6, 0), new Position(6, 8))); + assertEquals(location, beans[0].getLocation()); + } + + @Test + void testBeansDefinitionLocationFromConfigurationAnnotatedClass() { + Bean[] beans = springIndex.getBeans("configurationWithoutInjection"); + assertEquals(1, beans.length); + + String docUri = directory.toPath().resolve("src/main/java/org/test/injections/ConfigurationWithoutInjection.java").toUri().toString(); + assertEquals(docUri, beans[0].getLocation().getUri()); + } + + @Test + void testBeanNoInjectionPointsFromBeanAnnotatedMethod() { + Bean[] beans = springIndex.getBeans("beanWithoutInjections"); + assertEquals(1, beans.length); + + InjectionPoint[] injectionPoints = beans[0].getInjectionPoints(); + assertEquals(0, injectionPoints.length); + } + + @Test + void testBeanInjectionPointsFromBeanAnnotatedMethod() { + Bean[] beans = springIndex.getBeans("manualBeanWithConstructor"); + assertEquals(1, beans.length); + + String docUri = directory.toPath().resolve("src/main/java/org/test/injections/ConfigurationWithInjections.java").toUri().toString(); + + InjectionPoint[] injectionPoints = beans[0].getInjectionPoints(); + assertEquals(2, injectionPoints.length); + + assertEquals("bean1", injectionPoints[0].getName()); + assertEquals("org.test.BeanClass1", injectionPoints[0].getType()); + Location ip1Location = new Location(docUri, new Range(new Position(12, 73), new Position(12, 78))); + assertEquals(ip1Location, injectionPoints[0].getLocation()); + + assertEquals("bean2", injectionPoints[1].getName()); + assertEquals("org.test.BeanClass2", injectionPoints[1].getType()); + Location ip2Location = new Location(docUri, new Range(new Position(12, 91), new Position(12, 96))); + assertEquals(ip2Location, injectionPoints[1].getLocation()); + } + + @Test + void testBeanInjectionPointsFromConstructor() { + Bean[] beans = springIndex.getBeans("constructorInjectionService"); + assertEquals(1, beans.length); + + String docUri = directory.toPath().resolve("src/main/java/org/test/injections/ConstructorInjectionService.java").toUri().toString(); + + InjectionPoint[] injectionPoints = beans[0].getInjectionPoints(); + assertEquals(2, injectionPoints.length); + + assertEquals("bean1", injectionPoints[0].getName()); + assertEquals("org.test.BeanClass1", injectionPoints[0].getType()); + Location ip1Location = new Location(docUri, new Range(new Position(12, 47), new Position(12, 52))); + assertEquals(ip1Location, injectionPoints[0].getLocation()); + + assertEquals("bean2", injectionPoints[1].getName()); + assertEquals("org.test.BeanClass2", injectionPoints[1].getType()); + Location ip2Location = new Location(docUri, new Range(new Position(12, 65), new Position(12, 70))); + assertEquals(ip2Location, injectionPoints[1].getLocation()); + } + + @Test + void testBeanInjectionPointsFromAutowiredFields() { + Bean[] beans = springIndex.getBeans("autowiredInjectionService"); + assertEquals(1, beans.length); + + String docUri = directory.toPath().resolve("src/main/java/org/test/injections/AutowiredInjectionService.java").toUri().toString(); + + InjectionPoint[] injectionPoints = beans[0].getInjectionPoints(); + assertEquals(2, injectionPoints.length); + + assertEquals("bean1", injectionPoints[0].getName()); + assertEquals("org.test.BeanClass1", injectionPoints[0].getType()); + Location ip1Location = new Location(docUri, new Range(new Position(10, 31), new Position(10, 36))); + assertEquals(ip1Location, injectionPoints[0].getLocation()); + + assertEquals("bean2", injectionPoints[1].getName()); + assertEquals("org.test.BeanClass2", injectionPoints[1].getType()); + Location ip2Location = new Location(docUri, new Range(new Position(11, 31), new Position(11, 36))); + assertEquals(ip2Location, injectionPoints[1].getLocation()); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/mvnw b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/mvnw new file mode 100755 index 000000000..02217b1ec --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/mvnw @@ -0,0 +1,233 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # + # Look for the Apple JDKs first to preserve the existing behaviour, and then look + # for the new JDKs provided by Oracle. + # + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then + # + # Oracle JDKs + # + export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then + # + # Apple JDKs + # + export JAVA_HOME=`/usr/libexec/java_home` + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + local basedir=$(pwd) + local wdir=$(pwd) + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + wdir=$(cd "$wdir/.."; pwd) + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} "$@" diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/mvnw.cmd b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/mvnw.cmd new file mode 100644 index 000000000..4b98b78c4 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/mvnw.cmd @@ -0,0 +1,145 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%* + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% \ No newline at end of file diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/pom.xml b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/pom.xml new file mode 100644 index 000000000..dacc19bc6 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + com.example + test-spring-indexing + 0.0.1-SNAPSHOT + jar + + + org.springframework.boot + spring-boot-starter-parent + 2.7.8 + + + + + UTF-8 + UTF-8 + 17 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + + diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/BeanClass1.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/BeanClass1.java new file mode 100644 index 000000000..4e4f76fb5 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/BeanClass1.java @@ -0,0 +1,5 @@ +package org.test; + +public class BeanClass1 { + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/BeanClass2.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/BeanClass2.java new file mode 100644 index 000000000..45b3c3cba --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/BeanClass2.java @@ -0,0 +1,5 @@ +package org.test; + +public class BeanClass2 { + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/MainClass.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/MainClass.java new file mode 100644 index 000000000..cc4fd96b4 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/MainClass.java @@ -0,0 +1,24 @@ +package org.test; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class MainClass { + + public static void main(String[] args) throws Exception { + SpringApplication.run(MainClass.class, args); + } + + @Bean + BeanClass1 bean1() { + return new BeanClass1(); + } + + @Bean + BeanClass2 bean2() { + return new BeanClass2(); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/ManuallyCreatedBeanWithConstructor.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/ManuallyCreatedBeanWithConstructor.java new file mode 100644 index 000000000..1ea940136 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/ManuallyCreatedBeanWithConstructor.java @@ -0,0 +1,21 @@ +package org.test; + +public class ManuallyCreatedBeanWithConstructor { + + private BeanClass1 bean1; + private BeanClass2 bean2; + + public ManuallyCreatedBeanWithConstructor(BeanClass1 bean1, BeanClass2 bean2) { + this.bean1 = bean1; + this.bean2 = bean2; + } + + public BeanClass1 getBean1() { + return bean1; + } + + public BeanClass2 getBean2() { + return bean2; + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/AutowiredInjectionService.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/AutowiredInjectionService.java new file mode 100644 index 000000000..e2b91394e --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/AutowiredInjectionService.java @@ -0,0 +1,22 @@ +package org.test.injections; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.test.BeanClass1; +import org.test.BeanClass2; + +@Service +public class AutowiredInjectionService { + + @Autowired private BeanClass1 bean1; + @Autowired private BeanClass2 bean2; + + public BeanClass1 getBean1() { + return bean1; + } + + public BeanClass2 getBean2() { + return bean2; + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/ConfigurationWithInjections.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/ConfigurationWithInjections.java new file mode 100644 index 000000000..451cf1eb3 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/ConfigurationWithInjections.java @@ -0,0 +1,17 @@ +package org.test.injections; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.test.BeanClass1; +import org.test.BeanClass2; +import org.test.ManuallyCreatedBeanWithConstructor; + +@Configuration +public class ConfigurationWithInjections { + + @Bean + ManuallyCreatedBeanWithConstructor manualBeanWithConstructor(BeanClass1 bean1, BeanClass2 bean2) { + return new ManuallyCreatedBeanWithConstructor(bean1, bean2); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/ConfigurationWithoutInjection.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/ConfigurationWithoutInjection.java new file mode 100644 index 000000000..bbf7ae9dc --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/ConfigurationWithoutInjection.java @@ -0,0 +1,15 @@ +package org.test.injections; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.test.BeanClass1; + +@Configuration +public class ConfigurationWithoutInjection { + + @Bean + BeanClass1 beanWithoutInjections() { + return new BeanClass1(); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/ConstructorInjectionService.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/ConstructorInjectionService.java new file mode 100644 index 000000000..241336a74 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/injections/ConstructorInjectionService.java @@ -0,0 +1,26 @@ +package org.test.injections; + +import org.springframework.stereotype.Service; +import org.test.BeanClass1; +import org.test.BeanClass2; + +@Service +public class ConstructorInjectionService { + + private BeanClass1 bean1; + private BeanClass2 bean2; + + public ConstructorInjectionService(BeanClass1 bean1, BeanClass2 bean2) { + this.bean1 = bean1; + this.bean2 = bean2; + } + + public BeanClass1 getBean1() { + return bean1; + } + + public BeanClass2 getBean2() { + return bean2; + } + +}