diff --git a/headless-services/commons/commons-rewrite/src/main/java/org/openrewrite/java/spring/framework/BeanMethodsNotPublic.java b/headless-services/commons/commons-rewrite/src/main/java/org/openrewrite/java/spring/framework/BeanMethodsNotPublic.java deleted file mode 100644 index eb3cc38889..0000000000 --- a/headless-services/commons/commons-rewrite/src/main/java/org/openrewrite/java/spring/framework/BeanMethodsNotPublic.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2021 the original author or authors. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * https://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.openrewrite.java.spring.framework; - -import org.openrewrite.ExecutionContext; -import org.openrewrite.Preconditions; -import org.openrewrite.Recipe; -import org.openrewrite.TreeVisitor; -import org.openrewrite.java.AnnotationMatcher; -import org.openrewrite.java.ChangeMethodAccessLevelVisitor; -import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.search.UsesType; -import org.openrewrite.java.service.AnnotationService; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.TypeUtils; - -public class BeanMethodsNotPublic extends Recipe { - private static final String BEAN = "org.springframework.context.annotation.Bean"; - private static final AnnotationMatcher BEAN_ANNOTATION_MATCHER = new AnnotationMatcher("@" + BEAN); - - @Override - public String getDisplayName() { - return "Remove `public` from `@Bean` methods"; - } - - @Override - public String getDescription() { - return "Remove public modifier from `@Bean` methods. They no longer have to be public visibility to be usable by Spring."; - } - - @Override - public TreeVisitor getVisitor() { - return Preconditions.check(new UsesType<>(BEAN, false), new JavaIsoVisitor() { - @Override - public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) { - if (service(AnnotationService.class).matches(getCursor(), BEAN_ANNOTATION_MATCHER) && - !TypeUtils.isOverride(method.getMethodType())) { - // remove public modifier and copy any associated comments to the method - doAfterVisit(new ChangeMethodAccessLevelVisitor<>(new MethodMatcher(method), null)); - } - return super.visitMethodDeclaration(method, ctx); - } - }); - } -} diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/framework/BeanMethodsNotPublicTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/framework/BeanMethodsNotPublicTest.java deleted file mode 100644 index 4b1f865aa7..0000000000 --- a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/framework/BeanMethodsNotPublicTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2021 the original author or authors. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * https://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.openrewrite.java.spring.framework; - -import org.junit.jupiter.api.Test; -import org.openrewrite.Issue; -import org.openrewrite.java.JavaParser; -import org.openrewrite.test.RecipeSpec; -import org.openrewrite.test.RewriteTest; - -import static org.openrewrite.java.Assertions.java; - -class BeanMethodsNotPublicTest implements RewriteTest { - - @Override - public void defaults(RecipeSpec spec) { - spec.recipe(new BeanMethodsNotPublic()) - .parser(JavaParser.fromJavaVersion().classpath("spring-context")); - } - - @Test - void removePublicModifierFromBeanMethods() { - //language=java - rewriteRun( - java( - """ - package a.b.c; - public class DataSource {} - """), - java( - """ - import a.b.c.DataSource; - import org.springframework.context.annotation.Bean; - import org.springframework.context.annotation.Primary; - - public class DatabaseConfiguration { - - // primary comments - @Primary - @Bean - public DataSource dataSource() { - return new DataSource(); - } - - @Bean // comments - public final DataSource dataSource2() { - return new DataSource(); - } - - @Bean - // comments - public static DataSource dataSource3() { - return new DataSource(); - } - } - """, - """ - import a.b.c.DataSource; - import org.springframework.context.annotation.Bean; - import org.springframework.context.annotation.Primary; - - public class DatabaseConfiguration { - - // primary comments - @Primary - @Bean - DataSource dataSource() { - return new DataSource(); - } - - @Bean // comments - final DataSource dataSource2() { - return new DataSource(); - } - - @Bean - // comments - static DataSource dataSource3() { - return new DataSource(); - } - } - """ - ) - ); - } - - @Issue("https://github.com/openrewrite/rewrite-spring/issues/70") - @Test - void leaveOverridesUnchanged() { - //language=java - rewriteRun( - java( - """ - interface A { - void a(); - } - """ - ), - java( - """ - class B { - public void b() {} - } - """ - ), - java( - """ - import org.springframework.context.annotation.Bean; - - public class PublicBeans extends B implements A { - @Bean - public void a() {} - - @Bean - public void b() {} - } - """ - ) - ); - } -} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/jdt/refactoring/ChangeMethodVisibilityRefactoring.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/jdt/refactoring/ChangeMethodVisibilityRefactoring.java new file mode 100644 index 0000000000..e6349cc99e --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/jdt/refactoring/ChangeMethodVisibilityRefactoring.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2026 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.jdt.refactoring; + +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.Modifier; +import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; +import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; +import org.eclipse.jdt.core.dom.rewrite.ListRewrite; + +public class ChangeMethodVisibilityRefactoring implements JdtRefactoring { + + public enum Visibility { + PUBLIC, PROTECTED, PACKAGE_PRIVATE, PRIVATE + } + + private final Visibility targetVisibility; + private final int[] methodOffsets; + + public ChangeMethodVisibilityRefactoring(Visibility targetVisibility, int... methodOffsets) { + this.targetVisibility = targetVisibility; + this.methodOffsets = methodOffsets; + } + + @Override + public void apply(ASTRewrite rewrite, CompilationUnit cu) { + AST ast = cu.getAST(); + for (int offset : methodOffsets) { + MethodDeclaration method = findMethodAtOffset(cu, offset); + if (method != null) { + ListRewrite modifiersRewrite = rewrite.getListRewrite(method, MethodDeclaration.MODIFIERS2_PROPERTY); + + // Remove existing visibility modifiers + Modifier existingVisibilityModifier = null; + for (Object mod : method.modifiers()) { + if (mod instanceof Modifier modifier) { + if (modifier.isPublic() || modifier.isProtected() || modifier.isPrivate()) { + existingVisibilityModifier = modifier; + modifiersRewrite.remove(modifier, null); + break; + } + } + } + + // Add new visibility modifier if not package private + ModifierKeyword keyword = getModifierKeyword(targetVisibility); + if (keyword != null) { + Modifier newModifier = ast.newModifier(keyword); + if (existingVisibilityModifier != null) { + modifiersRewrite.insertAfter(newModifier, existingVisibilityModifier, null); + } else { + modifiersRewrite.insertFirst(newModifier, null); + } + } + } + } + } + + private ModifierKeyword getModifierKeyword(Visibility visibility) { + switch (visibility) { + case PUBLIC: + return ModifierKeyword.PUBLIC_KEYWORD; + case PROTECTED: + return ModifierKeyword.PROTECTED_KEYWORD; + case PRIVATE: + return ModifierKeyword.PRIVATE_KEYWORD; + case PACKAGE_PRIVATE: + default: + return null; + } + } + + private MethodDeclaration findMethodAtOffset(CompilationUnit cu, int offset) { + MethodDeclaration[] result = new MethodDeclaration[1]; + cu.accept(new ASTVisitor() { + @Override + public boolean visit(MethodDeclaration node) { + if (node.getStartPosition() == offset) { + result[0] = node; + } + return result[0] == null; // stop visiting if found + } + }); + return result[0]; + } +} 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 0aa28fda52..7c0495ea81 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 @@ -24,20 +24,23 @@ import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; -import org.openrewrite.java.spring.framework.BeanMethodsNotPublic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType; +import org.springframework.ide.vscode.boot.java.jdt.refactoring.ChangeMethodVisibilityRefactoring; +import org.springframework.ide.vscode.boot.java.jdt.refactoring.ChangeMethodVisibilityRefactoring.Visibility; +import org.springframework.ide.vscode.boot.java.jdt.refactoring.JdtFixDescriptor; +import org.springframework.ide.vscode.boot.java.jdt.refactoring.JdtRefactorings; import org.springframework.ide.vscode.commons.Version; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.java.SpringProjectUtil; +import org.springframework.ide.vscode.commons.languageserver.quickfix.Quickfix.QuickfixData; import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry; +import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixType; 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 BeanMethodNotPublicReconciler implements JdtAstReconciler { @@ -65,11 +68,14 @@ public ProblemType getProblemType() { public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, ReconcilingContext context) { return new ASTVisitor() { + + private final List problemOffsets = new java.util.ArrayList<>(); + private final List problems = new java.util.ArrayList<>(); @Override public boolean visit(SingleMemberAnnotation node) { try { - visitAnnotation(project, cu, docUri, node, context.getProblemCollector()); + visitAnnotation(project, cu, docUri, node, context.getProblemCollector(), problemOffsets, problems); } catch (Exception e) { log.error("", e); } @@ -79,7 +85,7 @@ public boolean visit(SingleMemberAnnotation node) { @Override public boolean visit(NormalAnnotation node) { try { - visitAnnotation(project, cu, docUri, node, context.getProblemCollector()); + visitAnnotation(project, cu, docUri, node, context.getProblemCollector(), problemOffsets, problems); } catch (Exception e) { log.error("", e); } @@ -89,12 +95,31 @@ public boolean visit(NormalAnnotation node) { @Override public boolean visit(MarkerAnnotation node) { try { - visitAnnotation(project, cu, docUri, node, context.getProblemCollector()); + visitAnnotation(project, cu, docUri, node, context.getProblemCollector(), problemOffsets, problems); } catch (Exception e) { log.error("", e); } return super.visit(node); } + + @Override + public void endVisit(CompilationUnit node) { + if (problemOffsets.size() > 1 && quickfixRegistry != null) { + QuickfixType quickfixType = quickfixRegistry.getQuickfixType(JdtRefactorings.JDT_QUICKFIX); + if (quickfixType != null) { + String uri = docUri.toASCIIString(); + JdtFixDescriptor descriptor = new JdtFixDescriptor( + new ChangeMethodVisibilityRefactoring(Visibility.PACKAGE_PRIVATE, problemOffsets.stream().mapToInt(i -> i).toArray()), + List.of(uri), LABEL + " in file"); + + // We need to attach this "fix all" quickfix to all the problems we found + for (ReconcileProblemImpl problem : problems) { + problem.addQuickfix(new QuickfixData<>(quickfixType, descriptor, LABEL + " in file", false)); + } + } + } + super.endVisit(node); + } }; } @@ -103,7 +128,7 @@ public static final boolean isNotOverridingPublicMethod(IMethodBinding methodBin return !isOverriding(methodBinding) && (methodBinding.getModifiers() & Modifier.PUBLIC) != 0; } - private void visitAnnotation(IJavaProject project, CompilationUnit cu, URI docUri, Annotation node, IProblemCollector problemCollector) { + private void visitAnnotation(IJavaProject project, CompilationUnit cu, URI docUri, Annotation node, IProblemCollector problemCollector, List problemOffsets, List problems) { ITypeBinding typeBinding = node.resolveTypeBinding(); if (typeBinding != null && Annotations.BEAN.equals(typeBinding.getQualifiedName()) && node.getParent() instanceof MethodDeclaration) { MethodDeclaration method = (MethodDeclaration) node.getParent(); @@ -123,6 +148,8 @@ private void visitAnnotation(IJavaProject project, CompilationUnit cu, URI docUr method.getName().getStartPosition(), method.getName().getLength())); addQuickFixes(cu, docUri, problem, method); + problemOffsets.add(method.getStartPosition()); + problems.add(problem); problemCollector.accept(problem); } @@ -145,18 +172,14 @@ private static final boolean isOverriding(IMethodBinding binding) { private void addQuickFixes(CompilationUnit cu, URI docUri, ReconcileProblemImpl problem, MethodDeclaration method) { if (quickfixRegistry != null) { - String id = BeanMethodsNotPublic.class.getName(); - String uri = docUri.toASCIIString(); - - ReconcileUtils.setRewriteFixes(quickfixRegistry, problem, List.of( - new FixDescriptor(id, List.of(uri), LABEL) - .withRecipeScope(RecipeScope.NODE) - .withRangeScope(ReconcileUtils.createOpenRewriteRange(cu, method, null)), - new FixDescriptor(id, List.of(uri), ReconcileUtils.buildLabel(LABEL, RecipeScope.FILE)) - .withRecipeScope(RecipeScope.FILE), - new FixDescriptor(id, List.of(uri), ReconcileUtils.buildLabel(LABEL, RecipeScope.PROJECT)) - .withRecipeScope(RecipeScope.PROJECT) - )); + QuickfixType quickfixType = quickfixRegistry.getQuickfixType(JdtRefactorings.JDT_QUICKFIX); + if (quickfixType != null) { + String uri = docUri.toASCIIString(); + JdtFixDescriptor descriptor = new JdtFixDescriptor( + new ChangeMethodVisibilityRefactoring(Visibility.PACKAGE_PRIVATE, method.getStartPosition()), + List.of(uri), LABEL); + problem.addQuickfix(new QuickfixData<>(quickfixType, descriptor, LABEL, true)); + } } } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/jdt/refactoring/ChangeMethodVisibilityRefactoringTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/jdt/refactoring/ChangeMethodVisibilityRefactoringTest.java new file mode 100644 index 0000000000..d063931d7a --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/jdt/refactoring/ChangeMethodVisibilityRefactoringTest.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright (c) 2026 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.jdt.refactoring; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Map; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; +import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; +import org.eclipse.jface.text.Document; +import org.eclipse.text.edits.TextEdit; +import org.junit.jupiter.api.Test; +import org.springframework.ide.vscode.boot.java.jdt.refactoring.ChangeMethodVisibilityRefactoring.Visibility; + +/** + * Unit tests for {@link ChangeMethodVisibilityRefactoring}. + */ +class ChangeMethodVisibilityRefactoringTest { + + private static Map defaultFormatterOptions() { + Map options = JavaCore.getOptions(); + options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, JavaCore.TAB); + options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, "4"); + return options; + } + + private static CompilationUnit parseSource(String source) { + ASTParser parser = ASTParser.newParser(AST.JLS25); + parser.setSource(source.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + parser.setResolveBindings(false); + + Map options = JavaCore.getOptions(); + String apiLevel = JavaCore.VERSION_21; + JavaCore.setComplianceOptions(apiLevel, options); + parser.setCompilerOptions(options); + + return (CompilationUnit) parser.createAST(null); + } + + private static String applyRefactoring(String source, Visibility visibility, int... offsets) + throws Exception { + CompilationUnit cu = parseSource(source); + ASTRewrite rewrite = ASTRewrite.create(cu.getAST()); + new ChangeMethodVisibilityRefactoring(visibility, offsets).apply(rewrite, cu); + Document doc = new Document(source); + TextEdit edit = rewrite.rewriteAST(doc, defaultFormatterOptions()); + edit.apply(doc); + return doc.get(); + } + + private static int offsetOf(String source, String substring) { + return source.indexOf(substring); + } + + @Test + void publicToPackagePrivate() throws Exception { + String source = """ + package com.example; + + class TestClass { + public void test() { + } + } + """; + + String result = applyRefactoring(source, Visibility.PACKAGE_PRIVATE, offsetOf(source, "public void test")); + + assertEquals(""" + package com.example; + + class TestClass { + void test() { + } + } + """, result); + } + + @Test + void privateToPublic() throws Exception { + String source = """ + package com.example; + + class TestClass { + private void test() { + } + } + """; + + String result = applyRefactoring(source, Visibility.PUBLIC, offsetOf(source, "private void test")); + + assertEquals(""" + package com.example; + + class TestClass { + public void test() { + } + } + """, result); + } + + @Test + void packagePrivateToProtected() throws Exception { + String source = """ + package com.example; + + class TestClass { + void test() { + } + } + """; + + String result = applyRefactoring(source, Visibility.PROTECTED, offsetOf(source, "void test")); + + assertEquals(""" + package com.example; + + class TestClass { + protected void test() { + } + } + """, result); + } + + @Test + void publicToPrivate_withAnnotations() throws Exception { + String source = """ + package com.example; + + class TestClass { + @Override + public void test() { + } + } + """; + + String result = applyRefactoring(source, Visibility.PRIVATE, offsetOf(source, "@Override")); + + assertEquals(""" + package com.example; + + class TestClass { + @Override + private void test() { + } + } + """, result); + } + + @Test + void batchReplacement() throws Exception { + String source = """ + package com.example; + + class TestClass { + public void test1() { + } + + protected void test2() { + } + } + """; + + String result = applyRefactoring(source, Visibility.PACKAGE_PRIVATE, + offsetOf(source, "public void test1"), + offsetOf(source, "protected void test2")); + + assertEquals(""" + package com.example; + + class TestClass { + void test1() { + } + + void test2() { + } + } + """, result); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/CodeActionViaReconcilerTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/BeanMethodNotPublicReconcilerTest.java similarity index 70% rename from headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/CodeActionViaReconcilerTest.java rename to headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/BeanMethodNotPublicReconcilerTest.java index 467c009515..3edcc92fc6 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/CodeActionViaReconcilerTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/BeanMethodNotPublicReconcilerTest.java @@ -40,7 +40,7 @@ @ExtendWith(SpringExtension.class) @BootLanguageServerTest @Import(IndexerTestConf.class) -public class CodeActionViaReconcilerTest { +public class BeanMethodNotPublicReconcilerTest { @Autowired private BootLanguageServerHarness harness; @Autowired private JavaProjectFinder projectFinder; @@ -65,10 +65,11 @@ public void setup() throws Exception { initProject.get(5, TimeUnit.SECONDS); } - @Test - void codeActionsFromReconcilingProblems() throws Exception { - String docUri = directory.toPath().resolve("src/main/java/org/test/BeanMethodNotPublic1.java").toUri().toString(); - Editor editor = harness.newEditor(LanguageId.JAVA, """ + @Test + void codeActionsFromReconcilingProblems() throws Exception { + String docUri = directory.toPath().resolve("src/main/java/org/test/BeanMethodNotPublic1.java").toUri() + .toString(); + Editor editor = harness.newEditor(LanguageId.JAVA, """ package org.test; import org.springframework.context.annotation.Bean; @@ -89,24 +90,43 @@ BeanClass2 nonPublicBeanMethod() { } """, docUri); - - List codeActions = editor.getCodeActions("public", 1); - assertEquals(0, codeActions.size()); - - Diagnostic problem = editor.assertProblem("public"); - assertNotNull(problem); - assertEquals(Boot2JavaProblemType.JAVA_PUBLIC_BEAN_METHOD.getCode(), problem.getCode().getLeft()); - assertEquals(Boot2JavaProblemType.JAVA_PUBLIC_BEAN_METHOD.getLabel(), problem.getMessage().getLeft()); - - codeActions = editor.getCodeActions(problem); - assertEquals(3, codeActions.size()); - harness.changeConfiguration("{\"spring-boot\": {\"ls\": {\"problem\": { \"boot2\": { \"JAVA_PUBLIC_BEAN_METHOD\": \"IGNORE\"}}}}}"); - - editor.assertProblems(); - - codeActions = editor.getCodeActions("public", 1); - assertEquals(3, codeActions.size()); - } + List codeActions = editor.getCodeActions("public", 1); + assertEquals(0, codeActions.size()); + + Diagnostic problem = editor.assertProblem("public"); + assertNotNull(problem); + assertEquals(Boot2JavaProblemType.JAVA_PUBLIC_BEAN_METHOD.getCode(), problem.getCode().getLeft()); + assertEquals(Boot2JavaProblemType.JAVA_PUBLIC_BEAN_METHOD.getLabel(), problem.getMessage().getLeft()); + + codeActions = editor.getCodeActions(problem); + assertEquals(1, codeActions.size()); + + harness.executeCommand(codeActions.get(0).getCommand()); + + String expectedText = """ + package org.test; + + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + + @Configuration + class BeanMethodNotPublic1 { + + @Bean BeanClass1 publicBeanMethod() { + return new BeanClass1(); + } + + @Bean + BeanClass2 nonPublicBeanMethod() { + return new BeanClass2(); + } + + } + """; + assertEquals(expectedText, editor.getRawText()); + + editor.assertProblems(); + } }