From 98a5992e438fb3ff2c8d985efea93e54725c7bd0 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Fri, 28 Mar 2025 20:55:44 +0100 Subject: [PATCH] GH-1530: requires complete index for validation and added more complicated test cases as a start for further testing --- .../NotRegisteredBeansReconciler.java | 6 +- ...egisteredBeansAdvancedReconcilingTest.java | 151 ++++++++++++++++++ .../test-spring-validations/pom.xml | 2 +- .../src/main/java/org/test/aot/Config.java | 14 ++ ...egisteredBeanRegistrationAotProcessor.java | 14 ++ ...ComponentBeanRegistrationAotProcessor.java | 16 ++ ...FactoriesBeanRegistrationAotProcessor.java | 14 ++ ...ViaConfigBeanRegistrationAotProcessor.java | 14 ++ .../resources/META-INF/spring/aot.factories | 0 9 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/NotRegisteredBeansAdvancedReconcilingTest.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/Config.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/NotRegisteredBeanRegistrationAotProcessor.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegisteredAsComponentBeanRegistrationAotProcessor.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegisteredViaFactoriesBeanRegistrationAotProcessor.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegistetedViaConfigBeanRegistrationAotProcessor.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/resources/META-INF/spring/aot.factories diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NotRegisteredBeansReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NotRegisteredBeansReconciler.java index 4d60ccaee..27e80c125 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NotRegisteredBeansReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NotRegisteredBeansReconciler.java @@ -81,8 +81,12 @@ public class NotRegisteredBeansReconciler implements JdtAstReconciler { ITypeBinding type = node.resolveBinding(); if (type != null && ReconcileUtils.implementsAnyType(AOT_BEANS, type)) { - String beanClassName = type.getQualifiedName(); + if (!context.isIndexComplete()) { + throw new RequiredCompleteIndexException(); + } + + String beanClassName = type.getQualifiedName(); Bean[] registeredBeans = springIndex.getBeansWithType(project.getElementName(), beanClassName); if (registeredBeans == null || registeredBeans.length == 0) { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/NotRegisteredBeansAdvancedReconcilingTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/NotRegisteredBeansAdvancedReconcilingTest.java new file mode 100644 index 000000000..80ef4817a --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/NotRegisteredBeansAdvancedReconcilingTest.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) 2025 Broadcom + * 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: + * Broadcom - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.reconcilers.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.File; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.TextDocumentIdentifier; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +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.BootJavaConfig; +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.java.SpringAotJavaProblemType; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.languageserver.util.Settings; +import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness; +import org.springframework.ide.vscode.project.harness.ProjectsHarness; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; + +/** + * @author Martin Lippert + */ +@ExtendWith(SpringExtension.class) +@BootLanguageServerTest +@Import(SymbolProviderTestConf.class) +public class NotRegisteredBeansAdvancedReconcilingTest { + + @Autowired private BootLanguageServerHarness harness; + @Autowired private JavaProjectFinder projectFinder; + @Autowired private SpringSymbolIndex indexer; + @Autowired private BootJavaConfig config; + + private File directory; + + @BeforeEach + public void setup() throws Exception { + harness.intialize(null); + + JsonElement json = new Gson().fromJson(""" + { + "boot-java": { + "validation": { + "java": { + "boot2": "AUTO", + "boot3": "AUTO", + "spring-aot": "ON", + "version-validation": "ON" + } + } + } + } + """, JsonElement.class); + config.handleConfigurationChange(new Settings(json)); + + directory = new File(ProjectsHarness.class.getResource("/test-projects/test-spring-validations/").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 testBasicValidationOfAotProcessorNotRegistered() throws Exception { + String docUri = directory.toPath().resolve("src/main/java/org/test/aot/NotRegisteredBeanRegistrationAotProcessor.java").toUri().toString(); + + PublishDiagnosticsParams diagnosticsResult = harness.getDiagnostics(docUri); + List diagnostics = diagnosticsResult.getDiagnostics(); + + assertEquals(1, diagnostics.size()); + assertEquals(SpringAotJavaProblemType.JAVA_BEAN_NOT_REGISTERED_IN_AOT.getCode(), diagnostics.get(0).getCode().getLeft()); + } + + @Test + void testBasicValidationOfAotProcessorRegisteredAsComponent() throws Exception { + String docUri = directory.toPath().resolve("src/main/java/org/test/aot/RegisteredAsComponentBeanRegistrationAotProcessor.java").toUri().toString(); + + PublishDiagnosticsParams diagnosticsResult = harness.getDiagnostics(docUri); + List diagnostics = diagnosticsResult.getDiagnostics(); + + assertEquals(0, diagnostics.size()); + } + + @Test + void testBasicValidationOfAotProcessorRegisteredViaConfig() throws Exception { + String docUri = directory.toPath().resolve("src/main/java/org/test/aot/RegistetedViaConfigBeanRegistrationAotProcessor.java").toUri().toString(); + + PublishDiagnosticsParams diagnosticsResult = harness.getDiagnostics(docUri); + List diagnostics = diagnosticsResult.getDiagnostics(); + + assertEquals(0, diagnostics.size()); + } + + @Test + @Disabled // this case needs work - (1) factories not taken into account at all, (2) requires complete index doesn't take other indexers into account yet + void testBasicValidationOfAotProcessorRegisteredViaFactoriesFile() throws Exception { + String docUri = directory.toPath().resolve("src/main/java/org/test/aot/RegisteredViaFactoriesBeanRegistrationAotProcessor.java").toUri().toString(); + + PublishDiagnosticsParams diagnosticsResult = harness.getDiagnostics(docUri); + List diagnostics = diagnosticsResult.getDiagnostics(); + + assertEquals(0, diagnostics.size()); + } + + @Test + void testValidationDisappearsWhenComponentAnnotationIsAdded() throws Exception { + // TODO + } + + @Test + void testValidationAppearsWhenComponentAnnotationIsRemoved() throws Exception { + // TODO + } + + @Test + void testValidationDisappearsWhenBeanMethodIsAddedToConfig() throws Exception { + // TODO + } + + @Test + void testValidationAppearsWhenBeanMethodIsRemovedFromConfig() throws Exception { + // TODO + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/pom.xml b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/pom.xml index 486b74bdd..0ead86db0 100644 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/pom.xml +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/pom.xml @@ -11,7 +11,7 @@ org.springframework.boot spring-boot-starter-parent - 3.1.2 + 3.4.4 diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/Config.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/Config.java new file mode 100644 index 000000000..af22f76e4 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/Config.java @@ -0,0 +1,14 @@ +package org.test.aot; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class Config { + + @Bean + RegistetedViaConfigBeanRegistrationAotProcessor registeredViaConfigAotProcessor() { + return new RegistetedViaConfigBeanRegistrationAotProcessor(); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/NotRegisteredBeanRegistrationAotProcessor.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/NotRegisteredBeanRegistrationAotProcessor.java new file mode 100644 index 000000000..61d311e6a --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/NotRegisteredBeanRegistrationAotProcessor.java @@ -0,0 +1,14 @@ +package org.test.aot; + +import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; +import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor; +import org.springframework.beans.factory.support.RegisteredBean; + +public class NotRegisteredBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor { + + @Override + public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { + return null; + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegisteredAsComponentBeanRegistrationAotProcessor.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegisteredAsComponentBeanRegistrationAotProcessor.java new file mode 100644 index 000000000..53398b327 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegisteredAsComponentBeanRegistrationAotProcessor.java @@ -0,0 +1,16 @@ +package org.test.aot; + +import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; +import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor; +import org.springframework.beans.factory.support.RegisteredBean; +import org.springframework.stereotype.Component; + +@Component +public class RegisteredAsComponentBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor { + + @Override + public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { + return null; + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegisteredViaFactoriesBeanRegistrationAotProcessor.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegisteredViaFactoriesBeanRegistrationAotProcessor.java new file mode 100644 index 000000000..d199d65d2 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegisteredViaFactoriesBeanRegistrationAotProcessor.java @@ -0,0 +1,14 @@ +package org.test.aot; + +import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; +import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor; +import org.springframework.beans.factory.support.RegisteredBean; + +public class RegisteredViaFactoriesBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor { + + @Override + public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { + return null; + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegistetedViaConfigBeanRegistrationAotProcessor.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegistetedViaConfigBeanRegistrationAotProcessor.java new file mode 100644 index 000000000..1e2291e4e --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/java/org/test/aot/RegistetedViaConfigBeanRegistrationAotProcessor.java @@ -0,0 +1,14 @@ +package org.test.aot; + +import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; +import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor; +import org.springframework.beans.factory.support.RegisteredBean; + +public class RegistetedViaConfigBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor { + + @Override + public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { + return null; + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/resources/META-INF/spring/aot.factories b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-validations/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 000000000..e69de29bb