GH-1498: bean registrars are not bean index eleements anymore, but have a dedicated index element instead

This commit is contained in:
Martin Lippert
2025-03-25 11:18:14 +01:00
parent 7ae1e52daa
commit ab69e8231e
6 changed files with 84 additions and 39 deletions

View File

@@ -0,0 +1,45 @@
/*******************************************************************************
* 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.commons.protocol.spring;
import org.eclipse.lsp4j.DocumentSymbol;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.SymbolKind;
public class BeanRegistrarElement extends AbstractSpringIndexElement implements SymbolElement {
private final String name;
private final String type;
private final Location location;
public BeanRegistrarElement(String name, String type, Location location) {
this.name = name;
this.type = type;
this.location = location;
}
public String getType() {
return type;
}
public Location getLocation() {
return location;
}
@Override
public DocumentSymbol getDocumentSymbol() {
return new DocumentSymbol(
name + " (Bean Registrar)",
SymbolKind.Class,
location.getRange(), location.getRange());
}
}

View File

@@ -30,6 +30,7 @@ import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.RecordDeclaration;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.SymbolKind;
@@ -51,9 +52,11 @@ import org.springframework.ide.vscode.boot.java.utils.DefaultSymbolProvider;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.protocol.spring.BeanRegistrarElement;
import org.springframework.ide.vscode.commons.protocol.spring.DefaultValues;
import org.springframework.ide.vscode.commons.protocol.spring.InjectionPoint;
import org.springframework.ide.vscode.commons.protocol.spring.SimpleSymbolElement;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
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;
@@ -401,7 +404,7 @@ public class ComponentSymbolProvider implements SymbolProvider {
return null;
}
private void indexBeanRegistrarImplementation(Bean bean, TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
private void indexBeanRegistrarImplementation(SpringIndexElement parentNode, TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
try {
ITypeBinding typeBinding = typeDeclaration.resolveBinding();
if (typeBinding == null) return;
@@ -416,39 +419,32 @@ public class ComponentSymbolProvider implements SymbolProvider {
throw new RequiredCompleteAstException();
}
if (bean == null) { // need to create and register bean element
String beanType = typeBinding.getQualifiedName();
String beanName = BeanUtils.getBeanNameFromType(typeBinding.getName());
if (parentNode == null) { // need to create and register bean element
String name = typeBinding.getName();
String type = typeBinding.getQualifiedName();
Location location = new Location(doc.getUri(), doc.toRange(typeDeclaration.getStartPosition(), typeDeclaration.getLength()));
SimpleName typeNameNode = typeDeclaration.getName();
Location location = new Location(doc.getUri(), doc.toRange(typeNameNode.getStartPosition(), typeNameNode.getLength()));
WorkspaceSymbol symbol = new WorkspaceSymbol(
beanLabel("+", null, null, beanName, beanType),
SymbolKind.Class,
name + " (Bean Registrar)",
SymbolKind.Interface,
Either.forLeft(location));
InjectionPoint[] injectionPoints = ASTUtils.findInjectionPoints(typeDeclaration, doc);
Set<String> supertypes = new HashSet<>();
ASTUtils.findSupertypes(typeBinding, supertypes);
Collection<Annotation> annotationsOnMethod = ASTUtils.getAnnotations(typeDeclaration);
AnnotationMetadata[] annotations = ASTUtils.getAnnotationsMetadata(annotationsOnMethod, doc);
bean = new Bean(beanName, beanType, location, injectionPoints, supertypes, annotations, false, symbol.getName());
parentNode = new BeanRegistrarElement(name, type, location);
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), symbol));
context.getBeans().add(new CachedBean(context.getDocURI(), bean));
context.getBeans().add(new CachedBean(context.getDocURI(), parentNode));
}
scanBeanRegistryInvocations(bean, registerMethod.getBody(), context, doc);
scanBeanRegistryInvocations(parentNode, registerMethod.getBody(), context, doc);
} catch (BadLocationException e) {
log.error("", e);
}
}
private void scanBeanRegistryInvocations(Bean component, Block body, SpringIndexerJavaContext context, TextDocument doc) {
private void scanBeanRegistryInvocations(SpringIndexElement parent, Block body, SpringIndexerJavaContext context, TextDocument doc) {
if (body == null) {
return;
}
@@ -491,7 +487,7 @@ public class ComponentSymbolProvider implements SymbolProvider {
String beanName = BeanUtils.getBeanNameFromType(typeParameters[0].getName());
String beanType = typeParamName;
createBean(component, beanName, beanType, typeParameters[0], methodInvocation, context, doc);
createBean(parent, beanName, beanType, typeParameters[0], methodInvocation, context, doc);
}
}
else if (arguments.size() == 2 && "java.lang.String".equals(types.get(0).getQualifiedName()) && "java.lang.Class".equals(types.get(1).getBinaryName())) {
@@ -505,7 +501,7 @@ public class ComponentSymbolProvider implements SymbolProvider {
String typeParamName = typeParameters[0].getBinaryName();
String beanType = typeParamName;
createBean(component, beanName, beanType, typeParameters[0], methodInvocation, context, doc);
createBean(parent, beanName, beanType, typeParameters[0], methodInvocation, context, doc);
}
}
else if (arguments.size() == 2 && "java.lang.Class".equals(types.get(0).getBinaryName()) && "java.util.function.Consumer".equals(types.get(1).getBinaryName())) {
@@ -519,7 +515,7 @@ public class ComponentSymbolProvider implements SymbolProvider {
String beanName = BeanUtils.getBeanNameFromType(typeParameters[0].getName());
String beanType = typeParamName;
createBean(component, beanName, beanType, typeParameters[0], methodInvocation, context, doc);
createBean(parent, beanName, beanType, typeParameters[0], methodInvocation, context, doc);
}
}
else if (arguments.size() == 3 && "java.lang.String".equals(types.get(0).getQualifiedName())
@@ -534,7 +530,7 @@ public class ComponentSymbolProvider implements SymbolProvider {
String typeParamName = typeParameters[0].getBinaryName();
String beanType = typeParamName;
createBean(component, beanName, beanType, typeParameters[0], methodInvocation, context, doc);
createBean(parent, beanName, beanType, typeParameters[0], methodInvocation, context, doc);
}
}
}
@@ -548,7 +544,7 @@ public class ComponentSymbolProvider implements SymbolProvider {
});
}
public void createBean(Bean parentBean, String beanName, String beanType, ITypeBinding beanTypeBinding, ASTNode node, SpringIndexerJavaContext context, TextDocument doc) throws BadLocationException {
public void createBean(SpringIndexElement parentNode, String beanName, String beanType, ITypeBinding beanTypeBinding, ASTNode node, SpringIndexerJavaContext context, TextDocument doc) throws BadLocationException {
Location location = new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()));
WorkspaceSymbol symbol = new WorkspaceSymbol(
@@ -564,7 +560,7 @@ public class ComponentSymbolProvider implements SymbolProvider {
AnnotationMetadata[] annotations = DefaultValues.EMPTY_ANNOTATIONS;
Bean bean = new Bean(beanName, beanType, location, injectionPoints, supertypes, annotations, false, symbol.getName());
parentBean.addChild(bean);
parentNode.addChild(bean);
}
public static String beanLabel(String searchPrefix, String annotationTypeName, Collection<String> metaAnnotationNames, String beanName, String beanType) {

View File

@@ -37,6 +37,7 @@ import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRe
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.protocol.spring.BeanRegistrarElement;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
@@ -168,10 +169,11 @@ public class BeanRegistrarDeclarationReconciler implements JdtAstReconciler {
Set<String> importedTypesDelta = getImportAnnotationTypesDelta(createdIndexElements, previuosIndexElements);
Arrays.stream(springIndex.getBeans())
.filter(bean -> bean.isTypeCompatibleWith(Annotations.BEAN_REGISTRAR_INTERFACE))
.filter(bean -> importedTypesDelta.contains(bean.getType()))
.map(bean -> bean.getLocation().getUri())
List<BeanRegistrarElement> registrarElements = springIndex.getNodesOfType(BeanRegistrarElement.class);
registrarElements.stream()
.filter(registrar -> importedTypesDelta.contains(registrar.getType()))
.map(registrar -> registrar.getLocation().getUri())
.map(docURI -> UriUtil.toFileString(docURI))
.forEach(file -> context.markForAffetcedFilesIndexing(file));
}

View File

@@ -92,7 +92,7 @@ public class SpringIndexerJava implements SpringIndexer {
// whenever the implementation of the indexer changes in a way that the stored data in the cache is no longer valid,
// we need to change the generation - this will result in a re-indexing due to no up-to-date cache data being found
private static final String GENERATION = "GEN-17";
private static final String GENERATION = "GEN-18";
private static final String INDEX_FILES_TASK_ID = "index-java-source-files-task-";
private static final String SYMBOL_KEY = "symbols";

View File

@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.index.test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -31,8 +32,9 @@ import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf;
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.protocol.spring.BeanRegistrarElement;
import org.springframework.ide.vscode.commons.protocol.spring.DocumentElement;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
@@ -72,15 +74,17 @@ public class SpringIndexerBeanRegistrarTest {
void testSimpleBeanRegistration() throws Exception {
String docUri = directory.toPath().resolve("src/main/java/com/example/MyBeanRegistrar.java").toUri().toString();
Bean[] beans = springIndex.getBeansOfDocument(docUri);
assertEquals(5, beans.length);
Bean[] beansOfDoc = springIndex.getBeansOfDocument(docUri);
assertFalse(Arrays.stream(beansOfDoc).anyMatch(bean -> bean.getName().equals("myBeanRegistrar")));
Bean beanRegistrarBean = Arrays.stream(beans).filter(bean -> bean.getName().equals("myBeanRegistrar")).findFirst().get();
assertEquals("com.example.MyBeanRegistrar", beanRegistrarBean.getType());
DocumentElement document = springIndex.getDocument(docUri);
List<SpringIndexElement> docChildren = document.getChildren();
assertEquals(1, docChildren.size());
assertTrue(docChildren.get(0) instanceof BeanRegistrarElement);
List<SpringIndexElement> children = beanRegistrarBean.getChildren();
List<SpringIndexElement> children = docChildren.get(0).getChildren();
assertEquals(4, children.size());
Bean fooFoo = (Bean) children.get(0);
assertEquals("fooFoo", fooFoo.getName());
assertEquals("com.example.FooFoo", fooFoo.getType());

View File

@@ -31,7 +31,6 @@ 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.SpringMetamodelIndex;
import org.springframework.ide.vscode.boot.java.Boot4JavaProblemType;
import org.springframework.ide.vscode.boot.java.utils.test.TestFileScanListener;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
@@ -51,7 +50,6 @@ public class BeanRegistrarAdvancedReconcilingTest {
@Autowired private BootLanguageServerHarness harness;
@Autowired private JavaProjectFinder projectFinder;
@Autowired private SpringSymbolIndex indexer;
@Autowired private SpringMetamodelIndex springIndex;
private File directory;