GH-1499: re-validating bean registrars now when config classes change their import annotation expressions

This commit is contained in:
Martin Lippert
2025-03-24 13:59:47 +01:00
parent 3d1ccd7dfe
commit a2503612bc
36 changed files with 501 additions and 119 deletions

View File

@@ -235,7 +235,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
@Override
public void removeSymbols(IJavaProject project, String docURI) {
SpringSymbolIndex.this.removeSymbolsByDoc(project, docURI);
springIndex.removeElements(project.getElementName(), docURI);
// springIndex.removeElements(project.getElementName(), docURI);
// TODO remove diagnostics ?!? maybe, maybe not

View File

@@ -12,6 +12,7 @@ package org.springframework.ide.vscode.boot.index;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -249,4 +250,23 @@ public class SpringMetamodelIndex {
return (Bean[]) result.toArray(new Bean[result.size()]);
}
public static <T extends SpringIndexElement> List<T> getNodesOfType(Class<T> type, Collection<SpringIndexElement> rootNodes) {
List<T> result = new ArrayList<>();
ArrayDeque<SpringIndexElement> elementsToVisit = new ArrayDeque<>();
elementsToVisit.addAll(rootNodes);
while (!elementsToVisit.isEmpty()) {
SpringIndexElement element = elementsToVisit.pop();
if (type.isInstance(element)) {
result.add(type.cast(element));
}
elementsToVisit.addAll(element.getChildren());
}
return result;
}
}

View File

@@ -17,9 +17,9 @@ import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.springframework.ide.vscode.boot.java.embedded.lang.EmbeddedLanguageSnippet;
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
import org.springframework.ide.vscode.boot.java.reconcilers.ReconcilingContext;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
public class JdtCronReconciler implements JdtAstReconciler {
@@ -41,14 +41,13 @@ public class JdtCronReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu,
IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@Override
public boolean visit(NormalAnnotation node) {
EmbeddedLanguageSnippet e = JdtCronVisitorUtils.extractCron(node);
if (e != null) {
cronReconciler.reconcile(e.getText(), e::toSingleJavaRange, problemCollector);
cronReconciler.reconcile(e.getText(), e::toSingleJavaRange, context.getProblemCollector());
}
return super.visit(node);
}

View File

@@ -25,11 +25,11 @@ import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitor
import org.springframework.ide.vscode.boot.java.embedded.lang.AntlrReconcilerWithSpel;
import org.springframework.ide.vscode.boot.java.handlers.Reconciler;
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
import org.springframework.ide.vscode.boot.java.reconcilers.ReconcilingContext;
import org.springframework.ide.vscode.boot.java.reconcilers.RequiredCompleteAstException;
import org.springframework.ide.vscode.boot.java.spel.SpelReconciler;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.parser.mysql.MySqlLexer;
import org.springframework.ide.vscode.parser.mysql.MySqlParser;
@@ -54,7 +54,7 @@ public class QueryJdtAstReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) throws RequiredCompleteAstException {
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, ReconcilingContext context) throws RequiredCompleteAstException {
AnnotationHierarchies annotationHierarchies = AnnotationHierarchies.get(cu);
return new ASTVisitor() {
@@ -63,7 +63,7 @@ public class QueryJdtAstReconciler implements JdtAstReconciler {
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(annotationHierarchies, node);
if (q != null) {
Optional<Reconciler> reconcilerOpt = q.isNative() ? getSqlReconciler(project) : Optional.of(getQueryReconciler(project));
reconcilerOpt.ifPresent(r -> r.reconcile(q.query().getText(), q.query()::toSingleJavaRange, problemCollector));
reconcilerOpt.ifPresent(r -> r.reconcile(q.query().getText(), q.query()::toSingleJavaRange, context.getProblemCollector()));
}
return super.visit(node);
}
@@ -72,7 +72,7 @@ public class QueryJdtAstReconciler implements JdtAstReconciler {
public boolean visit(SingleMemberAnnotation node) {
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(annotationHierarchies, node);
if (q != null) {
getQueryReconciler(project).reconcile(q.query().getText(), q.query()::toSingleJavaRange, problemCollector);
getQueryReconciler(project).reconcile(q.query().getText(), q.query()::toSingleJavaRange, context.getProblemCollector());
}
return super.visit(node);
}
@@ -81,7 +81,7 @@ public class QueryJdtAstReconciler implements JdtAstReconciler {
public boolean visit(MethodInvocation node) {
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(node);
if (q != null) {
getQueryReconciler(project).reconcile(q.query().getText(), q.query()::toSingleJavaRange, problemCollector);
getQueryReconciler(project).reconcile(q.query().getText(), q.query()::toSingleJavaRange, context.getProblemCollector());
}
return super.visit(node);
}

View File

@@ -20,7 +20,6 @@ import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
@@ -34,9 +33,9 @@ public abstract class AbstractSecurityLamdaDslReconciler implements JdtAstReconc
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
if (isCompleteAst) {
if (context.isCompleteAst()) {
return new ASTVisitor() {
@Override
@@ -59,7 +58,7 @@ public abstract class AbstractSecurityLamdaDslReconciler implements JdtAstReconc
ReconcileUtils.buildLabel(getFixLabel(), RecipeScope.PROJECT))
.withRecipeScope(RecipeScope.PROJECT)
));
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
return false;
}
}

View File

@@ -33,7 +33,6 @@ import org.springframework.ide.vscode.commons.Version;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
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;
@@ -65,7 +64,7 @@ public class AddConfigurationIfBeansPresentReconciler implements JdtAstReconcile
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@Override
@@ -85,7 +84,7 @@ public class AddConfigurationIfBeansPresentReconciler implements JdtAstReconcile
ReconcileUtils.buildLabel(FIX_LABEL, RecipeScope.PROJECT))
.withRecipeScope(RecipeScope.PROJECT)));
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
}
return true;
}

View File

@@ -23,7 +23,6 @@ import org.springframework.ide.vscode.commons.Version;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
@@ -57,9 +56,9 @@ public class AuthorizeHttpRequestsReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
if (isCompleteAst) {
if (context.isCompleteAst()) {
return new ASTVisitor() {
@Override
@@ -82,7 +81,7 @@ public class AuthorizeHttpRequestsReconciler implements JdtAstReconciler {
ReconcileUtils.buildLabel(AUTHORIZE_REQUESTS_FIX_LABEL,
RecipeScope.PROJECT))
.withRecipeScope(RecipeScope.PROJECT)));
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
return false;
}
}

View File

@@ -39,7 +39,6 @@ import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchie
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
@@ -67,7 +66,7 @@ public class AutowiredFieldIntoConstructorParameterReconciler implements JdtAstR
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
Path sourceFile = Paths.get(docUri);
// Check if source file belongs to non-test java sources folder
if (IClasspathUtil.getProjectJavaSourceFoldersWithoutTests(project.getClasspath())
@@ -91,14 +90,14 @@ public class AutowiredFieldIntoConstructorParameterReconciler implements JdtAstR
String fieldName = variableDeclarationFragment.getName().getIdentifier();
if (constructors.isEmpty()) {
problemCollector.accept(createProblem(cu, field, fieldName, docUri));
context.getProblemCollector().accept(createProblem(cu, field, fieldName, docUri));
} else if (constructors.size() == 1) {
if (!isCompleteAst) {
if (!context.isCompleteAst()) {
throw new RequiredCompleteAstException();
}
if (!isAssigningField(constructors.get(0), variableDeclarationFragment.resolveBinding(),
fieldName)) {
problemCollector.accept(createProblem(cu, field, fieldName, docUri));
context.getProblemCollector().accept(createProblem(cu, field, fieldName, docUri));
}
} else {
List<MethodDeclaration> autowiredConstructors = constructors.stream()
@@ -106,11 +105,11 @@ public class AutowiredFieldIntoConstructorParameterReconciler implements JdtAstR
Annotations.AUTOWIRED, true) != null)
.limit(2).collect(Collectors.toList());
if (autowiredConstructors.size() == 1) {
if (!isCompleteAst) {
if (!context.isCompleteAst()) {
throw new RequiredCompleteAstException();
} else if (!isAssigningField(autowiredConstructors.get(0),
variableDeclarationFragment.resolveBinding(), fieldName)) {
problemCollector.accept(createProblem(cu, field, fieldName, docUri));
context.getProblemCollector().accept(createProblem(cu, field, fieldName, docUri));
}
}
}

View File

@@ -66,14 +66,14 @@ public class BeanMethodNotPublicReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@Override
public boolean visit(SingleMemberAnnotation node) {
try {
visitAnnotation(project, cu, docUri, node, problemCollector);
visitAnnotation(project, cu, docUri, node, context.getProblemCollector());
} catch (Exception e) {
}
return super.visit(node);
@@ -82,7 +82,7 @@ public class BeanMethodNotPublicReconciler implements JdtAstReconciler {
@Override
public boolean visit(NormalAnnotation node) {
try {
visitAnnotation(project, cu, docUri, node, problemCollector);
visitAnnotation(project, cu, docUri, node, context.getProblemCollector());
} catch (Exception e) {
}
return super.visit(node);
@@ -91,7 +91,7 @@ public class BeanMethodNotPublicReconciler implements JdtAstReconciler {
@Override
public boolean visit(MarkerAnnotation node) {
try {
visitAnnotation(project, cu, docUri, node, problemCollector);
visitAnnotation(project, cu, docUri, node, context.getProblemCollector());
} catch (Exception e) {
}
return super.visit(node);

View File

@@ -25,7 +25,6 @@ import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.springframework.ide.vscode.boot.java.SpringAotJavaProblemType;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
@@ -56,7 +55,7 @@ public class BeanPostProcessingIgnoreInAotReconciler implements JdtAstReconciler
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@@ -73,7 +72,7 @@ public class BeanPostProcessingIgnoreInAotReconciler implements JdtAstReconciler
}
}
if (foundMethod != null) {
if (isCompleteAst) {
if (context.isCompleteAst()) {
AtomicBoolean returnsTrue = new AtomicBoolean(false);
foundMethod.accept(new ASTVisitor() {
@Override
@@ -99,7 +98,7 @@ public class BeanPostProcessingIgnoreInAotReconciler implements JdtAstReconciler
.withRangeScope(ReconcileUtils.createOpenRewriteRange(cu, typeDecl, null))
.withRecipeScope(RecipeScope.NODE)
));
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
}
}
return true;

View File

@@ -14,6 +14,7 @@ import java.net.URI;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -33,13 +34,16 @@ import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
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.SpringIndexElement;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.ImportBeanRegistrarInConfigRecipe;
import org.springframework.ide.vscode.commons.util.UriUtil;
import com.google.common.collect.Streams;
public class BeanRegistrarDeclarationReconciler implements JdtAstReconciler {
@@ -63,8 +67,7 @@ public class BeanRegistrarDeclarationReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu,
IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@Override
@@ -75,11 +78,14 @@ public class BeanRegistrarDeclarationReconciler implements JdtAstReconciler {
return true;
}
// this is not a bean registrar, but maybe a config class that has changed and is now importing a bean registrar
// so we need to mark the bean registrar for reconciling
if (ASTUtils.findInTypeHierarchy(type, Set.of(Annotations.BEAN_REGISTRAR_INTERFACE)) == null) {
identifyPossibleRegistrarsForReconciling(context);
return true;
}
if (!isIndexComplete) {
if (!context.isIndexComplete()) {
throw new RequiredCompleteIndexException();
}
@@ -99,7 +105,9 @@ public class BeanRegistrarDeclarationReconciler implements JdtAstReconciler {
}
}
if (configBeans.isEmpty() || !isImportedBeanRegistrarInConfig(configBeans, type)) {
List<String> importingBeanRegistrarConfigs = getImportedBeanRegistrarConfigs(configBeans, type);
if (configBeans.isEmpty() || importingBeanRegistrarConfigs.size() == 0) {
ReconcileProblemImpl problem = new ReconcileProblemImpl(getProblemType(), "Bean not registered", node.getName().getStartPosition(), node.getName().getLength());
List<FixDescriptor> fixes = configBeans.stream()
.filter(b -> b.getLocation() != null && b.getLocation().getUri() != null)
@@ -111,7 +119,18 @@ public class BeanRegistrarDeclarationReconciler implements JdtAstReconciler {
.withRecipeScope(RecipeScope.FILE)
).toList();
ReconcileUtils.setRewriteFixes(registry, problem, fixes);
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
// record dependencies on types where we found import annotations for this bean registrar
// mark this file
}
else {
// record dependencies on types where we found import annotations for this bean registrar
for (String typeOfConfigClassWithImport : importingBeanRegistrarConfigs) {
context.addDependency(typeOfConfigClassWithImport);
}
}
return true;
}
@@ -119,12 +138,65 @@ public class BeanRegistrarDeclarationReconciler implements JdtAstReconciler {
};
}
private boolean isImportedBeanRegistrarInConfig(List<Bean> configBeans, ITypeBinding beanRegType) {
private List<String> getImportedBeanRegistrarConfigs(List<Bean> configBeans, ITypeBinding beanRegType) {
return configBeans.stream()
.flatMap(bean -> Arrays.stream(bean.getAnnotations())) // look into annotations on this bean definition
.filter(configBean -> isImportingBeanRegistrar(configBean, beanRegType))
.map(configBean -> configBean.getType())
.toList();
}
private boolean isImportingBeanRegistrar(Bean configBean, ITypeBinding beanRegType) {
if (configBean.getAnnotations() == null) {
return false;
}
else {
return Arrays.stream(configBean.getAnnotations())
.filter(annotation -> Annotations.IMPORT.equals(annotation.getAnnotationType())) // look into @Import annotations only
.flatMap(annotation -> annotation.getAttributes().get("value") == null ? Stream.empty() : Arrays.stream(annotation.getAttributes().get("value"))) // look into the attribute values of "value" attribute
.anyMatch(annotationValue -> annotationValue.getName().equals(beanRegType.getQualifiedName()));
}
}
/**
* This is basically the reverse check: it tries to identify possible bean registrars that need to be
* reconciled because the type this reconciler is currently looking at refers to it or has referred to it.
*/
protected void identifyPossibleRegistrarsForReconciling(ReconcilingContext context) {
List<SpringIndexElement> createdIndexElements = context.getCreatedIndexElements();
List<SpringIndexElement> previuosIndexElements = springIndex.getDocument(context.getDocURI()) != null ?
springIndex.getDocument(context.getDocURI()).getChildren() : Collections.emptyList();
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())
.map(docURI -> UriUtil.toFileString(docURI))
.forEach(file -> context.markForAffetcedFilesIndexing(file));
}
public Set<String> getImportAnnotationTypesDelta(List<SpringIndexElement> updatedElements, List<SpringIndexElement> previousElements) {
Set<String> updatedImportedTypes = getImportAnnotationTypes(updatedElements);
Set<String> previousImportedTypes = getImportAnnotationTypes(previousElements);
return Streams.concat(updatedImportedTypes.stream(), previousImportedTypes.stream()
.filter(element ->
(updatedImportedTypes.contains(element) && !previousImportedTypes.contains(element))
|| (!updatedImportedTypes.contains(element) && previousImportedTypes.contains(element))))
.collect(Collectors.toSet());
}
public Set<String> getImportAnnotationTypes(List<SpringIndexElement> elements) {
return elements.stream()
.filter(element -> element instanceof Bean)
.map(element -> (Bean) element)
.flatMap(bean -> Arrays.stream(bean.getAnnotations()))
.filter(annotation -> Annotations.IMPORT.equals(annotation.getAnnotationType())) // look into @Import annotations only
.flatMap(annotation -> annotation.getAttributes().get("value") == null ? Stream.empty() : Arrays.stream(annotation.getAttributes().get("value"))) // look into the attribute values of "value" attribute
.anyMatch(annotationValue -> annotationValue.getName().equals(beanRegType.getQualifiedName()));
.map(attributeValue -> attributeValue.getName())
.distinct()
.collect(Collectors.toSet());
}
}

View File

@@ -22,7 +22,6 @@ import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.SimpleType;
import org.springframework.ide.vscode.boot.java.Boot3JavaProblemType;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
@@ -45,14 +44,14 @@ public class Boot3NotSupportedTypeReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@Override
public boolean visit(ImportDeclaration node) {
String fqName = node.getName().getFullyQualifiedName();
if (TYPE_FQNAMES.contains(fqName)) {
problemCollector.accept(createProblem(fqName, node.getName().getStartPosition(), node.getName().getLength()));
context.getProblemCollector().accept(createProblem(fqName, node.getName().getStartPosition(), node.getName().getLength()));
}
return super.visit(node);
}
@@ -61,7 +60,7 @@ public class Boot3NotSupportedTypeReconciler implements JdtAstReconciler {
public boolean visit(SimpleType node) {
String fqName = processType(cu, node.getName().getFullyQualifiedName());
if (fqName != null) {
problemCollector.accept(createProblem(fqName, node.getStartPosition(), node.getLength()));
context.getProblemCollector().accept(createProblem(fqName, node.getStartPosition(), node.getLength()));
}
return super.visit(node);
}

View File

@@ -44,7 +44,6 @@ import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchie
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.JavaUtils;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
@@ -70,7 +69,7 @@ public class EntityIdForRepoReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, ReconcilingContext context) {
AnnotationHierarchies annotationHierarchies = AnnotationHierarchies.get(cu);
return new ASTVisitor() {
@@ -129,7 +128,7 @@ public class EntityIdForRepoReconciler implements JdtAstReconciler {
}
private void markProblem(ITypeBinding idType, ASTNode node) {
problemCollector.accept(new ReconcileProblemImpl(getProblemType(),
context.getProblemCollector().accept(new ReconcileProblemImpl(getProblemType(),
"Expected Domain ID type is '" + idType.getQualifiedName() + "'", node.getStartPosition(),
node.getLength()));
}

View File

@@ -34,7 +34,6 @@ import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
@@ -74,7 +73,7 @@ public class ImplicitWebAnnotationNamesReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@@ -109,7 +108,7 @@ public class ImplicitWebAnnotationNamesReconciler implements JdtAstReconciler {
ReconcileUtils.buildLabel(FIX_LABEL_PLURAL, RecipeScope.PROJECT))
.withRecipeScope(RecipeScope.PROJECT)
));
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
}
}
};

View File

@@ -15,7 +15,6 @@ import java.net.URI;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
public interface JdtAstReconciler {
@@ -32,6 +31,6 @@ public interface JdtAstReconciler {
ProblemType getProblemType();
ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete);
ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, ReconcilingContext context);
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2022, 2023 VMware, Inc.
* Copyright (c) 2022, 2025 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
@@ -86,25 +86,28 @@ public class JdtReconciler implements JavaReconciler {
final long s = System.currentTimeMillis();
URI uri = URI.create(doc.getUri());
compilationUnitCache.withCompilationUnit(project, uri, cu -> {
if (cu != null) {
try {
reconcile(project, URI.create(doc.getUri()), cu, problemCollector, true, true);
ReconcilingContext reconcilingContext = new ReconcilingContext(doc.getUri(), problemCollector, true, true, Collections.emptyList());
reconcile(project, URI.create(doc.getUri()), cu, reconcilingContext);
} catch (RequiredCompleteAstException e) {
log.error("Unexpected incomplete AST", e);
}
// TODO: is the index indeed complete?!? do need to react to complete index exception instead ?!?
}
log.info("reconciling (JDT): " + doc.getUri() + " done in " + (System.currentTimeMillis() - s) + "ms");
return null;
});
}
public ASTVisitor createCompositeVisitor(IJavaProject project, URI docURI, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst,
boolean isIndexComplete) throws RequiredCompleteAstException {
public ASTVisitor createCompositeVisitor(IJavaProject project, URI docURI, CompilationUnit cu, ReconcilingContext context) throws RequiredCompleteAstException {
CompositeASTVisitor compositeVisitor = new CompositeASTVisitor();
for (JdtAstReconciler reconciler : getApplicableReconcilers(project)) {
ASTVisitor visitor = reconciler.createVisitor(project, docURI, cu, problemCollector, isCompleteAst, isIndexComplete);
ASTVisitor visitor = reconciler.createVisitor(project, docURI, cu, context);
if (visitor != null) {
compositeVisitor.add(visitor);
@@ -115,7 +118,7 @@ public class JdtReconciler implements JavaReconciler {
}
public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete)
public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context)
throws RequiredCompleteAstException, RequiredCompleteIndexException {
long start = System.currentTimeMillis();
@@ -125,7 +128,7 @@ public class JdtReconciler implements JavaReconciler {
}
try {
ASTVisitor compositeVisitor = createCompositeVisitor(project, docUri, cu, problemCollector, isCompleteAst, isIndexComplete);
ASTVisitor compositeVisitor = createCompositeVisitor(project, docUri, cu, context);
cu.accept(compositeVisitor);
// for (JdtAstReconciler reconciler : getApplicableReconcilers(project)) {

View File

@@ -28,7 +28,6 @@ import org.springframework.ide.vscode.boot.modulith.AppModules;
import org.springframework.ide.vscode.boot.modulith.ModulithService;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
@@ -52,7 +51,7 @@ public class ModulithTypeReferenceViolationReconciler implements JdtAstReconcile
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
Path sourceFile = Paths.get(docUri);
if (IClasspathUtil.getProjectJavaSourceFoldersWithoutTests(project.getClasspath())
@@ -81,7 +80,7 @@ public class ModulithTypeReferenceViolationReconciler implements JdtAstReconcile
private void validate(ASTNode node, ITypeBinding type) {
if (type != null) {
appModules.getModuleNotExposingType(packageName, type.getBinaryName()).ifPresent(module -> {
problemCollector.accept(new ReconcileProblemImpl(getProblemType(),
context.getProblemCollector().accept(new ReconcileProblemImpl(getProblemType(),
"Invalid reference to non-exposed type of module '%s'!".formatted(module.name()),
node.getStartPosition(), node.getLength()));
});

View File

@@ -29,7 +29,6 @@ import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchie
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
@@ -57,7 +56,7 @@ public class NoAutowiredOnConstructorReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
AnnotationHierarchies annotationHierarchies = AnnotationHierarchies.get(cu);
return new ASTVisitor() {
@@ -91,7 +90,7 @@ public class NoAutowiredOnConstructorReconciler implements JdtAstReconciler {
List.of(new FixDescriptor(NoAutowiredOnConstructor.class.getName(), List.of(docUri.toASCIIString()), FIX_LABEL)
.withRecipeScope(RecipeScope.NODE)
.withRangeScope(ReconcileUtils.createOpenRewriteRange(cu, typeDecl, null))));
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
}
}

View File

@@ -27,7 +27,6 @@ import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
@@ -55,7 +54,7 @@ public class NoRepoAnnotationReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@@ -82,7 +81,7 @@ public class NoRepoAnnotationReconciler implements JdtAstReconciler {
ReconcileUtils.buildLabel(FIX_LABEL, RecipeScope.PROJECT))
.withRecipeScope(RecipeScope.PROJECT)
));
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
}
}
}

View File

@@ -37,7 +37,6 @@ import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
@@ -69,7 +68,7 @@ public class NoRequestMappingAnnotationReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@@ -108,12 +107,12 @@ public class NoRequestMappingAnnotationReconciler implements JdtAstReconciler {
"Replace all `@RequestMapping` in project '%s' with `@GetMapping`, `@PostMapping`, etc.".formatted(project.getElementName()))
.withRecipeScope(RecipeScope.PROJECT)
));
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
} else if (SUPPORTED_REQUEST_METHODS == requestMethods) { // the case of no request methods specified
ReconcileProblemImpl problem = new ReconcileProblemImpl(getProblemType(), PROBLEM_LABEL, a.getStartPosition(), a.getLength());
ReconcileUtils.setRewriteFixes(registry, problem,
requestMethods.stream().map(m -> createFixDescriptor(uri, range, m)).collect(Collectors.toList()));
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
}
}
}

View File

@@ -71,7 +71,7 @@ public class NotRegisteredBeansReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@@ -86,7 +86,7 @@ public class NotRegisteredBeansReconciler implements JdtAstReconciler {
Bean[] registeredBeans = springIndex.getBeansWithType(project.getElementName(), beanClassName);
if (registeredBeans == null || registeredBeans.length == 0) {
createProblemAndQuickFixes(project, problemCollector, node, type);
createProblemAndQuickFixes(project, context.getProblemCollector(), node, type);
}
}
}

View File

@@ -30,7 +30,6 @@ import org.springframework.ide.vscode.boot.java.SpringAotJavaProblemType;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
@@ -57,7 +56,7 @@ public class PreciseBeanTypeReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
final AnnotationHierarchies annotationHierarchies = AnnotationHierarchies.get(cu);
return new ASTVisitor() {
@@ -72,7 +71,7 @@ public class PreciseBeanTypeReconciler implements JdtAstReconciler {
if (methodBinding != null) {
boolean isBeanMethod = annotationHierarchies.isAnnotatedWith(methodBinding, Annotations.BEAN);
if (isBeanMethod) {
if (isCompleteAst) {
if (context.isCompleteAst()) {
if (currentMethod == null) {// Do not jump into anonymous class methods
currentMethod = method;
currentReturnTypes = new ArrayList<>();
@@ -91,7 +90,7 @@ public class PreciseBeanTypeReconciler implements JdtAstReconciler {
if (currentMethod == method) {
ReconcileProblemImpl problem = new ReconcileProblemImpl(getProblemType(), LABEL, method.getReturnType2().getStartPosition(), method.getReturnType2().getLength());
if (currentReturnTypes.size() > 1) {
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
} else if (currentReturnTypes.size() == 1 && !method.resolveBinding().getReturnType().isAssignmentCompatible(currentReturnTypes.get(0))) {
String uri = docUri.toASCIIString();
String replacementType = currentReturnTypes.get(0).getName();
@@ -105,7 +104,7 @@ public class PreciseBeanTypeReconciler implements JdtAstReconciler {
new FixDescriptor(recipeId, List.of(uri), ReconcileUtils.buildLabel(LABEL, RecipeScope.PROJECT))
.withRecipeScope(RecipeScope.PROJECT)
));
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
}
currentMethod = null;

View File

@@ -0,0 +1,84 @@
/*******************************************************************************
* 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;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
/**
* context information for reconcilers
*/
public class ReconcilingContext {
private final String docURI;
private final IProblemCollector problemCollector;
private final boolean isCompleteAst;
private final boolean isIndexComplete;
private final Set<String> dependencies; // set of fully qualified types
private final Set<String> markedForAffectedFilesIndexing; // set of files
private final List<SpringIndexElement> createdIndexElements;
public ReconcilingContext(String docURI, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete, List<SpringIndexElement> createdIndexElements) {
this.docURI = docURI;
this.problemCollector = problemCollector;
this.isCompleteAst = isCompleteAst;
this.isIndexComplete = isIndexComplete;
this.dependencies = new HashSet<>();
this.markedForAffectedFilesIndexing = new HashSet<>();
this.createdIndexElements = createdIndexElements;
}
public String getDocURI() {
return docURI;
}
public IProblemCollector getProblemCollector() {
return problemCollector;
}
public boolean isCompleteAst() {
return isCompleteAst;
}
public boolean isIndexComplete() {
return isIndexComplete;
}
public void addDependency(String typeOfConfigClassWithImport) {
this.dependencies.add(typeOfConfigClassWithImport);
}
public Set<String> getDependencies() {
return dependencies;
}
public void markForAffetcedFilesIndexing(String file) {
this.markedForAffectedFilesIndexing.add(file);
}
public Set<String> getMarkedForAffectedFilesIndexing() {
return markedForAffectedFilesIndexing;
}
public List<SpringIndexElement> getCreatedIndexElements() {
return createdIndexElements;
}
}

View File

@@ -27,7 +27,6 @@ import org.openrewrite.java.spring.boot2.UnnecessarySpringExtension;
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
@@ -74,7 +73,7 @@ public class UnnecessarySpringExtensionReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@Override
@@ -95,7 +94,7 @@ public class UnnecessarySpringExtensionReconciler implements JdtAstReconciler {
ReconcileUtils.setRewriteFixes(registry, problem, List.of(
new FixDescriptor(UnnecessarySpringExtension.class.getName(), List.of(docUri.toASCIIString()), ReconcileUtils.buildLabel(LABEL, RecipeScope.PROJECT))
));
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
break;
}
}

View File

@@ -28,7 +28,6 @@ import org.springframework.ide.vscode.commons.Version;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
@@ -85,7 +84,7 @@ public class WebSecurityConfigurerAdapterReconciler implements JdtAstReconciler
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) {
AnnotationHierarchies annotationHierarchies = AnnotationHierarchies.get(cu);
return new ASTVisitor() {
@@ -111,7 +110,7 @@ public class WebSecurityConfigurerAdapterReconciler implements JdtAstReconciler
);
}
problemCollector.accept(problem);
context.getProblemCollector().accept(problem);
}
return super.visit(typeDecl);
}

View File

@@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.app.BootJavaConfig;
import org.springframework.ide.vscode.boot.java.handlers.JavaCodeActionHandler;
import org.springframework.ide.vscode.boot.java.reconcilers.JdtReconciler;
import org.springframework.ide.vscode.boot.java.reconcilers.ReconcilingContext;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.quickfix.Quickfix.QuickfixData;
@@ -105,14 +106,20 @@ public class RewriteCodeActionHandler implements JavaCodeActionHandler {
URI uri = URI.create(doc.getUri());
final QuickfixType rewriteFixType = quickfixRegistry.getQuickfixType(RewriteRefactorings.REWRITE_RECIPE_QUICKFIX);
if (isSupported(capabilities, context) && rewriteFixType != null) {
List<CodeAction> codeActions = cuCache.withCompilationUnit(project, uri, cu -> {
if (cu != null) {
try {
List<CodeAction> cas = new ArrayList<>();
List<ReconcileProblem> problems = new ArrayList<>();
BasicProblemCollector problemsCollector = new BasicProblemCollector(problems);
jdtReconciler.reconcile(project, uri, cu, problemsCollector, true, true);
ReconcilingContext reconcilingContext = new ReconcilingContext(doc.getUri(), problemsCollector, true, true, Collections.emptyList());
jdtReconciler.reconcile(project, uri, cu, reconcilingContext);
for (ReconcileProblem p : problems) {
if (p.getOffset() <= region.getOffset() && p.getOffset() + p.getLength() >= region.getOffset() + region.getLength() && severityProvider.getDiagnosticSeverity(p) == null) {
for (QuickfixData<?> qf : p.getQuickfixes()) {
@@ -123,6 +130,7 @@ public class RewriteCodeActionHandler implements JavaCodeActionHandler {
}
}
return cas;
} catch (Exception e) {
log.error("", e);
}

View File

@@ -19,9 +19,9 @@ import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.springframework.ide.vscode.boot.java.SpelProblemType;
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
import org.springframework.ide.vscode.boot.java.reconcilers.ReconcilingContext;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
public class JdtSpelReconciler implements JdtAstReconciler {
@@ -44,8 +44,7 @@ public class JdtSpelReconciler implements JdtAstReconciler {
}
@Override
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu,
IProblemCollector problemCollector, boolean isCompleteAst, boolean isIndexComplete) {
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, ReconcilingContext context) {
return new ASTVisitor() {
@Override
public boolean visit(SingleMemberAnnotation node) {
@@ -53,7 +52,7 @@ public class JdtSpelReconciler implements JdtAstReconciler {
.map(e -> e.getSpelRegion(node))
.filter(o -> o.isPresent())
.map(o -> o.get())
.forEach(snippet -> spelReconciler.reconcile(snippet.getText(), snippet::toSingleJavaRange, problemCollector));
.forEach(snippet -> spelReconciler.reconcile(snippet.getText(), snippet::toSingleJavaRange, context.getProblemCollector()));
return super.visit(node);
}
@@ -63,7 +62,7 @@ public class JdtSpelReconciler implements JdtAstReconciler {
.map(e -> e.getSpelRegion(node))
.filter(o -> o.isPresent())
.map(o -> o.get())
.forEach(snippet -> spelReconciler.reconcile(snippet.getText(), snippet::toSingleJavaRange, problemCollector));
.forEach(snippet -> spelReconciler.reconcile(snippet.getText(), snippet::toSingleJavaRange, context.getProblemCollector()));
return super.visit(node);
}

View File

@@ -63,6 +63,7 @@ import org.springframework.ide.vscode.boot.java.beans.CachedBean;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.boot.java.reconcilers.CachedDiagnostics;
import org.springframework.ide.vscode.boot.java.reconcilers.JdtReconciler;
import org.springframework.ide.vscode.boot.java.reconcilers.ReconcilingContext;
import org.springframework.ide.vscode.boot.java.reconcilers.RequiredCompleteAstException;
import org.springframework.ide.vscode.boot.java.reconcilers.RequiredCompleteIndexException;
import org.springframework.ide.vscode.commons.java.IClasspath;
@@ -356,8 +357,8 @@ public class SpringIndexerJava implements SpringIndexer {
scannedFiles.add(file);
}
Set<String> scannedTypes = scanFilesInternally(project, docs);
scanAffectedFiles(project, scannedTypes, scannedFiles);
ScanFilesInternallyResult result = scanFilesInternally(project, docs);
scanAffectedFiles(project, result.scannedTypes, scannedFiles, result.scanResult.getMarkedForAffectedFilesIndexing());
}
private void scanFile(IJavaProject project, DocumentDescriptor updatedDoc, String content) throws Exception {
@@ -417,11 +418,11 @@ public class SpringIndexerJava implements SpringIndexer {
reconcileWithCompleteIndex(project, result.getMarkedForReconcilingWithCompleteIndex());
scanAffectedFiles(project, context.getScannedTypes(), scannedFiles);
scanAffectedFiles(project, context.getScannedTypes(), scannedFiles, result.getMarkedForAffectedFilesIndexing());
}
}
private Set<String> scanFilesInternally(IJavaProject project, DocumentDescriptor[] docs) throws Exception {
private ScanFilesInternallyResult scanFilesInternally(IJavaProject project, DocumentDescriptor[] docs) throws Exception {
final boolean ignoreMethodBodies = false;
// this is to keep track of already scanned files to avoid endless loops due to circular dependencies
@@ -498,14 +499,18 @@ public class SpringIndexerJava implements SpringIndexer {
result.publishResults(symbolHandler);
reconcileWithCompleteIndex(project, result.getMarkedForReconcilingWithCompleteIndex());
return scannedTypes;
return new ScanFilesInternallyResult(scannedTypes, result);
}
private static record ScanFilesInternallyResult(Set<String> scannedTypes, SpringIndexerJavaScanResult scanResult) {};
private void scanAffectedFiles(IJavaProject project, Set<String> changedTypes, Set<String> alreadyScannedFiles) throws Exception {
private void scanAffectedFiles(IJavaProject project, Set<String> changedTypes, Set<String> alreadyScannedFiles, Set<String> alreadyMarkedForAffectedFilesIndexing) throws Exception {
log.info("Start scanning affected files for types {}", changedTypes);
Multimap<String, String> dependencies = dependencyTracker.getAllDependencies();
Set<String> filesToScan = new HashSet<>();
filesToScan.addAll(alreadyMarkedForAffectedFilesIndexing);
for (String file : dependencies.keys()) {
if (!alreadyScannedFiles.contains(file)) {
@@ -646,6 +651,9 @@ public class SpringIndexerJava implements SpringIndexer {
boolean ignoreMethodBodies = false;
String[] javaFiles = markedForReconcilingWithCompleteIndex.keySet().toArray(String[]::new);
log.info("additional reconciling with complete index triggere for: " + Arrays.toString(javaFiles));
long[] modificationTimestamps = new long[javaFiles.length];
for (int i = 0; i < javaFiles.length; i++) {
modificationTimestamps[i] = markedForReconcilingWithCompleteIndex.get(javaFiles[i]);
@@ -676,7 +684,7 @@ public class SpringIndexerJava implements SpringIndexer {
lastModified, docRef, null, problemCollector, new ArrayList<>(), !ignoreMethodBodies, true, reconcilingResult);
try {
DocumentUtils.getTempTextDocument(docURI, docRef, null);
DocumentUtils.getTempTextDocument(docURI, docRef, null); // initialize the docRef with a real document before running validations
reconcile(context);
} catch (Exception e) {
log.error("problem creating temp document during re-reconciling for: " + docURI, e);
@@ -826,7 +834,22 @@ public class SpringIndexerJava implements SpringIndexer {
try {
problemCollector.beginCollecting();
reconciler.reconcile(context.getProject(), URI.create(context.getDocURI()), context.getCu(), problemCollector, context.isFullAst(), context.isIndexComplete());
List<SpringIndexElement> createdElements = context.getBeans().stream()
.filter(cachedBean -> cachedBean.getDocURI().equals(context.getDocURI()))
.map(cachedBean -> cachedBean.getBean())
.toList();
ReconcilingContext reconcilingContext = new ReconcilingContext(context.getDocURI(), problemCollector, context.isFullAst(), context.isIndexComplete(), createdElements);
reconciler.reconcile(context.getProject(), URI.create(context.getDocURI()), context.getCu(), reconcilingContext);
for (String dependency : reconcilingContext.getDependencies()) {
context.addDependency(dependency);
}
context.getResult().markForAffectedFilesIndexing(reconcilingContext.getMarkedForAffectedFilesIndexing());
problemCollector.endCollecting();
} catch (RequiredCompleteAstException e) {

View File

@@ -123,13 +123,19 @@ public class SpringIndexerJavaContext {
public void addDependency(ITypeBinding dependsOn) {
if (dependsOn != null && dependsOn.isFromSource()) {
String type = dependsOn.getKey();
String type = dependsOn.getQualifiedName();
if (type != null && !scannedTypes.contains(type)) {
dependencies.add(type);
}
}
}
public void addDependency(String qualifiedTypeName) {
if (qualifiedTypeName != null) {
dependencies.add(qualifiedTypeName);
}
}
public Set<String> getScannedTypes() {
return scannedTypes;
@@ -137,7 +143,7 @@ public class SpringIndexerJavaContext {
public void addScannedType(ITypeBinding scannedType) {
if (scannedType != null) {
String type = scannedType.getKey();
String type = scannedType.getQualifiedName();
scannedTypes.add(type);
dependencies.remove(type);
}
@@ -171,5 +177,5 @@ public class SpringIndexerJavaContext {
}
}
}

View File

@@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.java.utils;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -37,7 +38,8 @@ import org.springframework.ide.vscode.commons.util.UriUtil;
*/
public class SpringIndexerJavaScanResult {
private final Map<String, Long> markedForReconciling;
private final Map<String, Long> markedForReconciling; // file + modification timestamp
private final Set<String> markedForAffetcedFilesIndexing; // file
private final List<CachedSymbol> generatedSymbols;
private final List<CachedBean> generatedBeans;
@@ -45,12 +47,15 @@ public class SpringIndexerJavaScanResult {
private final IJavaProject project;
private final String[] javaFiles;
public SpringIndexerJavaScanResult(IJavaProject project, String[] javaFiles) {
this.project = project;
this.javaFiles = javaFiles;
this.markedForReconciling = new HashMap<>();
this.markedForAffetcedFilesIndexing = new HashSet<>();
this.generatedSymbols = new ArrayList<CachedSymbol>();
this.generatedBeans = new ArrayList<CachedBean>();
this.generatedDiagnostics = new ArrayList<CachedDiagnostics>();
@@ -63,10 +68,13 @@ public class SpringIndexerJavaScanResult {
this.javaFiles = javaFiles;
this.markedForReconciling = new HashMap<>();
this.markedForAffetcedFilesIndexing = new HashSet<>();
this.generatedSymbols = Arrays.asList(symbols);
this.generatedBeans = Arrays.asList(beans);
this.generatedDiagnostics = Arrays.asList(diagnostics);
}
public Map<String, Long> getMarkedForReconcilingWithCompleteIndex() {
return markedForReconciling;
@@ -76,6 +84,15 @@ public class SpringIndexerJavaScanResult {
this.markedForReconciling.put(file, lastModified);
}
public void markForAffectedFilesIndexing(Collection<String> markedForAffectedFilesIndexing) {
this.markedForAffetcedFilesIndexing.addAll(markedForAffectedFilesIndexing);
}
public Set<String> getMarkedForAffectedFilesIndexing() {
return this.markedForAffetcedFilesIndexing;
}
public List<CachedBean> getGeneratedBeans() {
return generatedBeans;
}
@@ -108,5 +125,5 @@ public class SpringIndexerJavaScanResult {
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023 VMware, Inc.
* Copyright (c) 2023, 2025 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
@@ -19,6 +19,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -31,6 +32,7 @@ import org.eclipse.jdt.core.dom.FileASTRequestor;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
import org.springframework.ide.vscode.boot.java.reconcilers.CompositeASTVisitor;
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
import org.springframework.ide.vscode.boot.java.reconcilers.ReconcilingContext;
import org.springframework.ide.vscode.boot.java.reconcilers.RequiredCompleteAstException;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJava;
import org.springframework.ide.vscode.boot.java.value.test.ValueSpelExpressionValidationTest.TestProblemCollector;
@@ -106,7 +108,10 @@ public abstract class BaseReconcilerTest {
public void acceptAST(String sourceFilePath, CompilationUnit cu) {
try {
JdtAstReconciler reconciler = reconcilerFactory.get();
ASTVisitor visitor = reconciler.createVisitor(project, path.toUri(), cu, problemCollector, isCompleteAst, isIndexComplete);
String docURI = path.toUri().toASCIIString();
ReconcilingContext reconcilingContext = new ReconcilingContext(docURI, problemCollector, isCompleteAst, isIndexComplete, Collections.emptyList());
ASTVisitor visitor = reconciler.createVisitor(project, path.toUri(), cu, reconcilingContext);
if (visitor != null) {
// use a composite visitor here to make sure that the tests will fail if there is anything missing in the composite

View File

@@ -0,0 +1,156 @@
/*******************************************************************************
* 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.nio.charset.Charset;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.FileUtils;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.PublishDiagnosticsParams;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.WorkspaceSymbol;
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.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;
import org.springframework.ide.vscode.commons.util.UriUtil;
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 BeanRegistrarAdvancedReconcilingTest {
@Autowired private BootLanguageServerHarness harness;
@Autowired private JavaProjectFinder projectFinder;
@Autowired private SpringSymbolIndex indexer;
@Autowired private SpringMetamodelIndex springIndex;
private File directory;
@BeforeEach
public void setup() throws Exception {
harness.intialize(null);
directory = new File(ProjectsHarness.class.getResource("/test-projects/test-framework-7-indexing/").toURI());
String projectDir = directory.toURI().toString();
// trigger project creation
projectFinder.find(new TextDocumentIdentifier(projectDir)).get();
CompletableFuture<Void> initProject = indexer.waitOperation();
initProject.get(5, TimeUnit.SECONDS);
}
@Test
void testNoErrorOnRegisteredRegistrar() throws Exception {
String docUri = directory.toPath().resolve("src/main/java/com/example/MyBeanRegistrar.java").toUri().toString();
PublishDiagnosticsParams diagnosticsResult = harness.getDiagnostics(docUri);
List<Diagnostic> diagnostics = diagnosticsResult.getDiagnostics();
assertEquals(0, diagnostics.size());
}
@Test
void testErrorOnNonRegisteredRegistrar() throws Exception {
String docUri = directory.toPath().resolve("src/main/java/com/example/NotRegisteredBeanRegistrar.java").toUri().toString();
PublishDiagnosticsParams diagnosticsResult = harness.getDiagnostics(docUri);
List<Diagnostic> diagnostics = diagnosticsResult.getDiagnostics();
assertEquals(1, diagnostics.size());
assertEquals(Boot4JavaProblemType.REGISTRAR_BEAN_DECLARATION.getCode(), diagnostics.get(0).getCode().getLeft());
}
@Test
void testBeanRegistrarGetsReconciledWhenConfigChangesAddImportCase() throws Exception {
String configDoc = directory.toPath().resolve("src/main/java/com/example/ConfigImportsBeanRegistrar.java").toUri().toString();
String registeredRegistrarDocUri = directory.toPath().resolve("src/main/java/com/example/MyBeanRegistrar.java").toUri().toString();
String nonRegisteredRegistrarDocUri = directory.toPath().resolve("src/main/java/com/example/NotRegisteredBeanRegistrar.java").toUri().toString();
// symbol pre-check
List<? extends WorkspaceSymbol> symbols = indexer.getWorkspaceSymbolsFromSymbolIndex(registeredRegistrarDocUri);
assertEquals(5, symbols.size());
// now change the config class source code and update doc
TestFileScanListener fileScanListener = new TestFileScanListener();
indexer.getJavaIndexer().setFileScanListener(fileScanListener);
String configClassSource = FileUtils.readFileToString(UriUtil.toFile(configDoc), Charset.defaultCharset());
String updatedConfigClassSource = configClassSource.replace("@Import(MyBeanRegistrar.class)", "@Import({MyBeanRegistrar.class, NotRegisteredBeanRegistrar.class})");
CompletableFuture<Void> updateFuture = indexer.updateDocument(configDoc, updatedConfigClassSource, "test triggered");
updateFuture.get(5, TimeUnit.SECONDS);
// check if the bean registrar files have been re-scanned
fileScanListener.assertScannedUri(configDoc, 1);
fileScanListener.assertScannedUri(registeredRegistrarDocUri, 1);
fileScanListener.assertScannedUri(nonRegisteredRegistrarDocUri, 1);
fileScanListener.assertNoFileScans(3);
// check diagnostics result
PublishDiagnosticsParams diagnosticsResultForRegisteredRegistrar = harness.getDiagnostics(registeredRegistrarDocUri);
List<Diagnostic> diagnosticsForAlreadyRegisteredRegistrar = diagnosticsResultForRegisteredRegistrar.getDiagnostics();
assertEquals(0, diagnosticsForAlreadyRegisteredRegistrar.size());
PublishDiagnosticsParams diagnosticsResultForNewlyRegisteredRegistrar = harness.getDiagnostics(nonRegisteredRegistrarDocUri);
List<Diagnostic> diagnosticsForPreviouslyNotRegisteredRegistrar = diagnosticsResultForNewlyRegisteredRegistrar.getDiagnostics();
assertEquals(0, diagnosticsForPreviouslyNotRegisteredRegistrar.size());
// check if the symbols are still in place correctly
List<? extends WorkspaceSymbol> symbolsAfterUpdate = indexer.getWorkspaceSymbolsFromSymbolIndex(registeredRegistrarDocUri);
assertEquals(5, symbolsAfterUpdate.size());
}
@Test
void testBeanRegistrarGetsReconciledWhenConfigChangesRemoveImportCase() throws Exception {
String configDoc = directory.toPath().resolve("src/main/java/com/example/ConfigImportsBeanRegistrar.java").toUri().toString();
String registeredRegistrarDocUri = directory.toPath().resolve("src/main/java/com/example/MyBeanRegistrar.java").toUri().toString();
TestFileScanListener fileScanListener = new TestFileScanListener();
indexer.getJavaIndexer().setFileScanListener(fileScanListener);
String configClassSource = FileUtils.readFileToString(UriUtil.toFile(configDoc), Charset.defaultCharset());
String updatedConfigClassSource = configClassSource.replace("@Import(MyBeanRegistrar.class)", "");
CompletableFuture<Void> updateFuture = indexer.updateDocument(configDoc, updatedConfigClassSource, "test triggered");
updateFuture.get(5, TimeUnit.SECONDS);
fileScanListener.assertScannedUri(configDoc, 1);
fileScanListener.assertScannedUri(registeredRegistrarDocUri, 1);
fileScanListener.assertNoFileScans(2);
PublishDiagnosticsParams diagnosticsResultForPreviouslyRegisteredRegistrar = harness.getDiagnostics(registeredRegistrarDocUri);
List<Diagnostic> diagnosticsForPreviouslyRegisteredRegistrar = diagnosticsResultForPreviouslyRegisteredRegistrar.getDiagnostics();
assertEquals(1, diagnosticsForPreviouslyRegisteredRegistrar.size());
assertEquals(Boot4JavaProblemType.REGISTRAR_BEAN_DECLARATION.getCode(), diagnosticsForPreviouslyRegisteredRegistrar.get(0).getCode().getLeft());
}
}

View File

@@ -32,7 +32,7 @@ import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
public class BeanRegistrarDeclarationReconcilerTest extends BaseReconcilerTest {
@Override
protected String getFolder() {
return "sf7validation";

View File

@@ -109,8 +109,9 @@ public class RequestMappingSymbolProviderTest {
}
@Test
//TODO: Enable when JDT Core 3.41 or higher is adopted. See: https://github.com/eclipse-jdt/eclipse.jdt.core/pull/3416
@DisabledOnOs(OS.WINDOWS)
// TODO: Enable when JDT Core 3.41 or higher is adopted. See: https://github.com/eclipse-jdt/eclipse.jdt.core/pull/3416
// additional comment: switched the string to not contain the "key" of the AST node, but the fully qualified type name, therefore enabling this again everywhere
// @DisabledOnOs(OS.WINDOWS)
void testSimpleRequestMappingSymbolFromConstantInDifferentClass() throws Exception {
String docUri = directory.toPath().resolve("src/main/java/org/test/SimpleMappingClassWithConstantInDifferentClass.java").toUri().toString();
String constantsUri = directory.toPath().resolve("src/main/java/org/test/Constants.java").toUri().toString();
@@ -120,7 +121,7 @@ public class RequestMappingSymbolProviderTest {
//Verify whether dependency tracker logics works properly for this example.
SpringIndexerJavaDependencyTracker dt = indexer.getJavaIndexer().getDependencyTracker();
assertEquals(ImmutableSet.of("Lorg/test/Constants;"), dt.getAllDependencies().get(UriUtil.toFileString(docUri)));
assertEquals(ImmutableSet.of("org.test.Constants"), dt.getAllDependencies().get(UriUtil.toFileString(docUri)));
TestFileScanListener fileScanListener = new TestFileScanListener();
indexer.getJavaIndexer().setFileScanListener(fileScanListener);
@@ -135,7 +136,8 @@ public class RequestMappingSymbolProviderTest {
@Test
//TODO: Enable when JDT Core 3.41 or higher is adopted. See: https://github.com/eclipse-jdt/eclipse.jdt.core/pull/3416
@DisabledOnOs(OS.WINDOWS)
// additional comment: switched the string to not contain the "key" of the AST node, but the fully qualified type name, therefore enabling this again everywhere
// @DisabledOnOs(OS.WINDOWS)
void testUpdateDocumentWithConstantFromDifferentClass() throws Exception {
String docUri = directory.toPath().resolve("src/main/java/org/test/SimpleMappingClassWithConstantInDifferentClass.java").toUri().toString();
String constantsUri = directory.toPath().resolve("src/main/java/org/test/Constants.java").toUri().toString();
@@ -145,7 +147,7 @@ public class RequestMappingSymbolProviderTest {
//Verify whether dependency tracker logics works properly for this example.
SpringIndexerJavaDependencyTracker dt = indexer.getJavaIndexer().getDependencyTracker();
assertEquals(ImmutableSet.of("Lorg/test/Constants;"), dt.getAllDependencies().get(UriUtil.toFileString(docUri)));
assertEquals(ImmutableSet.of("org.test.Constants"), dt.getAllDependencies().get(UriUtil.toFileString(docUri)));
TestFileScanListener fileScanListener = new TestFileScanListener();
indexer.getJavaIndexer().setFileScanListener(fileScanListener);
@@ -153,7 +155,7 @@ public class RequestMappingSymbolProviderTest {
CompletableFuture<Void> updateFuture = indexer.updateDocument(docUri, FileUtils.readFileToString(UriUtil.toFile(docUri), Charset.defaultCharset()), "test triggered");
updateFuture.get(5, TimeUnit.SECONDS);
assertEquals(ImmutableSet.of("Lorg/test/Constants;"), dt.getAllDependencies().get(UriUtil.toFileString(docUri)));
assertEquals(ImmutableSet.of("org.test.Constants"), dt.getAllDependencies().get(UriUtil.toFileString(docUri)));
fileScanListener.assertScannedUris(docUri);
fileScanListener.assertScannedUri(constantsUri, 0);

View File

@@ -65,4 +65,8 @@ public class TestFileScanListener implements FileScanListener {
public void reset() {
scannedFiles.clear();
}
public void assertNoFileScans(int count) {
assertEquals(count, scannedFiles.size());
}
}

View File

@@ -4,7 +4,7 @@ import org.springframework.beans.factory.BeanRegistrar;
import org.springframework.beans.factory.BeanRegistry;
import org.springframework.core.env.Environment;
public class NotRegisterredBeanRegistrar implements BeanRegistrar {
public class NotRegisteredBeanRegistrar implements BeanRegistrar {
@Override
public void register(BeanRegistry registry, Environment env) {