From fc7cbf60fb35324ea81314e7f7651dd19561c533 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Fri, 26 Apr 2024 18:49:33 +0200 Subject: [PATCH] refactoring of reconciler design to avoid running through all the ast visitor mechanics for each validation --- .../AbstractSecurityLamdaDslReconciler.java | 39 +++-- ...ConfigurationIfBeansPresentReconciler.java | 49 +++--- .../reconcilers/AnnotationNodeReconciler.java | 34 +++-- .../AuthorizeHttpRequestsReconciler.java | 49 +++--- ...eldIntoConstructorParameterReconciler.java | 54 ++++--- .../BeanMethodNotPublicReconciler.java | 110 +++++++------- ...anPostProcessingIgnoreInAotReconciler.java | 48 +++--- .../Boot3NotSupportedTypeReconciler.java | 41 ++--- .../java/reconcilers/CompositeASTVisitor.java | 143 ++++++++++++++++++ .../EntityIdForRepoReconciler.java | 113 +++++++------- .../java/reconcilers/JdtAstReconciler.java | 5 +- .../boot/java/reconcilers/JdtReconciler.java | 61 ++++++-- ...ulithTypeReferenceViolationReconciler.java | 53 ++++--- .../NoAutowiredOnConstructorReconciler.java | 36 +++-- .../NoRepoAnnotationReconciler.java | 84 +++++----- .../NoRequestMappingAnnotationReconciler.java | 36 +++-- .../NotRegisteredBeansReconciler.java | 49 +++--- .../PreciseBeanTypeReconciler.java | 45 +++--- .../RequiredCompleteAstException.java | 2 +- .../UnnecessarySpringExtensionReconciler.java | 89 ++++++----- ...ebSecurityConfigurerAdapterReconciler.java | 41 ++--- .../boot/java/utils/SpringIndexerJava.java | 4 + 22 files changed, 731 insertions(+), 454 deletions(-) create mode 100644 headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/CompositeASTVisitor.java diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AbstractSecurityLamdaDslReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AbstractSecurityLamdaDslReconciler.java index 56624572d..132f9b1da 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AbstractSecurityLamdaDslReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AbstractSecurityLamdaDslReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -29,15 +29,23 @@ public abstract class AbstractSecurityLamdaDslReconciler implements JdtAstReconc private QuickfixRegistry registry; - AbstractSecurityLamdaDslReconciler(QuickfixRegistry registry) { + public AbstractSecurityLamdaDslReconciler(QuickfixRegistry registry) { this.registry = registry; } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + if (visitor != null) { + cu.accept(visitor); + } + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + if (isCompleteAst) { - cu.accept(new ASTVisitor() { + return new ASTVisitor() { @Override public boolean visit(MethodInvocation node) { @@ -66,28 +74,27 @@ public abstract class AbstractSecurityLamdaDslReconciler implements JdtAstReconc return true; } - }); + }; } else { if (ReconcileUtils.isAnyTypeUsed(cu, List.of(getTargetTypeFqName()))) { throw new RequiredCompleteAstException(); } + else { + return null; + } } } + protected abstract String getFixLabel(); + protected abstract String getRecipeId(); + protected abstract String getProblemLabel(); + abstract protected String getTargetTypeFqName(); + abstract protected Collection getApplicableMethodNames(); + private static MethodInvocation findTopLevelMethodInvocation(MethodInvocation m) { for (; m.getParent() instanceof MethodInvocation; m = (MethodInvocation) m.getParent()) {} return m; } - protected abstract String getFixLabel(); - - protected abstract String getRecipeId(); - - protected abstract String getProblemLabel(); - - abstract protected String getTargetTypeFqName(); - - abstract protected Collection getApplicableMethodNames(); - } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AddConfigurationIfBeansPresentReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AddConfigurationIfBeansPresentReconciler.java index 9b1c8e78b..4e853c124 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AddConfigurationIfBeansPresentReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AddConfigurationIfBeansPresentReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -48,21 +48,40 @@ import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor; public class AddConfigurationIfBeansPresentReconciler implements JdtAstReconciler, ApplicationContextAware { private static final String PROBLEM_LABEL = "'@Configuration' is missing on a class defining Spring Beans"; - private static final String FIX_LABEL = "Add missing '@Configuration' annotations over classes"; private QuickfixRegistry quickfixRegistry; - private ApplicationContext applicationContext; public AddConfigurationIfBeansPresentReconciler(QuickfixRegistry quickfixRegistry) { this.quickfixRegistry = quickfixRegistry; } + + @Override + public boolean isApplicable(IJavaProject project) { + Version version = SpringProjectUtil.getDependencyVersion(project, "spring-context"); + return version != null && version.compareTo(new Version(3, 0, 0, null)) >= 0; + } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) { - cu.accept(new ASTVisitor() { + public ProblemType getProblemType() { + return Boot2JavaProblemType.MISSING_CONFIGURATION_ANNOTATION; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + return new ASTVisitor() { @Override public boolean visit(TypeDeclaration classDecl) { @@ -86,7 +105,7 @@ public class AddConfigurationIfBeansPresentReconciler implements JdtAstReconcile return true; } - }); + }; } private boolean isApplicableClass(IJavaProject project, CompilationUnit cu, TypeDeclaration classDecl) { @@ -179,20 +198,4 @@ public class AddConfigurationIfBeansPresentReconciler implements JdtAstReconcile return false; } - @Override - public boolean isApplicable(IJavaProject project) { - Version version = SpringProjectUtil.getDependencyVersion(project, "spring-context"); - return version != null && version.compareTo(new Version(3, 0, 0, null)) >= 0; - } - - @Override - public ProblemType getProblemType() { - return Boot2JavaProblemType.MISSING_CONFIGURATION_ANNOTATION; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AnnotationNodeReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AnnotationNodeReconciler.java index 7ece477f2..15f1d8435 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AnnotationNodeReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AnnotationNodeReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -75,11 +75,27 @@ public class AnnotationNodeReconciler implements JdtAstReconciler { }; config.addListener(evt -> this.spelExpressionReconciler.setEnabled(config.isSpelExpressionValidationEnabled())); } + + @Override + public boolean isApplicable(IJavaProject project) { + return true; + } + @Override + public ProblemType getProblemType() { + return SpelProblemType.JAVA_SPEL_EXPRESSION_SYNTAX; + } @Override public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { - cu.accept(new ASTVisitor() { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, + IProblemCollector problemCollector, boolean isCompleteAst) { + return new ASTVisitor() { @Override public boolean visit(SingleMemberAnnotation node) { @@ -111,7 +127,7 @@ public class AnnotationNodeReconciler implements JdtAstReconciler { return super.visit(node); } - }); + }; } private void visitAnnotation(IJavaProject project, URI docUri, Annotation node, IProblemCollector problemCollector) { @@ -123,16 +139,4 @@ public class AnnotationNodeReconciler implements JdtAstReconciler { } } - - @Override - public boolean isApplicable(IJavaProject project) { - return true; - } - - - @Override - public ProblemType getProblemType() { - return SpelProblemType.JAVA_SPEL_EXPRESSION_SYNTAX; - } - } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AuthorizeHttpRequestsReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AuthorizeHttpRequestsReconciler.java index a0369ccda..62a8f9a3b 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AuthorizeHttpRequestsReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AuthorizeHttpRequestsReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -32,17 +32,11 @@ import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor; public class AuthorizeHttpRequestsReconciler implements JdtAstReconciler { private static final String FQN_HTTP_SECURITY = "org.springframework.security.config.annotation.web.builders.HttpSecurity"; - private static final String AUTHORIZE_REQUESTS = "authorizeRequests"; - private static final String AUTHORIZE_REQUESTS_PROBLEM_LABEL = "HttpSecurity API 'authorizeRequests(...)' is outdated"; - private static final String AUTHORIZE_REQUESTS_FIX_LABEL = "Replace with 'authorizeHttpRequests(...)' and related types"; - private static final String FQN_INTERCEPTOR_URL_CONFIG = "org.springframework.security.config.annotation.web.configurers.AbstractInterceptUrlConfigurer"; - private static final String FQN_EXPR_AUTH_CONFIG = "org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer"; - private static final String FQN_EXPR_INTERCEPT_REG = "org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry"; private QuickfixRegistry registry; @@ -52,10 +46,29 @@ public class AuthorizeHttpRequestsReconciler implements JdtAstReconciler { } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { + public boolean isApplicable(IJavaProject project) { + Version version = SpringProjectUtil.getDependencyVersion(project, "spring-security-config"); + return version != null && version.compareTo(new Version(5, 6, 0, null)) >= 0; + } + + @Override + public ProblemType getProblemType() { + return Boot2JavaProblemType.HTTP_SECURITY_AUTHORIZE_HTTP_REQUESTS; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + if (visitor != null) { + cu.accept(visitor); + } + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + if (isCompleteAst) { - cu.accept(new ASTVisitor() { + return new ASTVisitor() { @Override public boolean visit(MethodInvocation node) { @@ -84,7 +97,7 @@ public class AuthorizeHttpRequestsReconciler implements JdtAstReconciler { return true; } - }); + }; } else { boolean needsFullAst = ReconcileUtils.isAnyTypeUsed(cu, List.of( FQN_HTTP_SECURITY, @@ -92,21 +105,13 @@ public class AuthorizeHttpRequestsReconciler implements JdtAstReconciler { FQN_EXPR_AUTH_CONFIG, FQN_EXPR_INTERCEPT_REG )); + if (needsFullAst) { throw new RequiredCompleteAstException(); } + + return null; } } - @Override - public boolean isApplicable(IJavaProject project) { - Version version = SpringProjectUtil.getDependencyVersion(project, "spring-security-config"); - return version != null && version.compareTo(new Version(5, 6, 0, null)) >= 0; - } - - @Override - public ProblemType getProblemType() { - return Boot2JavaProblemType.HTTP_SECURITY_AUTHORIZE_HTTP_REQUESTS; - } - } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AutowiredFieldIntoConstructorParameterReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AutowiredFieldIntoConstructorParameterReconciler.java index d8acc8537..56d017f7e 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AutowiredFieldIntoConstructorParameterReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AutowiredFieldIntoConstructorParameterReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -18,7 +18,6 @@ import java.nio.file.Paths; import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import org.eclipse.jdt.core.dom.ASTVisitor; @@ -57,14 +56,32 @@ public class AutowiredFieldIntoConstructorParameterReconciler implements JdtAstR } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { + public boolean isApplicable(IJavaProject project) { + return springBootVersionGreaterOrEqual(2, 0, 0).test(project); + } + + @Override + public ProblemType getProblemType() { + return Boot2JavaProblemType.JAVA_CONSTRUCTOR_PARAMETER_INJECTION; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + if (visitor != null) { + cu.accept(visitor); + } + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + Path sourceFile = Paths.get(docUri); // Check if source file belongs to non-test java sources folder if (IClasspathUtil.getProjectJavaSourceFoldersWithoutTests(project.getClasspath()) .anyMatch(f -> sourceFile.startsWith(f.toPath()))) { - AtomicBoolean completeAstRequired = new AtomicBoolean(false); - cu.accept(new ASTVisitor() { + + return new ASTVisitor() { @Override public boolean visit(FieldDeclaration field) { @@ -84,8 +101,7 @@ public class AutowiredFieldIntoConstructorParameterReconciler implements JdtAstR problemCollector.accept(createProblem(cu, field, fieldName, docUri)); } else if (constructors.size() == 1) { if (!isCompleteAst) { - completeAstRequired.set(true); - return false; + throw new RequiredCompleteAstException(); } if (!isAssigningField(constructors.get(0), variableDeclarationFragment.resolveBinding(), fieldName)) { @@ -98,8 +114,7 @@ public class AutowiredFieldIntoConstructorParameterReconciler implements JdtAstR .limit(2).collect(Collectors.toList()); if (autowiredConstructors.size() == 1) { if (!isCompleteAst) { - completeAstRequired.set(true); - return false; + throw new RequiredCompleteAstException(); } else if (!isAssigningField(autowiredConstructors.get(0), variableDeclarationFragment.resolveBinding(), fieldName)) { problemCollector.accept(createProblem(cu, field, fieldName, docUri)); @@ -112,12 +127,11 @@ public class AutowiredFieldIntoConstructorParameterReconciler implements JdtAstR return true; } - }); - if (completeAstRequired.get()) { - throw new RequiredCompleteAstException(); - } + }; + } + else { + return null; } - } private ReconcileProblemImpl createProblem(CompilationUnit cu, FieldDeclaration field, String fieldName, @@ -157,14 +171,4 @@ public class AutowiredFieldIntoConstructorParameterReconciler implements JdtAstR return false; } - @Override - public boolean isApplicable(IJavaProject project) { - return springBootVersionGreaterOrEqual(2, 0, 0).test(project); - } - - @Override - public ProblemType getProblemType() { - return Boot2JavaProblemType.JAVA_CONSTRUCTOR_PARAMETER_INJECTION; - } - } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/BeanMethodNotPublicReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/BeanMethodNotPublicReconciler.java index b767ba0ea..30f67e703 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/BeanMethodNotPublicReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/BeanMethodNotPublicReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022, 2023 VMware, Inc. + * Copyright (c) 2022, 2024 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 @@ -46,8 +46,7 @@ import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor; public class BeanMethodNotPublicReconciler implements JdtAstReconciler { private static final Logger log = LoggerFactory.getLogger(BeanMethodNotPublicReconciler.class); - - private static final String LABEL = "Remove 'public' from @Bean method"; + private static final String LABEL = "Remove 'public' from @Bean method"; private final QuickfixRegistry quickfixRegistry; @@ -55,6 +54,62 @@ public class BeanMethodNotPublicReconciler implements JdtAstReconciler { this.quickfixRegistry = quickfixRegistry; } + @Override + public boolean isApplicable(IJavaProject project) { + Version version = SpringProjectUtil.getDependencyVersion(project, SpringProjectUtil.SPRING_BOOT); + return version != null && version.getMajor() >= 2; + } + + @Override + public ProblemType getProblemType() { + return Boot2JavaProblemType.JAVA_PUBLIC_BEAN_METHOD; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + + return new ASTVisitor() { + + @Override + public boolean visit(SingleMemberAnnotation node) { + try { + visitAnnotation(project, cu, docUri, node, problemCollector); + } catch (Exception e) { + } + return super.visit(node); + } + + @Override + public boolean visit(NormalAnnotation node) { + try { + visitAnnotation(project, cu, docUri, node, problemCollector); + } catch (Exception e) { + } + return super.visit(node); + } + + @Override + public boolean visit(MarkerAnnotation node) { + try { + visitAnnotation(project, cu, docUri, node, problemCollector); + } catch (Exception e) { + } + return super.visit(node); + } + + }; + } + + public static final boolean isNotOverridingPublicMethod(IMethodBinding methodBinding) { + return !isOverriding(methodBinding) && (methodBinding.getModifiers() & Modifier.PUBLIC) != 0; + } + private void visitAnnotation(IJavaProject project, CompilationUnit cu, URI docUri, Annotation node, IProblemCollector problemCollector) { ITypeBinding typeBinding = node.resolveTypeBinding(); if (typeBinding != null && Annotations.BEAN.equals(typeBinding.getQualifiedName()) && node.getParent() instanceof MethodDeclaration) { @@ -95,10 +150,6 @@ public class BeanMethodNotPublicReconciler implements JdtAstReconciler { return false; } - public static final boolean isNotOverridingPublicMethod(IMethodBinding methodBinding) { - return !isOverriding(methodBinding) && (methodBinding.getModifiers() & Modifier.PUBLIC) != 0; - } - private void addQuickFixes(CompilationUnit cu, URI docUri, ReconcileProblemImpl problem, MethodDeclaration method) { if (quickfixRegistry != null) { @@ -130,49 +181,4 @@ public class BeanMethodNotPublicReconciler implements JdtAstReconciler { } } - @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { - cu.accept(new ASTVisitor() { - - @Override - public boolean visit(SingleMemberAnnotation node) { - try { - visitAnnotation(project, cu, docUri, node, problemCollector); - } catch (Exception e) { - } - return super.visit(node); - } - - @Override - public boolean visit(NormalAnnotation node) { - try { - visitAnnotation(project, cu, docUri, node, problemCollector); - } catch (Exception e) { - } - return super.visit(node); - } - - @Override - public boolean visit(MarkerAnnotation node) { - try { - visitAnnotation(project, cu, docUri, node, problemCollector); - } catch (Exception e) { - } - return super.visit(node); - } - - }); - } - - @Override - public boolean isApplicable(IJavaProject project) { - Version version = SpringProjectUtil.getDependencyVersion(project, SpringProjectUtil.SPRING_BOOT); - return version != null && version.getMajor() >= 2; - } - - @Override - public ProblemType getProblemType() { - return Boot2JavaProblemType.JAVA_PUBLIC_BEAN_METHOD; - } - } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/BeanPostProcessingIgnoreInAotReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/BeanPostProcessingIgnoreInAotReconciler.java index 11272ff1b..12d0ffea7 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/BeanPostProcessingIgnoreInAotReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/BeanPostProcessingIgnoreInAotReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -44,12 +44,27 @@ public class BeanPostProcessingIgnoreInAotReconciler implements JdtAstReconciler public BeanPostProcessingIgnoreInAotReconciler(QuickfixRegistry registry) { this.registry = registry; } + + @Override + public boolean isApplicable(IJavaProject project) { + return springBootVersionGreaterOrEqual(3, 0, 0).test(project); + } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { - AtomicBoolean requiresFullAst = new AtomicBoolean(false); - cu.accept(new ASTVisitor() { + public ProblemType getProblemType() { + return SpringAotJavaProblemType.JAVA_BEAN_POST_PROCESSOR_IGNORED_IN_AOT; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + + return new ASTVisitor() { @Override public boolean visit(TypeDeclaration typeDecl) { @@ -77,7 +92,7 @@ public class BeanPostProcessingIgnoreInAotReconciler implements JdtAstReconciler }); markProblem = returnsTrue.get(); } else { - requiresFullAst.set(true); + throw new RequiredCompleteAstException(); } } else { markProblem = true; @@ -93,27 +108,14 @@ public class BeanPostProcessingIgnoreInAotReconciler implements JdtAstReconciler problemCollector.accept(problem); } } - return !requiresFullAst.get(); + return true; } - private boolean isApplicable(ITypeBinding type) { - return ReconcileUtils.implementsType(RUNTIME_BEAN_POST_PROCESSOR, type) && ReconcileUtils.implementsType(COMPILE_BEAN_POST_PROCESSOR, type); - } - - }); - if (requiresFullAst.get()) { - throw new RequiredCompleteAstException(); - } + }; } - @Override - public boolean isApplicable(IJavaProject project) { - return springBootVersionGreaterOrEqual(3, 0, 0).test(project); - } - - @Override - public ProblemType getProblemType() { - return SpringAotJavaProblemType.JAVA_BEAN_POST_PROCESSOR_IGNORED_IN_AOT; + private static boolean isApplicable(ITypeBinding type) { + return ReconcileUtils.implementsType(RUNTIME_BEAN_POST_PROCESSOR, type) && ReconcileUtils.implementsType(COMPILE_BEAN_POST_PROCESSOR, type); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/Boot3NotSupportedTypeReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/Boot3NotSupportedTypeReconciler.java index 5b2c62d2d..220ceed54 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/Boot3NotSupportedTypeReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/Boot3NotSupportedTypeReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -33,11 +33,26 @@ public class Boot3NotSupportedTypeReconciler implements JdtAstReconciler { "java.lang.SecurityManager", "java.security.AccessControlException" ); + + @Override + public boolean isApplicable(IJavaProject project) { + return springBootVersionGreaterOrEqual(3, 0, 0).test(project); + } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { - cu.accept(new ASTVisitor() { + public ProblemType getProblemType() { + return Boot3JavaProblemType.JAVA_TYPE_NOT_SUPPORTED; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + return new ASTVisitor() { @Override public boolean visit(ImportDeclaration node) { @@ -57,10 +72,10 @@ public class Boot3NotSupportedTypeReconciler implements JdtAstReconciler { return super.visit(node); } - }); + }; } - - private String processType(CompilationUnit cu, String name) { + + private static String processType(CompilationUnit cu, String name) { if (TYPE_FQNAMES.contains(name)) { return name; } else { @@ -73,7 +88,7 @@ public class Boot3NotSupportedTypeReconciler implements JdtAstReconciler { return null; } - private List createFqNamesFromWildcardImports(CompilationUnit cu, String name) { + private static List createFqNamesFromWildcardImports(CompilationUnit cu, String name) { List fqNames = new ArrayList<>(); for (Object im : cu.imports()) { ImportDeclaration importDecl = (ImportDeclaration) im; @@ -84,16 +99,6 @@ public class Boot3NotSupportedTypeReconciler implements JdtAstReconciler { return fqNames; } - @Override - public boolean isApplicable(IJavaProject project) { - return springBootVersionGreaterOrEqual(3, 0, 0).test(project); - } - - @Override - public ProblemType getProblemType() { - return Boot3JavaProblemType.JAVA_TYPE_NOT_SUPPORTED; - } - private static String createLabel(String type) { StringBuilder sb = new StringBuilder(); sb.append("'"); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/CompositeASTVisitor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/CompositeASTVisitor.java new file mode 100644 index 000000000..904d153d6 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/CompositeASTVisitor.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2024 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.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.ImportDeclaration; +import org.eclipse.jdt.core.dom.MarkerAnnotation; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.NormalAnnotation; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.SimpleType; +import org.eclipse.jdt.core.dom.SingleMemberAnnotation; +import org.eclipse.jdt.core.dom.TypeDeclaration; + +public class CompositeASTVisitor extends ASTVisitor { + + List visitors = new ArrayList<>(); + + public void add(ASTVisitor visitor) { + visitors.add(visitor); + } + + @Override + public boolean visit(TypeDeclaration node) { + boolean result = true; + for (ASTVisitor astVisitor : visitors) { + result &= astVisitor.visit(node); + } + return result; + } + + @Override + public boolean visit(MethodInvocation node) { + boolean result = true; + for (ASTVisitor astVisitor : visitors) { + result &= astVisitor.visit(node); + } + return result; + } + + @Override + public boolean visit(MethodDeclaration node) { + boolean result = true; + for (ASTVisitor astVisitor : visitors) { + result &= astVisitor.visit(node); + } + return result; + } + + @Override + public void endVisit(MethodDeclaration node) { + for (ASTVisitor astVisitor : visitors) { + astVisitor.endVisit(node); + } + } + + @Override + public boolean visit(FieldDeclaration node) { + boolean result = true; + for (ASTVisitor astVisitor : visitors) { + result &= astVisitor.visit(node); + } + return result; + } + + @Override + public boolean visit(SingleMemberAnnotation node) { + boolean result = true; + for (ASTVisitor astVisitor : visitors) { + result &= astVisitor.visit(node); + } + return result; + } + + @Override + public boolean visit(NormalAnnotation node) { + boolean result = true; + for (ASTVisitor astVisitor : visitors) { + result &= astVisitor.visit(node); + } + return result; + } + + @Override + public boolean visit(MarkerAnnotation node) { + boolean result = true; + for (ASTVisitor astVisitor : visitors) { + result &= astVisitor.visit(node); + } + return result; + } + + @Override + public boolean visit(ImportDeclaration node) { + boolean result = true; + for (ASTVisitor astVisitor : visitors) { + result &= astVisitor.visit(node); + } + return result; + } + + @Override + public boolean visit(SimpleType node) { + boolean result = true; + for (ASTVisitor astVisitor : visitors) { + result &= astVisitor.visit(node); + } + return result; + } + + @Override + public boolean visit(QualifiedName node) { + boolean result = true; + for (ASTVisitor astVisitor : visitors) { + result &= astVisitor.visit(node); + } + return result; + } + + @Override + public boolean visit(ReturnStatement node) { + boolean result = true; + for (ASTVisitor astVisitor : visitors) { + result &= astVisitor.visit(node); + } + return result; + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/EntityIdForRepoReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/EntityIdForRepoReconciler.java index 9406894d2..ac82bf8ff 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/EntityIdForRepoReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/EntityIdForRepoReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -55,12 +55,31 @@ public class EntityIdForRepoReconciler implements JdtAstReconciler { Double.class.getName(), Byte.class.getName() ); + + @Override + public boolean isApplicable(IJavaProject project) { + return springBootVersionGreaterOrEqual(2, 0, 0).test(project); + } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { - final boolean considerIdField = project.getClasspath().findBinaryLibrary("spring-data-mongodb-").isPresent(); - cu.accept(new ASTVisitor() { + public ProblemType getProblemType() { + return Boot2JavaProblemType.DOMAIN_ID_FOR_REPOSITORY; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + if (visitor != null) { + cu.accept(visitor); + } + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + + return new ASTVisitor() { + + final boolean considerIdField = project.getClasspath().findBinaryLibrary("spring-data-mongodb-").isPresent(); @Override public boolean visit(TypeDeclaration typeDecl) { @@ -216,22 +235,6 @@ public class EntityIdForRepoReconciler implements JdtAstReconciler { } } - private ITypeBinding getTypeFromAnnotationParameter(IAnnotationBinding a, String param) { - for (IMemberValuePairBinding pair : a.getDeclaredMemberValuePairs()) { - if (pair.getName().equals(param)) { - if (pair.getValue() instanceof ITypeBinding) { - return (ITypeBinding) pair.getValue(); - } else if (pair.getValue() instanceof Object[]) { - Object[] arr = (Object[]) pair.getValue(); - if (arr.length > 0 && arr[0] instanceof ITypeBinding) { - return (ITypeBinding) arr[0]; - } - } - } - } - return null; - } - private List findIdType(ITypeBinding type) { List idTypes = findAnnotatedIdTypes(type, new HashSet<>()); if (idTypes.isEmpty() && considerIdField) { @@ -243,40 +246,47 @@ public class EntityIdForRepoReconciler implements JdtAstReconciler { return idTypes; } - private boolean isValidRepoIdType(ITypeBinding repoIdType, ITypeBinding idType) { - if (NUMBER_CLASS_NAMES.contains(repoIdType.getQualifiedName()) && NUMBER_CLASS_NAMES.contains(idType.getQualifiedName())) { - return true; + }; + + } + + private static boolean isValidRepoIdType(ITypeBinding repoIdType, ITypeBinding idType) { + if (NUMBER_CLASS_NAMES.contains(repoIdType.getQualifiedName()) && NUMBER_CLASS_NAMES.contains(idType.getQualifiedName())) { + return true; + } + return repoIdType.isCastCompatible(idType) || idType.isCastCompatible(repoIdType); + } + + private static ITypeBinding getTypeFromAnnotationParameter(IAnnotationBinding a, String param) { + for (IMemberValuePairBinding pair : a.getDeclaredMemberValuePairs()) { + if (pair.getName().equals(param)) { + if (pair.getValue() instanceof ITypeBinding) { + return (ITypeBinding) pair.getValue(); + } else if (pair.getValue() instanceof Object[]) { + Object[] arr = (Object[]) pair.getValue(); + if (arr.length > 0 && arr[0] instanceof ITypeBinding) { + return (ITypeBinding) arr[0]; + } } - return repoIdType.isCastCompatible(idType) || idType.isCastCompatible(repoIdType); } - - }); - } - - @Override - public boolean isApplicable(IJavaProject project) { - return springBootVersionGreaterOrEqual(2, 0, 0).test(project); - } - - @Override - public ProblemType getProblemType() { - return Boot2JavaProblemType.DOMAIN_ID_FOR_REPOSITORY; - } - - public static void findSuperTypeBindings(ITypeBinding binding, Set superTypes) { - // superclasses - ITypeBinding superclass = binding.getSuperclass(); - if (superclass != null) { - superTypes.add(superclass); - findSuperTypeBindings(superclass, superTypes); - } - // interfaces - for (ITypeBinding i : binding.getInterfaces()) { - superTypes.add(i); - findSuperTypeBindings(i, superTypes); } + return null; } +// public static void findSuperTypeBindings(ITypeBinding binding, Set superTypes) { +// // superclasses +// ITypeBinding superclass = binding.getSuperclass(); +// if (superclass != null) { +// superTypes.add(superclass); +// findSuperTypeBindings(superclass, superTypes); +// } +// // interfaces +// for (ITypeBinding i : binding.getInterfaces()) { +// superTypes.add(i); +// findSuperTypeBindings(i, superTypes); +// } +// } +// private static @Nullable List findRepoTypeChain(ITypeBinding type, List visited) { if (visited.stream().anyMatch(b -> b.isEqualTo(type))) { return null; @@ -404,7 +414,7 @@ public class EntityIdForRepoReconciler implements JdtAstReconciler { return true; } - private List findParamTypes(List typeParams, ITypeBinding idType) { + private static List findParamTypes(List typeParams, ITypeBinding idType) { List matchedParams = new ArrayList<>(); for (Object o : typeParams) { if (o instanceof TypeParameter) { @@ -424,4 +434,5 @@ public class EntityIdForRepoReconciler implements JdtAstReconciler { return matchedParams; } + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtAstReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtAstReconciler.java index 6f6177f0d..411e7faf2 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtAstReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtAstReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -12,6 +12,7 @@ package org.springframework.ide.vscode.boot.java.reconcilers; 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; @@ -25,4 +26,6 @@ public interface JdtAstReconciler { ProblemType getProblemType(); + ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst); + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtReconciler.java index c9eac4d01..ea6fac9f3 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtReconciler.java @@ -17,6 +17,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.CompilationUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,13 +50,19 @@ public class JdtReconciler implements JavaReconciler { private final CompilationUnitCache compilationUnitCache; private final JdtAstReconciler[] reconcilers; private BootJavaConfig config; + + private long stats_timer; + private long stats_counter; public JdtReconciler(CompilationUnitCache compilationUnitCache, BootJavaConfig config, JdtAstReconciler[] reconcilers) { this.compilationUnitCache = compilationUnitCache; this.config = config; this.reconcilers = reconcilers; + + this.stats_timer = 0; + this.stats_counter = 0; } - + @Override public void reconcile(IJavaProject project, final IDocument doc, final IProblemCollector problemCollector) { if (!config.isJavaSourceReconcileEnabled()) { @@ -76,20 +83,48 @@ public class JdtReconciler implements JavaReconciler { return null; }); } + + public ASTVisitor createCompositeVisitor(IJavaProject project, URI docURI, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + CompositeASTVisitor compositeVisitor = new CompositeASTVisitor(); + + for (JdtAstReconciler reconciler : getApplicableReconcilers(project)) { + ASTVisitor visitor = reconciler.createVisitor(project, docURI, cu, problemCollector, isCompleteAst); + + if (visitor != null) { + compositeVisitor.add(visitor); + } + } + + return compositeVisitor; + } public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + long start = System.currentTimeMillis(); + if (!config.isJavaSourceReconcileEnabled()) { return; } - for (JdtAstReconciler reconciler : getApplicableReconcilers(project)) { - try { - reconciler.reconcile(project, docUri, cu, problemCollector, isCompleteAst); - } catch (RequiredCompleteAstException e) { - throw e; - } catch (Exception e) { - log.error("", e); - } + + try { + ASTVisitor compositeVisitor = createCompositeVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(compositeVisitor); + +// for (JdtAstReconciler reconciler : getApplicableReconcilers(project)) { +// try { +// reconciler.reconcile(project, docUri, cu, problemCollector, isCompleteAst); +// } catch (RequiredCompleteAstException e) { +// throw e; +// } catch (Exception e) { +// log.error("", e); +// } +// } + } + finally { + long end = System.currentTimeMillis(); + + stats_counter++; + stats_timer += (end - start); } } @@ -120,5 +155,13 @@ public class JdtReconciler implements JavaReconciler { return Collections.emptyMap(); } + public long getStatsTimer() { + return stats_timer; + } + + public long getStatsCounter() { + return stats_counter; + } + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/ModulithTypeReferenceViolationReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/ModulithTypeReferenceViolationReconciler.java index d59230f86..a3a65104c 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/ModulithTypeReferenceViolationReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/ModulithTypeReferenceViolationReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -35,19 +35,44 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.Reconcile public class ModulithTypeReferenceViolationReconciler implements JdtAstReconciler, ApplicationContextAware { private ApplicationContext appContext; + + @Override + public boolean isApplicable(IJavaProject project) { + return ModulithService.isModulithDependentProject(project); + } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { + public ProblemType getProblemType() { + return Boot3JavaProblemType.MODULITH_TYPE_REF_VIOLATION; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.appContext = applicationContext; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + if (visitor != null) { + cu.accept(visitor); + } + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + Path sourceFile = Paths.get(docUri); if (IClasspathUtil.getProjectJavaSourceFoldersWithoutTests(project.getClasspath()) .anyMatch(f -> sourceFile.startsWith(f.toPath()))) { + ModulithService modulithService = appContext.getBean(ModulithService.class); AppModules appModules = modulithService.getModulesData(project); if (appModules != null) { final String packageName = cu.getPackage().getName().getFullyQualifiedName(); - cu.accept(new ASTVisitor() { + + return new ASTVisitor() { @Override public boolean visit(QualifiedName node) { @@ -71,25 +96,11 @@ public class ModulithTypeReferenceViolationReconciler implements JdtAstReconcile } } - }); - + }; } } - } - - @Override - public boolean isApplicable(IJavaProject project) { - return ModulithService.isModulithDependentProject(project); - } - - @Override - public ProblemType getProblemType() { - return Boot3JavaProblemType.MODULITH_TYPE_REF_VIOLATION; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.appContext = applicationContext; + + return null; } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoAutowiredOnConstructorReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoAutowiredOnConstructorReconciler.java index 197fdf658..609ff5511 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoAutowiredOnConstructorReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoAutowiredOnConstructorReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -45,9 +45,25 @@ public class NoAutowiredOnConstructorReconciler implements JdtAstReconciler { } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { - cu.accept(new ASTVisitor() { + public boolean isApplicable(IJavaProject project) { + return springBootVersionGreaterOrEqual(2, 0, 0).test(project); + } + + @Override + public ProblemType getProblemType() { + return Boot2JavaProblemType.JAVA_AUTOWIRED_CONSTRUCTOR; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + + return new ASTVisitor() { @Override public boolean visit(TypeDeclaration typeDecl) { @@ -86,17 +102,7 @@ public class NoAutowiredOnConstructorReconciler implements JdtAstReconciler { return super.visit(typeDecl); } - }); - } - - @Override - public boolean isApplicable(IJavaProject project) { - return springBootVersionGreaterOrEqual(2, 0, 0).test(project); - } - - @Override - public ProblemType getProblemType() { - return Boot2JavaProblemType.JAVA_AUTOWIRED_CONSTRUCTOR; + }; } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoRepoAnnotationReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoRepoAnnotationReconciler.java index 759fdd904..a722dfbb2 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoRepoAnnotationReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoRepoAnnotationReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -44,10 +44,25 @@ public class NoRepoAnnotationReconciler implements JdtAstReconciler { } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { - cu.accept(new ASTVisitor() { + public boolean isApplicable(IJavaProject project) { + return springBootVersionGreaterOrEqual(2, 0, 0).test(project); + } + @Override + public Boot2JavaProblemType getProblemType() { + return Boot2JavaProblemType.JAVA_REPOSITORY; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + + return new ASTVisitor() { @Override public boolean visit(TypeDeclaration typeDecl) { @@ -80,46 +95,35 @@ public class NoRepoAnnotationReconciler implements JdtAstReconciler { } return super.visit(typeDecl); } - - private boolean isApplicableRepoAnnotation(Annotation a) { - if (a instanceof MarkerAnnotation || (a.isNormalAnnotation() && ((NormalAnnotation) a).properties().isEmpty())) { - String typeName = a.getTypeName().getFullyQualifiedName(); - if (Annotations.REPOSITORY.equals(typeName)) { - return true; - } else if (typeName.endsWith("Repository")) { - ITypeBinding type = a.resolveTypeBinding(); - if (type != null && Annotations.REPOSITORY.equals(type.getQualifiedName())) { - return true; - } - } - } - return false; - } - - private boolean isRepo(ITypeBinding t) { - if (INTERFACE_REPOSITORY.equals(t.getQualifiedName())) { + }; + } + + private static boolean isApplicableRepoAnnotation(Annotation a) { + if (a instanceof MarkerAnnotation || (a.isNormalAnnotation() && ((NormalAnnotation) a).properties().isEmpty())) { + String typeName = a.getTypeName().getFullyQualifiedName(); + if (Annotations.REPOSITORY.equals(typeName)) { + return true; + } else if (typeName.endsWith("Repository")) { + ITypeBinding type = a.resolveTypeBinding(); + if (type != null && Annotations.REPOSITORY.equals(type.getQualifiedName())) { return true; - } else { - for (ITypeBinding st : t.getInterfaces()) { - if (isRepo(st)) { - return true; - } - } } - return false; } - - }); + } + return false; } - - @Override - public boolean isApplicable(IJavaProject project) { - return springBootVersionGreaterOrEqual(2, 0, 0).test(project); - } - - @Override - public Boot2JavaProblemType getProblemType() { - return Boot2JavaProblemType.JAVA_REPOSITORY; + + private static boolean isRepo(ITypeBinding t) { + if (INTERFACE_REPOSITORY.equals(t.getQualifiedName())) { + return true; + } else { + for (ITypeBinding st : t.getInterfaces()) { + if (isRepo(st)) { + return true; + } + } + } + return false; } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoRequestMappingAnnotationReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoRequestMappingAnnotationReconciler.java index 8f9a7b213..693a2bdee 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoRequestMappingAnnotationReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/NoRequestMappingAnnotationReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -57,11 +57,27 @@ public class NoRequestMappingAnnotationReconciler implements JdtAstReconciler { public NoRequestMappingAnnotationReconciler(QuickfixRegistry registry) { this.registry = registry; } + + @Override + public boolean isApplicable(IJavaProject project) { + return springBootVersionGreaterOrEqual(2, 0, 0).test(project); + } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { - cu.accept(new ASTVisitor() { + public ProblemType getProblemType() { + return Boot2JavaProblemType.JAVA_PRECISE_REQUEST_MAPPING; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + + return new ASTVisitor() { @Override public boolean visit(MarkerAnnotation node) { @@ -109,7 +125,7 @@ public class NoRequestMappingAnnotationReconciler implements JdtAstReconciler { } } - }); + }; } private static FixDescriptor createFixDescriptor(String uri, Range range, String requestMethod) { @@ -162,14 +178,4 @@ public class NoRequestMappingAnnotationReconciler implements JdtAstReconciler { return SUPPORTED_REQUEST_METHODS.contains(requestMethod) ? requestMethod : UNSUPPORTED_REQUEST_METHOD; } - @Override - public boolean isApplicable(IJavaProject project) { - return springBootVersionGreaterOrEqual(2, 0, 0).test(project); - } - - @Override - public ProblemType getProblemType() { - return Boot2JavaProblemType.JAVA_PRECISE_REQUEST_MAPPING; - } - } 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 35b901d73..36f29b5ea 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2204 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 @@ -64,14 +64,34 @@ public class NotRegisteredBeansReconciler implements JdtAstReconciler, Applicati private QuickfixRegistry registry; public NotRegisteredBeansReconciler(QuickfixRegistry registry) { - this.registry = registry; - + this.registry = registry; } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { - cu.accept(new ASTVisitor() { + public boolean isApplicable(IJavaProject project) { + return springBootVersionGreaterOrEqual(3, 0, 0).test(project); + } + + @Override + public ProblemType getProblemType() { + return SpringAotJavaProblemType.JAVA_BEAN_NOT_REGISTERED_IN_AOT; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + + return new ASTVisitor() { @Override public boolean visit(TypeDeclaration node) { @@ -146,24 +166,9 @@ public class NotRegisteredBeansReconciler implements JdtAstReconciler, Applicati return super.visit(node); } - }); + }; } - @Override - public boolean isApplicable(IJavaProject project) { - return springBootVersionGreaterOrEqual(3, 0, 0).test(project); - } - - @Override - public ProblemType getProblemType() { - return SpringAotJavaProblemType.JAVA_BEAN_NOT_REGISTERED_IN_AOT; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - private static Set allFQTypes(IBinding binding) { ImmutableSet.Builder b = ImmutableSet.builder(); if (binding instanceof IMethodBinding) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/PreciseBeanTypeReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/PreciseBeanTypeReconciler.java index db1e50eeb..f2363e294 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/PreciseBeanTypeReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/PreciseBeanTypeReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -17,7 +17,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.ListIterator; -import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.CompilationUnit; @@ -45,14 +44,28 @@ public class PreciseBeanTypeReconciler implements JdtAstReconciler { public PreciseBeanTypeReconciler(QuickfixRegistry registry) { this.registry = registry; - + } + + @Override + public boolean isApplicable(IJavaProject project) { + return springBootVersionGreaterOrEqual(3, 0, 0).test(project); } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { - AtomicBoolean requiresCompleteAst = new AtomicBoolean(false); - cu.accept(new ASTVisitor() { + public ProblemType getProblemType() { + return SpringAotJavaProblemType.JAVA_CONCRETE_BEAN_TYPE; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + + return new ASTVisitor() { private MethodDeclaration currentMethod; @@ -72,7 +85,7 @@ public class PreciseBeanTypeReconciler implements JdtAstReconciler { return true; } } else { - requiresCompleteAst.set(true); + throw new RequiredCompleteAstException(); } } } @@ -124,21 +137,7 @@ public class PreciseBeanTypeReconciler implements JdtAstReconciler { return super.visit(node); } - }); - - if (requiresCompleteAst.get()) { - throw new RequiredCompleteAstException(); - } - } - - @Override - public boolean isApplicable(IJavaProject project) { - return springBootVersionGreaterOrEqual(3, 0, 0).test(project); - } - - @Override - public ProblemType getProblemType() { - return SpringAotJavaProblemType.JAVA_CONCRETE_BEAN_TYPE; + }; } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/RequiredCompleteAstException.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/RequiredCompleteAstException.java index 8b61a497e..c6127ad26 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/RequiredCompleteAstException.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/RequiredCompleteAstException.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.reconcilers; -public class RequiredCompleteAstException extends Exception { +public class RequiredCompleteAstException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/UnnecessarySpringExtensionReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/UnnecessarySpringExtensionReconciler.java index f6deb2215..d26bd721b 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/UnnecessarySpringExtensionReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/UnnecessarySpringExtensionReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -61,13 +61,28 @@ public class UnnecessarySpringExtensionReconciler implements JdtAstReconciler { public UnnecessarySpringExtensionReconciler(QuickfixRegistry registry) { this.registry = registry; - } + @Override + public boolean isApplicable(IJavaProject project) { + return springBootVersionGreaterOrEqual(2, 1, 0).test(project); + } + + @Override + public Boot2JavaProblemType getProblemType() { + return Boot2JavaProblemType.JAVA_TEST_SPRING_EXTENSION; + } + @Override public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { - cu.accept(new ASTVisitor() { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + return new ASTVisitor() { @Override public boolean visit(TypeDeclaration typeDecl) { @@ -94,50 +109,40 @@ public class UnnecessarySpringExtensionReconciler implements JdtAstReconciler { } return super.visit(typeDecl); } - - private boolean isApplicableExtendsWith(Annotation a) { - if (FQN_EXTEND_WITH.endsWith(a.getTypeName().getFullyQualifiedName())) { - IAnnotationBinding annotationBinding = a.resolveAnnotationBinding(); - if (annotationBinding != null && FQN_EXTEND_WITH.equals(annotationBinding.getAnnotationType().getQualifiedName()) && annotationBinding.getDeclaredMemberValuePairs().length == 1) { - IMemberValuePairBinding pair = annotationBinding.getDeclaredMemberValuePairs()[0]; - if ("value".equals(pair.getName())) { - ITypeBinding typeBinding = null; - if (pair.getValue() instanceof ITypeBinding) { - typeBinding = (ITypeBinding) pair.getValue(); - } else if (pair.getValue() instanceof Object[]) { - Object[] arr = (Object[]) pair.getValue(); - if (arr.length > 0 && arr[0] instanceof ITypeBinding) { - typeBinding = (ITypeBinding) arr[0]; - } - } - return typeBinding != null && FQN_SPRING_EXT.equals(typeBinding.getQualifiedName()); + }; + } + + private static boolean isApplicableExtendsWith(Annotation a) { + if (FQN_EXTEND_WITH.endsWith(a.getTypeName().getFullyQualifiedName())) { + IAnnotationBinding annotationBinding = a.resolveAnnotationBinding(); + if (annotationBinding != null && FQN_EXTEND_WITH.equals(annotationBinding.getAnnotationType().getQualifiedName()) && annotationBinding.getDeclaredMemberValuePairs().length == 1) { + IMemberValuePairBinding pair = annotationBinding.getDeclaredMemberValuePairs()[0]; + if ("value".equals(pair.getName())) { + ITypeBinding typeBinding = null; + if (pair.getValue() instanceof ITypeBinding) { + typeBinding = (ITypeBinding) pair.getValue(); + } else if (pair.getValue() instanceof Object[]) { + Object[] arr = (Object[]) pair.getValue(); + if (arr.length > 0 && arr[0] instanceof ITypeBinding) { + typeBinding = (ITypeBinding) arr[0]; } } + return typeBinding != null && FQN_SPRING_EXT.equals(typeBinding.getQualifiedName()); } - return false; } - - private boolean isApplicableTestAnnotation(Annotation a) { - String annotationTypeFqn = a.getTypeName().getFullyQualifiedName(); - if (SPRING_BOOT_TEST_ANNOTATIONS.stream().anyMatch(fqn -> fqn.endsWith(annotationTypeFqn))) { - IAnnotationBinding annotationBinding = a.resolveAnnotationBinding(); - if (annotationBinding != null && SPRING_BOOT_TEST_ANNOTATIONS.contains(annotationBinding.getAnnotationType().getQualifiedName())) { - return true; - } - } - return false; + } + return false; + } + + private static boolean isApplicableTestAnnotation(Annotation a) { + String annotationTypeFqn = a.getTypeName().getFullyQualifiedName(); + if (SPRING_BOOT_TEST_ANNOTATIONS.stream().anyMatch(fqn -> fqn.endsWith(annotationTypeFqn))) { + IAnnotationBinding annotationBinding = a.resolveAnnotationBinding(); + if (annotationBinding != null && SPRING_BOOT_TEST_ANNOTATIONS.contains(annotationBinding.getAnnotationType().getQualifiedName())) { + return true; } - }); - } - - @Override - public boolean isApplicable(IJavaProject project) { - return springBootVersionGreaterOrEqual(2, 1, 0).test(project); - } - - @Override - public Boot2JavaProblemType getProblemType() { - return Boot2JavaProblemType.JAVA_TEST_SPRING_EXTENSION; + } + return false; } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/WebSecurityConfigurerAdapterReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/WebSecurityConfigurerAdapterReconciler.java index d108e52cc..edb7516d1 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/WebSecurityConfigurerAdapterReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/WebSecurityConfigurerAdapterReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 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 @@ -36,11 +36,8 @@ import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor; public class WebSecurityConfigurerAdapterReconciler implements JdtAstReconciler { private static final String WEB_SECURITY_CONFIGURER_ADAPTER = "WebSecurityConfigurerAdapter"; - private static final String FQN_WEB_SECURITY_CONFIGURER_ADAPTER = "org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter"; - private static final String PROBLEM_LABEL = "Class extends 'WebSecurityConfigurerAdapter' which is removed in Spring-Security 6.x"; - private static final String FIX_LABEL = "Refactor class into a Configuration bean not extending 'WebSecurityConfigurerAdapter'"; private static final String STUB_WEB_SECURITY_CONFIG_ADAPTER = """ @@ -73,13 +70,28 @@ public class WebSecurityConfigurerAdapterReconciler implements JdtAstReconciler public WebSecurityConfigurerAdapterReconciler(QuickfixRegistry registry) { this.registry = registry; - } @Override - public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, - boolean isCompleteAst) throws RequiredCompleteAstException { - cu.accept(new ASTVisitor() { + public boolean isApplicable(IJavaProject project) { + Version version = SpringProjectUtil.getDependencyVersion(project, "spring-security-config"); + return version != null && version.compareTo(new Version(5, 7, 0, null)) >= 0 && version.compareTo(new Version(6, 1, 0, null)) < 0; + } + + @Override + public ProblemType getProblemType() { + return Boot2JavaProblemType.WEB_SECURITY_CONFIGURER_ADAPTER; + } + + @Override + public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException { + ASTVisitor visitor = createVisitor(project, docUri, cu, problemCollector, isCompleteAst); + cu.accept(visitor); + } + + @Override + public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) { + return new ASTVisitor() { @Override public boolean visit(TypeDeclaration typeDecl) { @@ -108,7 +120,7 @@ public class WebSecurityConfigurerAdapterReconciler implements JdtAstReconciler return super.visit(typeDecl); } - }); + }; } private static boolean isWebSecurityConfigurerAdapter(CompilationUnit cu, Type type) { @@ -133,15 +145,4 @@ public class WebSecurityConfigurerAdapterReconciler implements JdtAstReconciler return false; } - @Override - public boolean isApplicable(IJavaProject project) { - Version version = SpringProjectUtil.getDependencyVersion(project, "spring-security-config"); - return version != null && version.compareTo(new Version(5, 7, 0, null)) >= 0 && version.compareTo(new Version(6, 1, 0, null)) < 0; - } - - @Override - public ProblemType getProblemType() { - return Boot2JavaProblemType.WEB_SECURITY_CONFIGURER_ADAPTER; - } - } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java index 37d150011..278361d74 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java @@ -541,6 +541,9 @@ public class SpringIndexerJava implements SpringIndexer { addEmptyDiagnostics(diagnosticsByDoc, javaFiles); symbolHandler.addSymbols(project, enhancedSymbols, allBeans, diagnosticsByDoc); } + + System.out.println("reconciling stats - counter: " + reconciler.getStatsCounter()); + System.out.println("reconciling stats - timer: " + reconciler.getStatsTimer()); } private String[] scanFiles(IJavaProject project, String[] javaFiles, List generatedSymbols, List generatedBeans, @@ -606,6 +609,7 @@ public class SpringIndexerJava implements SpringIndexer { catch (Exception e) { log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + node.toString(), e); } + return super.visit(node); }