Next batch of JDT reconcilers
This commit is contained in:
@@ -18,12 +18,14 @@ import java.util.stream.Collectors;
|
||||
import org.openrewrite.ExecutionContext;
|
||||
import org.openrewrite.Recipe;
|
||||
import org.openrewrite.TreeVisitor;
|
||||
import org.openrewrite.internal.ListUtils;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.JavaParser;
|
||||
import org.openrewrite.java.JavaTemplate;
|
||||
import org.openrewrite.java.MethodMatcher;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.JavaType;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
|
||||
public class DefineMethod extends Recipe {
|
||||
|
||||
@@ -87,11 +89,22 @@ public class DefineMethod extends Recipe {
|
||||
.classpath(classpath.stream().map(s -> Paths.get(s)).collect(Collectors.toList())))
|
||||
|
||||
.imports(imports.toArray(new String[imports.size()])).build();
|
||||
J.Block body = t.apply(getCursor(), classDecl.getBody().getCoordinates().addMethodDeclaration((m, n) -> 1));
|
||||
// TODO: why did this return ClassDEclaration rather than Block??? Figure this out!!!
|
||||
J.ClassDeclaration templateClass = t.apply(getCursor(), classDecl.getBody().getCoordinates().addMethodDeclaration((m, n) -> 1));
|
||||
FullyQualified classType = c.getType();
|
||||
if (classType != null) {
|
||||
J.Block body = templateClass.getBody().withStatements(ListUtils.map(templateClass.getBody().getStatements(), s -> {
|
||||
if (s instanceof J.MethodDeclaration) {
|
||||
J.MethodDeclaration m = (J.MethodDeclaration) s;
|
||||
return m.withMethodType(m.getMethodType().withDeclaringType(classType));
|
||||
}
|
||||
return s;
|
||||
}));
|
||||
c = c.withBody(body);
|
||||
}
|
||||
for (String fq : imports) {
|
||||
maybeAddImport(fq);
|
||||
}
|
||||
c = c.withBody(body);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
|
||||
@@ -14,14 +14,19 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.AddConfigurationIfBeansPresentReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.AnnotationNodeReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.AuthorizeHttpRequestsReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.AutowiredFieldIntoConstructorParameterReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.BeanMethodNotPublicReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.BeanPostProcessingIgnoreInAotReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.Boot3NotSupportedTypeReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.HttpSecurityLambdaDslReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.ModulithTypeReferenceViolationReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.NoAutowiredOnConstructorReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.NoRepoAnnotationReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.NoRequestMappingAnnotationReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.NotRegisteredBeansReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.PreciseBeanTypeReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.ServerHttpSecurityLambdaDslReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.UnnecessarySpringExtensionReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.WebSecurityConfigurerAdapterReconciler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
@@ -76,5 +81,25 @@ public class JdtConfig {
|
||||
@Bean UnnecessarySpringExtensionReconciler unnecessarySpringExtensionReconciler(SimpleLanguageServer server) {
|
||||
return new UnnecessarySpringExtensionReconciler(server.getQuickfixRegistry());
|
||||
}
|
||||
|
||||
@Bean HttpSecurityLambdaDslReconciler httpSecurityLamdaDslReconciler(SimpleLanguageServer server) {
|
||||
return new HttpSecurityLambdaDslReconciler(server.getQuickfixRegistry());
|
||||
}
|
||||
|
||||
@Bean ServerHttpSecurityLambdaDslReconciler serverHttpSecurityLambdaDslReconciler(SimpleLanguageServer server) {
|
||||
return new ServerHttpSecurityLambdaDslReconciler(server.getQuickfixRegistry());
|
||||
}
|
||||
|
||||
@Bean AuthorizeHttpRequestsReconciler authorizeHttpRequestsReconciler(SimpleLanguageServer server) {
|
||||
return new AuthorizeHttpRequestsReconciler(server.getQuickfixRegistry());
|
||||
}
|
||||
|
||||
@Bean BeanPostProcessingIgnoreInAotReconciler beanPostProcessingIgnoreInAotReconciler(SimpleLanguageServer server) {
|
||||
return new BeanPostProcessingIgnoreInAotReconciler(server.getQuickfixRegistry());
|
||||
}
|
||||
|
||||
@Bean NotRegisteredBeansReconciler notRegisteredBeansReconciler(SimpleLanguageServer server) {
|
||||
return new NotRegisteredBeansReconciler(server.getQuickfixRegistry());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
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;
|
||||
|
||||
public abstract class AbstractSecurityLamdaDslReconciler implements JdtAstReconciler {
|
||||
|
||||
private QuickfixRegistry registry;
|
||||
|
||||
AbstractSecurityLamdaDslReconciler(QuickfixRegistry registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector,
|
||||
boolean isCompleteAst) throws RequiredCompleteAstException {
|
||||
if (isCompleteAst) {
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(MethodInvocation node) {
|
||||
if (getApplicableMethodNames().contains(node.getName().getIdentifier()) && node.arguments().isEmpty()) {
|
||||
ITypeBinding type = node.getExpression().resolveTypeBinding();
|
||||
if (type != null && getTargetTypeFqName().equals(type.getQualifiedName())) {
|
||||
MethodInvocation topMethodInvocation = findTopLevelMethodInvocation(node);
|
||||
ReconcileProblemImpl problem = new ReconcileProblemImpl(getProblemType(), getProblemLabel(), topMethodInvocation.getStartPosition(), topMethodInvocation.getLength());
|
||||
String uri = docUri.toASCIIString();
|
||||
RewriteQuickFixUtils.setRewriteFixes(registry, problem, List.of(
|
||||
new FixDescriptor(getRecipeId(), List.of(uri),
|
||||
RewriteQuickFixUtils.buildLabel(getFixLabel(), RecipeScope.NODE))
|
||||
.withRangeScope(RewriteQuickFixUtils.createOpenRewriteRange(cu, topMethodInvocation))
|
||||
.withRecipeScope(RecipeScope.NODE),
|
||||
new FixDescriptor(getRecipeId(), List.of(uri),
|
||||
RewriteQuickFixUtils.buildLabel(getFixLabel(), RecipeScope.FILE))
|
||||
.withRecipeScope(RecipeScope.FILE),
|
||||
new FixDescriptor(getRecipeId(), List.of(uri),
|
||||
RewriteQuickFixUtils.buildLabel(getFixLabel(), RecipeScope.PROJECT))
|
||||
.withRecipeScope(RecipeScope.PROJECT)
|
||||
));
|
||||
problemCollector.accept(problem);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
if (RewriteQuickFixUtils.isAnyTypeUsed(cu, List.of(getTargetTypeFqName()))) {
|
||||
throw new RequiredCompleteAstException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<String> getApplicableMethodNames();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MethodInvocation;
|
||||
import org.eclipse.jdt.core.dom.SimpleType;
|
||||
import org.openrewrite.java.spring.boot2.AuthorizeHttpRequests;
|
||||
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.java.Version;
|
||||
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;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
|
||||
|
||||
public class AuthorizeHttpRequestsReconciler implements JdtAstReconciler {
|
||||
|
||||
private static final String ID = AuthorizeHttpRequests.class.getName();
|
||||
|
||||
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 CLASS_FIX_LABEL_TEMPLATE = "Replace with %s and use 'HttpSecurity.authorizeHttpRequests(...) and related types";
|
||||
|
||||
private static final String FQN_AUTH_REQ_CONFIG = "org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer";
|
||||
|
||||
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;
|
||||
|
||||
public AuthorizeHttpRequestsReconciler(QuickfixRegistry registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector,
|
||||
boolean isCompleteAst) throws RequiredCompleteAstException {
|
||||
if (isCompleteAst) {
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(MethodInvocation node) {
|
||||
if (AUTHORIZE_REQUESTS.equals(node.getName().getIdentifier()) && node.arguments().isEmpty()) {
|
||||
ITypeBinding type = node.getExpression().resolveTypeBinding();
|
||||
if (type != null && FQN_HTTP_SECURITY.equals(type.getQualifiedName())) {
|
||||
ReconcileProblemImpl problem = new ReconcileProblemImpl(getProblemType(),
|
||||
AUTHORIZE_REQUESTS_PROBLEM_LABEL, node.getName().getStartPosition(),
|
||||
node.getName().getLength());
|
||||
String uri = docUri.toASCIIString();
|
||||
RewriteQuickFixUtils
|
||||
.setRewriteFixes(registry, problem, List.of(
|
||||
new FixDescriptor(ID, List.of(uri),
|
||||
RewriteQuickFixUtils.buildLabel(AUTHORIZE_REQUESTS_FIX_LABEL,
|
||||
RecipeScope.FILE))
|
||||
.withRecipeScope(RecipeScope.FILE),
|
||||
new FixDescriptor(ID, List.of(uri),
|
||||
RewriteQuickFixUtils.buildLabel(AUTHORIZE_REQUESTS_FIX_LABEL,
|
||||
RecipeScope.PROJECT))
|
||||
.withRecipeScope(RecipeScope.PROJECT)));
|
||||
problemCollector.accept(problem);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SimpleType node) {
|
||||
String replacementClass = null;
|
||||
if (RewriteQuickFixUtils.isApplicableTypeWithoutResolving(cu,
|
||||
List.of(FQN_AUTH_REQ_CONFIG, FQN_EXPR_AUTH_CONFIG), node.getName())) {
|
||||
replacementClass = "AuthorizeHttpRequestsConfigurer";
|
||||
} else if (RewriteQuickFixUtils.isApplicableTypeWithoutResolving(cu, List.of(FQN_EXPR_INTERCEPT_REG),
|
||||
node.getName())) {
|
||||
replacementClass = "AuthorizationManagerRequestMatcherRegistry";
|
||||
}
|
||||
if (replacementClass != null) {
|
||||
ReconcileProblemImpl problem = new ReconcileProblemImpl(getProblemType(),
|
||||
"Use of type '" + node.getName().getFullyQualifiedName() + "' is outdated",
|
||||
node.getName().getStartPosition(), node.getName().getLength());
|
||||
String uri = docUri.toASCIIString();
|
||||
RewriteQuickFixUtils
|
||||
.setRewriteFixes(registry, problem, List.of(
|
||||
new FixDescriptor(ID, List.of(uri),
|
||||
RewriteQuickFixUtils.buildLabel(String.format(CLASS_FIX_LABEL_TEMPLATE,
|
||||
replacementClass), RecipeScope.FILE))
|
||||
.withRecipeScope(RecipeScope.FILE),
|
||||
new FixDescriptor(ID, List.of(uri),
|
||||
RewriteQuickFixUtils.buildLabel(
|
||||
String.format(CLASS_FIX_LABEL_TEMPLATE, replacementClass),
|
||||
RecipeScope.PROJECT))
|
||||
.withRecipeScope(RecipeScope.PROJECT)));
|
||||
problemCollector.accept(problem);
|
||||
return false;
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
boolean needsFullAst = RewriteQuickFixUtils.isAnyTypeUsed(cu, List.of(
|
||||
FQN_HTTP_SECURITY,
|
||||
FQN_AUTH_REQ_CONFIG,
|
||||
FQN_EXPR_AUTH_CONFIG,
|
||||
FQN_EXPR_INTERCEPT_REG
|
||||
));
|
||||
if (needsFullAst) {
|
||||
throw new RequiredCompleteAstException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -85,10 +85,12 @@ public class BeanMethodNotPublicReconciler implements JdtAstReconciler {
|
||||
|
||||
private static final boolean isOverriding(IMethodBinding binding) {
|
||||
try {
|
||||
Field f = binding.getClass().getDeclaredField("binding");
|
||||
f.setAccessible(true);
|
||||
org.eclipse.jdt.internal.compiler.lookup.MethodBinding value = (org.eclipse.jdt.internal.compiler.lookup.MethodBinding) f.get(binding);
|
||||
return value.isOverriding();
|
||||
if (binding != null) {
|
||||
Field f = binding.getClass().getDeclaredField("binding");
|
||||
f.setAccessible(true);
|
||||
org.eclipse.jdt.internal.compiler.lookup.MethodBinding value = (org.eclipse.jdt.internal.compiler.lookup.MethodBinding) f.get(binding);
|
||||
return value.isOverriding();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers;
|
||||
|
||||
import static org.springframework.ide.vscode.commons.java.SpringProjectUtil.springBootVersionGreaterOrEqual;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.ReturnStatement;
|
||||
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;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.BeanPostProcessingIgnoreInAot;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
|
||||
|
||||
public class BeanPostProcessingIgnoreInAotReconciler implements JdtAstReconciler {
|
||||
|
||||
private static final String RECIPE_ID = BeanPostProcessingIgnoreInAot.class.getName();
|
||||
private static final String LABEL = "Add method 'isBeanExcludedFromAotProcessing' that returns 'false'";
|
||||
private static final String RUNTIME_BEAN_POST_PROCESSOR = "org.springframework.beans.factory.config.BeanPostProcessor";
|
||||
private static final String COMPILE_BEAN_POST_PROCESSOR = "org.springframework.beans.factory.aot.BeanRegistrationAotProcessor";
|
||||
public static final String METHOD_NAME = "isBeanExcludedFromAotProcessing";
|
||||
|
||||
private QuickfixRegistry registry;
|
||||
|
||||
public BeanPostProcessingIgnoreInAotReconciler(QuickfixRegistry registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
@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() {
|
||||
|
||||
@Override
|
||||
public boolean visit(TypeDeclaration typeDecl) {
|
||||
ITypeBinding type = typeDecl.resolveBinding();
|
||||
if (type != null && isApplicable(type)) {
|
||||
MethodDeclaration foundMethod = null;
|
||||
boolean markProblem = false;
|
||||
for (MethodDeclaration m : typeDecl.getMethods()) {
|
||||
if (METHOD_NAME.equals(m.getName().getIdentifier()) && m.parameters().isEmpty()) {
|
||||
foundMethod = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundMethod != null) {
|
||||
if (isCompleteAst) {
|
||||
AtomicBoolean returnsTrue = new AtomicBoolean(false);
|
||||
foundMethod.accept(new ASTVisitor() {
|
||||
@Override
|
||||
public boolean visit(ReturnStatement node) {
|
||||
if (Boolean.TRUE.equals(node.getExpression().resolveConstantExpressionValue())) {
|
||||
returnsTrue.set(true);
|
||||
}
|
||||
return !returnsTrue.get();
|
||||
}
|
||||
});
|
||||
markProblem = returnsTrue.get();
|
||||
} else {
|
||||
requiresFullAst.set(true);
|
||||
}
|
||||
} else {
|
||||
markProblem = true;
|
||||
}
|
||||
|
||||
if (markProblem) {
|
||||
ReconcileProblemImpl problem = new ReconcileProblemImpl(getProblemType(), LABEL, typeDecl.getName().getStartPosition(), typeDecl.getName().getLength());
|
||||
RewriteQuickFixUtils.setRewriteFixes(registry, problem, List.of(
|
||||
new FixDescriptor(RECIPE_ID, List.of(docUri.toASCIIString()), RewriteQuickFixUtils.buildLabel(LABEL, RecipeScope.NODE))
|
||||
.withRangeScope(RewriteQuickFixUtils.createOpenRewriteRange(cu, typeDecl))
|
||||
.withRecipeScope(RecipeScope.NODE)
|
||||
));
|
||||
problemCollector.accept(problem);
|
||||
}
|
||||
}
|
||||
return !requiresFullAst.get();
|
||||
}
|
||||
|
||||
private boolean isApplicable(ITypeBinding type) {
|
||||
return RewriteQuickFixUtils.implementsType(RUNTIME_BEAN_POST_PROCESSOR, type) && RewriteQuickFixUtils.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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers;
|
||||
|
||||
import static org.springframework.ide.vscode.commons.java.SpringProjectUtil.springBootVersionGreaterOrEqual;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.openrewrite.java.spring.boot2.search.EntityIdForRepositoryVisitor;
|
||||
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
|
||||
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;
|
||||
|
||||
public class EntityIdForRepoReconciler implements JdtAstReconciler {
|
||||
|
||||
private static final String ID = EntityIdForRepositoryVisitor.class.getName();
|
||||
|
||||
private QuickfixRegistry registry;
|
||||
|
||||
public EntityIdForRepoReconciler(QuickfixRegistry registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconcile(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector,
|
||||
boolean isCompleteAst) throws RequiredCompleteAstException {
|
||||
final boolean considerIdField = SpringProjectUtil.hasSpecificLibraryOnClasspath(project, "spring-data-mongodb-", true);
|
||||
cu.accept(new ASTVisitor() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(IJavaProject project) {
|
||||
return springBootVersionGreaterOrEqual(2, 0, 0).test(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProblemType getProblemType() {
|
||||
return Boot2JavaProblemType.DOMAIN_ID_FOR_REPOSITORY;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.openrewrite.java.spring.boot2.HttpSecurityLambdaDsl;
|
||||
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.java.Version;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
|
||||
|
||||
public class HttpSecurityLambdaDslReconciler extends AbstractSecurityLamdaDslReconciler {
|
||||
|
||||
private static final Collection<String> APPLICABLE_METHOD_NAMES = Arrays.asList(
|
||||
"anonymous", "authorizeRequests", "cors", "csrf", "exceptionHandling", "formLogin",
|
||||
"headers", "httpBasic", "jee", "logout", "oauth2Client", "oauth2Login", "oauth2ResourceServer",
|
||||
"openidLogin", "portMapper", "rememberMe", "requestCache", "requestMatchers", "requiresChannel",
|
||||
"saml2Login", "securityContext", "servletApi", "sessionManagement", "x509");
|
||||
|
||||
|
||||
public HttpSecurityLambdaDslReconciler(QuickfixRegistry registry) {
|
||||
super(registry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(IJavaProject project) {
|
||||
Version version = SpringProjectUtil.getDependencyVersion(project, "spring-security-config");
|
||||
return version != null && version.compareTo(new Version(5, 2, 0, null)) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProblemType getProblemType() {
|
||||
return Boot2JavaProblemType.JAVA_LAMBDA_DSL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFixLabel() {
|
||||
return "Switch to 'HttpSecurity` Lambda DSL syntax";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getRecipeId() {
|
||||
return HttpSecurityLambdaDsl.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getProblemLabel() {
|
||||
return "Consider switching to 'HttpSecurity' Lambda DSL syntax";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTargetTypeFqName() {
|
||||
return "org.springframework.security.config.annotation.web.builders.HttpSecurity";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> getApplicableMethodNames() {
|
||||
return APPLICABLE_METHOD_NAMES;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers;
|
||||
|
||||
import static org.springframework.ide.vscode.commons.java.SpringProjectUtil.springBootVersionGreaterOrEqual;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.IBinding;
|
||||
import org.eclipse.jdt.core.dom.IMethodBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.Modifier;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.WorkspaceSymbol;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
|
||||
import org.springframework.ide.vscode.boot.java.SpringAotJavaProblemType;
|
||||
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation;
|
||||
import org.springframework.ide.vscode.boot.java.beans.ConfigBeanSymbolAddOnInformation;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
|
||||
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;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.DefineMethod;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
public class NotRegisteredBeansReconciler implements JdtAstReconciler, ApplicationContextAware {
|
||||
|
||||
private static final String DEFINE_METHOD_RECIPE = DefineMethod.class.getName();
|
||||
|
||||
private static final List<String> AOT_BEANS = List.of(
|
||||
"org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor",
|
||||
"org.springframework.beans.factory.aot.BeanRegistrationAotProcessor"
|
||||
);
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private QuickfixRegistry registry;
|
||||
|
||||
public NotRegisteredBeansReconciler(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() {
|
||||
|
||||
@Override
|
||||
public boolean visit(TypeDeclaration node) {
|
||||
if (!node.isInterface() && !Modifier.isAbstract(node.getModifiers())) {
|
||||
ITypeBinding type = node.resolveBinding();
|
||||
if (type != null && RewriteQuickFixUtils.implementsAnyType(AOT_BEANS, type)) {
|
||||
String beanClassName =type.getQualifiedName();
|
||||
SpringSymbolIndex index = applicationContext.getBean(SpringSymbolIndex.class);
|
||||
List<WorkspaceSymbol> beanSymbols = index.getSymbols(data -> {
|
||||
SymbolAddOnInformation[] additionalInformation = data.getAdditionalInformation();
|
||||
if (additionalInformation != null) {
|
||||
for (SymbolAddOnInformation info : additionalInformation) {
|
||||
if (info instanceof BeansSymbolAddOnInformation) {
|
||||
BeansSymbolAddOnInformation info2 = (BeansSymbolAddOnInformation) info;
|
||||
return beanClassName.equals(info2.getBeanType());
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}).limit(1).collect(Collectors.toList());
|
||||
|
||||
if (beanSymbols.isEmpty()) {
|
||||
Builder<FixDescriptor> fixListBuilder = ImmutableList.builder();
|
||||
for (EnhancedSymbolInformation s : index.getEnhancedSymbols(project)) {
|
||||
if (s.getAdditionalInformation() != null) {
|
||||
ConfigBeanSymbolAddOnInformation configInfo = Arrays.stream(s.getAdditionalInformation()).filter(ConfigBeanSymbolAddOnInformation.class::isInstance).map(ConfigBeanSymbolAddOnInformation.class::cast).findFirst().orElse(null);
|
||||
if (configInfo != null) {
|
||||
for (IMethodBinding constructor : type.getDeclaredMethods()) {
|
||||
if (constructor.isConstructor()) {
|
||||
String constructorParamsSignature = "(" + Arrays.stream(constructor.getParameterTypes()).map(pt -> typePattern(pt)).collect(Collectors.joining(",")) + ")";
|
||||
String beanMethodName = "get" + type.getName();
|
||||
String pattern = beanMethodName + constructorParamsSignature;
|
||||
String contructorParamsLabel = "(" + Arrays.stream(constructor.getParameterTypes()).map(NotRegisteredBeansReconciler::typeStr).collect(Collectors.joining(", ")) + ")";
|
||||
|
||||
Builder<String> paramBuilder = ImmutableList.builder();
|
||||
for (int i = 0; i < constructor.getParameterNames().length && i < constructor.getParameterTypes().length; i++) {
|
||||
ITypeBinding paramType = constructor.getParameterTypes()[i];
|
||||
String paramName = constructor.getParameterNames()[i];
|
||||
paramBuilder.add(typeStr(paramType) + ' ' + paramName);
|
||||
}
|
||||
String paramsStr = String.join(", ", paramBuilder.build().toArray(String[]::new));
|
||||
|
||||
fixListBuilder.add(new FixDescriptor(DEFINE_METHOD_RECIPE, List.of(s.getSymbol().getLocation().getLeft().getUri()), "Define bean in config '" + configInfo.getBeanID() + "' with constructor " + contructorParamsLabel)
|
||||
.withRecipeScope(RecipeScope.FILE)
|
||||
.withParameters(Map.of(
|
||||
"targetFqName", configInfo.getBeanType(),
|
||||
"signature", pattern,
|
||||
"template", "@Bean\n"
|
||||
+ type.getName() + " " + beanMethodName + "(" + paramsStr + ") {\n"
|
||||
+ "return new " + type.getName() + "(" + Arrays.stream(constructor.getParameterNames()).collect(Collectors.joining(", ")) + ");\n"
|
||||
+ "}\n",
|
||||
"imports", allFQTypes(constructor).toArray(String[]::new),
|
||||
"typeStubs", new String[0]/*new String[] { source.printAll() }*/,
|
||||
"classpath", IClasspathUtil.getAllBinaryRoots(project.getClasspath()).stream().map(f -> f.toPath().toString()).toArray(String[]::new)
|
||||
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ReconcileProblemImpl problem = new ReconcileProblemImpl(getProblemType(), getProblemType().getLabel(), node.getName().getStartPosition(), node.getName().getLength());
|
||||
RewriteQuickFixUtils.setRewriteFixes(registry, problem, fixListBuilder.build());
|
||||
problemCollector.accept(problem);
|
||||
}
|
||||
}
|
||||
}
|
||||
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<String> allFQTypes(IBinding binding) {
|
||||
ImmutableSet.Builder<String> b = ImmutableSet.builder();
|
||||
if (binding instanceof IMethodBinding) {
|
||||
IMethodBinding methodBinding = (IMethodBinding) binding;
|
||||
b.addAll(allFQTypes(methodBinding.getDeclaringClass()));
|
||||
for (ITypeBinding paramType : methodBinding.getParameterTypes()) {
|
||||
b.addAll(allFQTypes(paramType));
|
||||
}
|
||||
} else if (binding instanceof ITypeBinding) {
|
||||
ITypeBinding typeBinding = (ITypeBinding) binding;
|
||||
if (!typeBinding.isPrimitive()) {
|
||||
for (ITypeBinding paramType : typeBinding.getTypeParameters()) {
|
||||
b.addAll(allFQTypes(paramType));
|
||||
}
|
||||
for (ITypeBinding argType : typeBinding.getTypeArguments()) {
|
||||
b.addAll(allFQTypes(argType));
|
||||
|
||||
}
|
||||
b.addAll(allFQTypes(typeBinding.getBound()));
|
||||
ITypeBinding erasure = typeBinding.getErasure();
|
||||
if (erasure == typeBinding) {
|
||||
b.add(typeBinding.getQualifiedName());
|
||||
} else {
|
||||
b.addAll(allFQTypes(erasure));
|
||||
}
|
||||
}
|
||||
}
|
||||
return b.build();
|
||||
}
|
||||
|
||||
|
||||
private static String typePattern(ITypeBinding type) {
|
||||
if (type.isArray()) {
|
||||
return typePattern(type.getErasure()) + "[]";
|
||||
} else {
|
||||
return RewriteQuickFixUtils.getDeepErasureType(type).getQualifiedName();
|
||||
}
|
||||
}
|
||||
|
||||
private static String typeStr(ITypeBinding type) {
|
||||
return type.getName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,12 +12,17 @@ package org.springframework.ide.vscode.boot.java.reconcilers;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.BodyDeclaration;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.ImportDeclaration;
|
||||
import org.eclipse.jdt.core.dom.Name;
|
||||
import org.eclipse.jdt.core.dom.SimpleType;
|
||||
import org.openrewrite.Tree;
|
||||
import org.openrewrite.marker.Range;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
|
||||
@@ -90,6 +95,87 @@ public class RewriteQuickFixUtils {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static boolean isApplicableTypeWithoutResolving(CompilationUnit cu, Collection<String> types, Name typeNameNode) {
|
||||
String typeName = typeNameNode.getFullyQualifiedName();
|
||||
if (cu.getPackage().getName() != null && types.contains(cu.getPackage().getName().getFullyQualifiedName() + "." + typeName)) {
|
||||
return true;
|
||||
}
|
||||
if (types.contains(typeName)) {
|
||||
return true;
|
||||
} else if (types.stream().anyMatch(t -> t.endsWith(typeName))) {
|
||||
for (Object im : cu.imports()) {
|
||||
ImportDeclaration importDecl = (ImportDeclaration) im;
|
||||
String importFqName = importDecl.getName().getFullyQualifiedName();
|
||||
if (importDecl.isOnDemand()) {
|
||||
if (types.contains(importFqName + "." + typeName)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
String importSimpleName = getSimpleName(importFqName);
|
||||
String firstTokenOfTypeName = getFirstTokenBeforeDot(typeName);
|
||||
if (importSimpleName.equals(firstTokenOfTypeName)) {
|
||||
if (types.contains(importFqName + typeName.substring(firstTokenOfTypeName.length()))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isAnyTypeUsed(CompilationUnit cu, Collection<String> types) {
|
||||
AtomicBoolean typeUsed = new AtomicBoolean(false);
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(ImportDeclaration node) {
|
||||
String fqName = node.getName().getFullyQualifiedName();
|
||||
if (types.contains(fqName)) {
|
||||
typeUsed.set(true);
|
||||
}
|
||||
return !typeUsed.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SimpleType node) {
|
||||
if (RewriteQuickFixUtils.isApplicableTypeWithoutResolving(cu, types, node.getName())) {
|
||||
typeUsed.set(true);
|
||||
}
|
||||
return !typeUsed.get();
|
||||
}
|
||||
});
|
||||
return typeUsed.get();
|
||||
}
|
||||
|
||||
public static boolean implementsType(String fqName, ITypeBinding type) {
|
||||
if (fqName.equals(type.getQualifiedName())) {
|
||||
return true;
|
||||
} else {
|
||||
for (ITypeBinding t : type.getInterfaces()) {
|
||||
if (implementsType(fqName, t)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean implementsAnyType(Collection<String> fqNames, ITypeBinding type) {
|
||||
if (fqNames.contains(type.getQualifiedName())) {
|
||||
return true;
|
||||
} else {
|
||||
for (ITypeBinding t : type.getInterfaces()) {
|
||||
if (implementsAnyType(fqNames, t)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static String getSimpleName(String fqName) {
|
||||
int idx = fqName.lastIndexOf('.');
|
||||
if (idx >= 0 && idx < fqName.length() - 1) {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.openrewrite.java.spring.boot2.ServerHttpSecurityLambdaDsl;
|
||||
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.java.Version;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
|
||||
|
||||
public class ServerHttpSecurityLambdaDslReconciler extends AbstractSecurityLamdaDslReconciler {
|
||||
|
||||
private static final Collection<String> APPLICABLE_METHOD_NAMES = Arrays.asList("anonymous", "authorizeExchange",
|
||||
"cors", "csrf", "exceptionHandling", "formLogin", "headers", "httpBasic", "logout", "oauth2Client",
|
||||
"oauth2Login", "oauth2ResourceServer", "redirectToHttps", "requestCache", "x509");
|
||||
|
||||
public ServerHttpSecurityLambdaDslReconciler(QuickfixRegistry registry) {
|
||||
super(registry);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(IJavaProject project) {
|
||||
Version version = SpringProjectUtil.getDependencyVersion(project, "spring-security-config");
|
||||
return version != null && version.compareTo(new Version(5, 2, 0, null)) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProblemType getProblemType() {
|
||||
return Boot2JavaProblemType.JAVA_LAMBDA_DSL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFixLabel() {
|
||||
return "Switch to 'ServerHttpSecurity` Lambda DSL syntax";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getRecipeId() {
|
||||
return ServerHttpSecurityLambdaDsl.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getProblemLabel() {
|
||||
return "Consider switching to 'ServerHttpSecurity' Lambda DSL syntax";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTargetTypeFqName() {
|
||||
return "org.springframework.security.config.web.server.ServerHttpSecurity";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> getApplicableMethodNames() {
|
||||
return APPLICABLE_METHOD_NAMES;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers.test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.AuthorizeHttpRequestsReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.RequiredCompleteAstException;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
|
||||
|
||||
public class AuthorizeHttpRequestsReconcilerTest extends BaseReconcilerTest {
|
||||
|
||||
@Override
|
||||
protected String getFolder() {
|
||||
return "authorizerequests";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getProjectName() {
|
||||
return "test-spring-indexing";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JdtAstReconciler getReconciler() {
|
||||
return new AuthorizeHttpRequestsReconciler(new QuickfixRegistry());
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireFullAst_1() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
|
||||
class A {
|
||||
|
||||
void something(HttpSecurity security) {
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
try {
|
||||
reconcile("A.java", source, false);
|
||||
fail("Should require full AST with method bodies");
|
||||
} catch (RequiredCompleteAstException e) {
|
||||
// pass
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireFullAst_2() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
|
||||
|
||||
class A {
|
||||
|
||||
void something() {
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
try {
|
||||
reconcile("A.java", source, false);
|
||||
fail("Should require full AST with method bodies");
|
||||
} catch (RequiredCompleteAstException e) {
|
||||
// pass
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireFullAst_3() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
||||
|
||||
class A {
|
||||
|
||||
void something(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry reg) {
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
try {
|
||||
reconcile("A.java", source, false);
|
||||
fail("Should require full AST with method bodies");
|
||||
} catch (RequiredCompleteAstException e) {
|
||||
// pass
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void sanityTest() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
|
||||
class A {
|
||||
|
||||
void something(HttpSecurity security) {
|
||||
security.authorizeRequests().mvcMatchers();
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
List<ReconcileProblem> problems = reconcile("A.java", source, true);
|
||||
|
||||
assertEquals(1, problems.size());
|
||||
|
||||
ReconcileProblem problem = problems.get(0);
|
||||
|
||||
assertEquals(Boot2JavaProblemType.HTTP_SECURITY_AUTHORIZE_HTTP_REQUESTS, problem.getType());
|
||||
|
||||
String markedStr = source.substring(problem.getOffset(), problem.getOffset() + problem.getLength());
|
||||
assertEquals("authorizeRequests", markedStr);
|
||||
|
||||
assertEquals(2, problem.getQuickfixes().size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipleProblems() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
@Configuration
|
||||
public class JdbcSecurityConfiguration {
|
||||
@Bean
|
||||
SecurityFilterChain web(HttpSecurity http) throws Exception {
|
||||
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry reqs = http.authorizeRequests();
|
||||
reqs.antMatchers("/ll").authenticated();
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
""";
|
||||
List<ReconcileProblem> problems = reconcile("A.java", source, true);
|
||||
|
||||
assertEquals(2, problems.size());
|
||||
|
||||
ReconcileProblem problem = problems.get(0);
|
||||
|
||||
assertEquals(Boot2JavaProblemType.HTTP_SECURITY_AUTHORIZE_HTTP_REQUESTS, problem.getType());
|
||||
|
||||
String markedStr = source.substring(problem.getOffset(), problem.getOffset() + problem.getLength());
|
||||
assertEquals("ExpressionUrlAuthorizationConfigurer", markedStr);
|
||||
|
||||
assertEquals(2, problem.getQuickfixes().size());
|
||||
|
||||
problem = problems.get(1);
|
||||
|
||||
assertEquals(Boot2JavaProblemType.HTTP_SECURITY_AUTHORIZE_HTTP_REQUESTS, problem.getType());
|
||||
|
||||
markedStr = source.substring(problem.getOffset(), problem.getOffset() + problem.getLength());
|
||||
assertEquals("authorizeRequests", markedStr);
|
||||
|
||||
assertEquals(2, problem.getQuickfixes().size());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import java.nio.file.Paths;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.FileASTRequestor;
|
||||
@@ -42,7 +43,7 @@ public abstract class BaseReconcilerTest {
|
||||
|
||||
abstract protected JdtAstReconciler getReconciler();
|
||||
|
||||
private Path createFile(String name, String content) throws IOException {
|
||||
protected Path createFile(String name, String content) throws IOException {
|
||||
Path filePath = Paths.get(project.getLocationUri()).resolve("src/main/java").resolve(getFolder()).resolve(name);
|
||||
Files.createDirectories(filePath.getParent());
|
||||
Files.createFile(filePath);
|
||||
@@ -75,6 +76,10 @@ public abstract class BaseReconcilerTest {
|
||||
}
|
||||
|
||||
List<ReconcileProblem> reconcile(String fileName, String source, boolean isCompleteAst) throws Exception {
|
||||
return reconcile(this::getReconciler, fileName, source, isCompleteAst);
|
||||
}
|
||||
|
||||
List<ReconcileProblem> reconcile(Supplier<JdtAstReconciler> reconcilerFactory, String fileName, String source, boolean isCompleteAst) throws Exception {
|
||||
Path path = createFile(fileName, source);
|
||||
TestProblemCollector problemCollector = new TestProblemCollector();
|
||||
AtomicBoolean requiredCompleteAst = new AtomicBoolean(false);
|
||||
@@ -83,7 +88,7 @@ public abstract class BaseReconcilerTest {
|
||||
@Override
|
||||
public void acceptAST(String sourceFilePath, CompilationUnit cu) {
|
||||
try {
|
||||
getReconciler().reconcile(project, path.toUri(), cu, problemCollector, isCompleteAst);
|
||||
reconcilerFactory.get().reconcile(project, path.toUri(), cu, problemCollector, isCompleteAst);
|
||||
} catch (RequiredCompleteAstException e) {
|
||||
requiredCompleteAst.set(true);
|
||||
}
|
||||
@@ -97,5 +102,4 @@ public abstract class BaseReconcilerTest {
|
||||
return problemCollector.getCollectedProblems();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers.test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ide.vscode.boot.java.SpringAotJavaProblemType;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.BeanPostProcessingIgnoreInAotReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.RequiredCompleteAstException;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
|
||||
|
||||
public class BeanPostProcessingIgnoreInAotReconcilerTest extends BaseReconcilerTest {
|
||||
|
||||
@Override
|
||||
protected String getFolder() {
|
||||
return "beanpostprocessingaot";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getProjectName() {
|
||||
return "test-spring-validations";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JdtAstReconciler getReconciler() {
|
||||
return new BeanPostProcessingIgnoreInAotReconciler(new QuickfixRegistry());
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void noMethod() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||
|
||||
class A implements BeanPostProcessor, BeanRegistrationAotProcessor{
|
||||
|
||||
A() {};
|
||||
|
||||
}
|
||||
""";
|
||||
List<ReconcileProblem> problems = reconcile("A.java", source, false);
|
||||
|
||||
assertEquals(1, problems.size());
|
||||
|
||||
ReconcileProblem problem = problems.get(0);
|
||||
|
||||
assertEquals(SpringAotJavaProblemType.JAVA_BEAN_POST_PROCESSOR_IGNORED_IN_AOT, problem.getType());
|
||||
|
||||
String markedStr = source.substring(problem.getOffset(), problem.getOffset() + problem.getLength());
|
||||
assertEquals("A", markedStr);
|
||||
|
||||
assertEquals(1, problem.getQuickfixes().size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void withMethodReturningTrue_IncompleteAst() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||
|
||||
class A implements BeanPostProcessor, BeanRegistrationAotProcessor{
|
||||
|
||||
A() {};
|
||||
|
||||
public boolean isBeanExcludedFromAotProcessing() { return true; }
|
||||
|
||||
}
|
||||
""";
|
||||
try {
|
||||
reconcile("A.java", source, false);
|
||||
fail("Should require complete AST");
|
||||
} catch (RequiredCompleteAstException e) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void withMethodReturningTrue_CompleteAst() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||
|
||||
class A implements BeanPostProcessor, BeanRegistrationAotProcessor{
|
||||
|
||||
A() {};
|
||||
|
||||
public boolean isBeanExcludedFromAotProcessing() { return true; }
|
||||
|
||||
}
|
||||
""";
|
||||
List<ReconcileProblem> problems = reconcile("A.java", source, true);
|
||||
|
||||
assertEquals(1, problems.size());
|
||||
|
||||
ReconcileProblem problem = problems.get(0);
|
||||
|
||||
assertEquals(SpringAotJavaProblemType.JAVA_BEAN_POST_PROCESSOR_IGNORED_IN_AOT, problem.getType());
|
||||
|
||||
String markedStr = source.substring(problem.getOffset(), problem.getOffset() + problem.getLength());
|
||||
assertEquals("A", markedStr);
|
||||
|
||||
assertEquals(1, problem.getQuickfixes().size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void withMethodReturningFalse() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||
|
||||
class A implements BeanPostProcessor, BeanRegistrationAotProcessor{
|
||||
|
||||
A() {};
|
||||
|
||||
public boolean isBeanExcludedFromAotProcessing() { return false; }
|
||||
|
||||
}
|
||||
""";
|
||||
List<ReconcileProblem> problems = reconcile("A.java", source, true);
|
||||
|
||||
assertEquals(0, problems.size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void noBeanPostProcessor() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||
|
||||
class A implements BeanRegistrationAotProcessor{
|
||||
|
||||
A() {};
|
||||
|
||||
}
|
||||
""";
|
||||
List<ReconcileProblem> problems = reconcile("A.java", source, true);
|
||||
|
||||
assertEquals(0, problems.size());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers.test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.HttpSecurityLambdaDslReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.RequiredCompleteAstException;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
|
||||
|
||||
public class HttpSecurityLambdaDslReconcilerTest extends BaseReconcilerTest {
|
||||
|
||||
@Override
|
||||
protected String getFolder() {
|
||||
return "httpsecuritydsl";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getProjectName() {
|
||||
return "test-spring-indexing";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JdtAstReconciler getReconciler() {
|
||||
return new HttpSecurityLambdaDslReconciler(new QuickfixRegistry());
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireFullAst_1() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
|
||||
class A {
|
||||
|
||||
void something(HttpSecurity security) {
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
try {
|
||||
reconcile("A.java", source, false);
|
||||
fail("Should require full AST with method bodies");
|
||||
} catch (RequiredCompleteAstException e) {
|
||||
// pass
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireFullAst_2() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.*;
|
||||
|
||||
class A {
|
||||
|
||||
void something(HttpSecurity security) {
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
try {
|
||||
reconcile("A.java", source, false);
|
||||
fail("Should require full AST with method bodies");
|
||||
} catch (RequiredCompleteAstException e) {
|
||||
// pass
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireFullAst_3() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
class A {
|
||||
|
||||
void something(org.springframework.security.config.annotation.web.builders.HttpSecurity security) {
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
try {
|
||||
reconcile("A.java", source, false);
|
||||
fail("Should require full AST with method bodies");
|
||||
} catch (RequiredCompleteAstException e) {
|
||||
// pass
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void sanityTest() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
|
||||
class A {
|
||||
|
||||
void something(HttpSecurity security) {
|
||||
security.authorizeRequests().mvcMatchers();
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
List<ReconcileProblem> problems = reconcile("A.java", source, true);
|
||||
|
||||
assertEquals(1, problems.size());
|
||||
|
||||
ReconcileProblem problem = problems.get(0);
|
||||
|
||||
assertEquals(Boot2JavaProblemType.JAVA_LAMBDA_DSL, problem.getType());
|
||||
|
||||
String markedStr = source.substring(problem.getOffset(), problem.getOffset() + problem.getLength());
|
||||
assertEquals("security.authorizeRequests().mvcMatchers()", markedStr);
|
||||
|
||||
assertEquals(3, problem.getQuickfixes().size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void noProblem() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
|
||||
class A {
|
||||
|
||||
void something(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests(requests -> requests
|
||||
.antMatchers("/blog/**").permitAll()
|
||||
.anyRequest().authenticated())
|
||||
.formLogin(login -> login
|
||||
.loginPage("/login")
|
||||
.permitAll())
|
||||
.rememberMe(withDefaults());
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
List<ReconcileProblem> problems = reconcile("A.java", source, true);
|
||||
|
||||
assertEquals(0, problems.size());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers.test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.SymbolKind;
|
||||
import org.eclipse.lsp4j.WorkspaceSymbol;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
|
||||
import org.springframework.ide.vscode.boot.java.SpringAotJavaProblemType;
|
||||
import org.springframework.ide.vscode.boot.java.beans.ConfigBeanSymbolAddOnInformation;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.NotRegisteredBeansReconciler;
|
||||
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.ReconcileProblem;
|
||||
|
||||
|
||||
public class NotRegisteredBeansReconcilerTest extends BaseReconcilerTest {
|
||||
|
||||
@Override
|
||||
protected String getFolder() {
|
||||
return "notregisteredbeanaot";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getProjectName() {
|
||||
return "test-spring-validations";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected JdtAstReconciler getReconciler() {
|
||||
NotRegisteredBeansReconciler reconciler = new NotRegisteredBeansReconciler(new QuickfixRegistry());
|
||||
SpringSymbolIndex mockSymbolIndex = mock(SpringSymbolIndex.class);
|
||||
when(mockSymbolIndex.getSymbols(any(Predicate.class))).thenReturn(Stream.empty());
|
||||
|
||||
ApplicationContext context = mock(ApplicationContext.class);
|
||||
when(context.getBean(SpringSymbolIndex.class)).thenReturn(mockSymbolIndex);
|
||||
|
||||
reconciler.setApplicationContext(context);
|
||||
return reconciler;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private NotRegisteredBeansReconciler createReconciler(EnhancedSymbolInformation... beanSymbols) {
|
||||
NotRegisteredBeansReconciler reconciler = new NotRegisteredBeansReconciler(new QuickfixRegistry());
|
||||
SpringSymbolIndex mockSymbolIndex = mock(SpringSymbolIndex.class);
|
||||
when(mockSymbolIndex.getSymbols(any(Predicate.class))).thenReturn(Stream.empty());
|
||||
when(mockSymbolIndex.getEnhancedSymbols(any(IJavaProject.class))).thenReturn(Arrays.asList(beanSymbols));
|
||||
|
||||
ApplicationContext context = mock(ApplicationContext.class);
|
||||
when(context.getBean(SpringSymbolIndex.class)).thenReturn(mockSymbolIndex);
|
||||
|
||||
reconciler.setApplicationContext(context);
|
||||
return reconciler;
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void sanityTest() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||
|
||||
class A implements BeanRegistrationAotProcessor {
|
||||
|
||||
public A(String k) {}
|
||||
}
|
||||
""";
|
||||
List<ReconcileProblem> problems = reconcile(() -> createReconciler(), "A.java", source, true);
|
||||
|
||||
assertEquals(1, problems.size());
|
||||
|
||||
ReconcileProblem problem = problems.get(0);
|
||||
|
||||
assertEquals(SpringAotJavaProblemType.JAVA_BEAN_NOT_REGISTERED_IN_AOT, problem.getType());
|
||||
|
||||
String markedStr = source.substring(problem.getOffset(), problem.getOffset() + problem.getLength());
|
||||
assertEquals("A", markedStr);
|
||||
|
||||
assertEquals(0, problem.getQuickfixes().size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void sanityTestWithQuickFixes() throws Exception {
|
||||
Path configClassPath = createFile("TestConfig.java", """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
class TestConfig {
|
||||
}
|
||||
""");
|
||||
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||
|
||||
class A implements BeanRegistrationAotProcessor {
|
||||
|
||||
public A(String k) {}
|
||||
}
|
||||
""";
|
||||
|
||||
WorkspaceSymbol workspaceSymbol = new WorkspaceSymbol("testConfig", SymbolKind.Class, Either.forLeft(new Location(configClassPath.toUri().toASCIIString(), new Range())));
|
||||
ConfigBeanSymbolAddOnInformation configBeanAddOn = new ConfigBeanSymbolAddOnInformation("testConfig", "example.demo.TestConfig");
|
||||
|
||||
List<ReconcileProblem> problems = reconcile(() -> createReconciler(new EnhancedSymbolInformation(workspaceSymbol, new SymbolAddOnInformation[] { configBeanAddOn })), "A.java", source, true);
|
||||
|
||||
assertEquals(1, problems.size());
|
||||
|
||||
ReconcileProblem problem = problems.get(0);
|
||||
|
||||
assertEquals(SpringAotJavaProblemType.JAVA_BEAN_NOT_REGISTERED_IN_AOT, problem.getType());
|
||||
|
||||
String markedStr = source.substring(problem.getOffset(), problem.getOffset() + problem.getLength());
|
||||
assertEquals("A", markedStr);
|
||||
|
||||
assertEquals(1, problem.getQuickfixes().size());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.reconcilers.test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.RequiredCompleteAstException;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.ServerHttpSecurityLambdaDslReconciler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
|
||||
|
||||
public class ServerHttpSecurityLambdaDslReconcilerTest extends BaseReconcilerTest {
|
||||
|
||||
@Override
|
||||
protected String getFolder() {
|
||||
return "serverhttpsecuritydsl";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getProjectName() {
|
||||
return "test-spring-indexing";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JdtAstReconciler getReconciler() {
|
||||
return new ServerHttpSecurityLambdaDslReconciler(new QuickfixRegistry());
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireFullAst() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
|
||||
class A {
|
||||
|
||||
void something(ServerHttpSecurity security) {
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
try {
|
||||
reconcile("A.java", source, false);
|
||||
fail("Should require full AST with method bodies");
|
||||
} catch (RequiredCompleteAstException e) {
|
||||
// pass
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void sanityTest() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
|
||||
class A {
|
||||
|
||||
void something(ServerHttpSecurity http) {
|
||||
http.authorizeExchange().pathMatchers("/blog/**").permitAll().anyExchange().authenticated();
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
List<ReconcileProblem> problems = reconcile("A.java", source, true);
|
||||
|
||||
assertEquals(1, problems.size());
|
||||
|
||||
ReconcileProblem problem = problems.get(0);
|
||||
|
||||
assertEquals(Boot2JavaProblemType.JAVA_LAMBDA_DSL, problem.getType());
|
||||
|
||||
String markedStr = source.substring(problem.getOffset(), problem.getOffset() + problem.getLength());
|
||||
assertEquals("http.authorizeExchange().pathMatchers(\"/blog/**\").permitAll().anyExchange().authenticated()", markedStr);
|
||||
|
||||
assertEquals(3, problem.getQuickfixes().size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void noProblem() throws Exception {
|
||||
String source = """
|
||||
package example.demo;
|
||||
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
|
||||
class A {
|
||||
|
||||
void something(ServerHttpSecurity http) {
|
||||
http.authorizeExchange(exchange -> exchange.pathMatchers("/blog/**").permitAll().anyExchange().authenticated());
|
||||
};
|
||||
|
||||
}
|
||||
""";
|
||||
List<ReconcileProblem> problems = reconcile("A.java", source, true);
|
||||
|
||||
assertEquals(0, problems.size());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user