"); - sb.append(r.description); - sb.append("
"); - sb.append("");
- sb.append(option.value());
- sb.append("");
- sb.append(option.description());
- sb.append("private. See {@link JavadocHover#getStyleSheet()}.
- * @return CSS as string
- */
- private static String getStyleSheet() {
- if (fgStyleSheet == null) {
- fgStyleSheet= JavadocHover.loadStyleSheet("/JavadocHoverStyleSheet.css"); //$NON-NLS-1$
- }
- String css= fgStyleSheet;
- if (css != null) {
- FontData fontData= JFaceResources.getFontRegistry().getFontData(PreferenceConstants.APPEARANCE_JAVADOC_FONT)[0];
- css= HTMLPrinter.convertTopLevelFont(css, fontData);
- }
- return css;
- }
-
-}
diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/PrefsInitializer.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/PrefsInitializer.java
index 9bf82e21b8..07972ef302 100644
--- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/PrefsInitializer.java
+++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/PrefsInitializer.java
@@ -43,20 +43,6 @@ public void initializeDefaultPreferences() {
preferenceStore.setDefault(Constants.PREF_SCAN_JAVA_TEST_SOURCES, false);
preferenceStore.setDefault(Constants.PREF_JAVA_RECONCILE, true);
- preferenceStore.setDefault(Constants.PREF_REWRITE_PROJECT_REFACTORINGS, true);
-
- preferenceStore.setDefault(Constants.PREF_REWRITE_RECIPE_FILTERS, StringListEditor.encode(new String[] {
- "org.openrewrite.java.spring.boot2.SpringBoot2JUnit4to5Migration",
- "org.openrewrite.java.spring.boot3.SpringBoot3BestPractices",
- "org.openrewrite.java.testing.junit5.JUnit5BestPractices",
- "org.openrewrite.java.testing.junit5.JUnit4to5Migration",
- "org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_7",
- "org.springframework.ide.vscode.rewrite.boot3.UpgradeSpringBoot_3_4",
- "org.springframework.ide.vscode.rewrite.boot3.UpgradeSpringBoot_3_5",
- "org.rewrite.java.security.*",
- "org.springframework.rewrite.test.*",
- "rewrite.test.*"
- }));
preferenceStore.setDefault(Constants.PREF_MODULITH, true);
preferenceStore.setDefault(Constants.PREF_LIVE_INFORMATION_ALL_JVM_PROCESSES, false);
diff --git a/headless-services/commons/commons-rewrite/pom.xml b/headless-services/commons/commons-rewrite/pom.xml
index b5ee41ef43..4493e37ae9 100644
--- a/headless-services/commons/commons-rewrite/pom.xml
+++ b/headless-services/commons/commons-rewrite/pom.xml
@@ -28,16 +28,6 @@
+ * 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; + +import org.jspecify.annotations.Nullable; +import org.openrewrite.*; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.properties.AddProperty; +import org.openrewrite.properties.tree.Properties; +import org.openrewrite.yaml.MergeYaml; +import org.openrewrite.yaml.tree.Yaml; + +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * A recipe to uniformly add a property to Spring configuration file. This recipe supports adding properties to + * ".properties" and YAML files. This recipe will only add the property if it does not already exist within the + * configuration file. + *
+ * NOTE: Because an application may have a large collection of yaml files (some of which may not even be related to
+ * Spring configuration), this recipe will only make changes to files that match one of the pathExpressions. If
+ * the recipe is configured without pathExpressions, it will query the execution context for reasonable defaults.
+ */
+public class AddSpringProperty extends Recipe {
+
+ @Option(displayName = "Property key",
+ description = "The property key to add.",
+ example = "management.metrics.enable.process.files")
+ String property;
+
+ @Option(displayName = "Property value",
+ description = "The value of the new property key.",
+ example = "true")
+ String value;
+
+ @Option(displayName = "Optional comment to be prepended to the property",
+ description = "A comment that will be added to the new property.",
+ required = false,
+ example = "This is a comment")
+ @Nullable
+ String comment;
+
+ @Option(displayName = "Optional list of file path matcher",
+ description = "Each value in this list represents a glob expression that is used to match which files will " +
+ "be modified. If this value is not present, this recipe will query the execution context for " +
+ "reasonable defaults. (\"**/application.yml\", \"**/application.yml\", and \"**/application.properties\".",
+ required = false,
+ example = "[\"**/application.yml\"]")
+ @Nullable
+ List
+ * 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;
+
+import org.openrewrite.Cursor;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Tree;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.java.*;
+import org.openrewrite.java.tree.*;
+import org.openrewrite.java.tree.J.Block;
+import org.openrewrite.java.tree.J.ClassDeclaration;
+import org.openrewrite.java.tree.J.MethodDeclaration;
+import org.openrewrite.java.tree.J.VariableDeclarations;
+import org.openrewrite.java.tree.JavaType.FullyQualified;
+import org.openrewrite.marker.Markers;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+
+public class AutowiredFieldIntoConstructorParameterVisitor extends JavaVisitor
+ * 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;
+
+import java.util.Objects;
+
+import org.jspecify.annotations.Nullable;
+import org.openrewrite.*;
+import org.openrewrite.internal.StringUtils;
+import org.openrewrite.properties.tree.Properties;
+import org.openrewrite.yaml.tree.Yaml;
+
+public class ChangeSpringPropertyValue extends Recipe {
+
+ @Override
+ public String getDisplayName() {
+ return "Change the value of a spring application property";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Change spring application property values existing in either Properties or Yaml files.";
+ }
+
+ @Option(displayName = "Property key",
+ description = "The name of the property key whose value is to be changed.",
+ example = "management.metrics.binders.files.enabled")
+ String propertyKey;
+
+ @Option(displayName = "New value",
+ description = "The new value to be used for key specified by `propertyKey`.",
+ example = "management.metrics.enable.process.files")
+ String newValue;
+
+ @Option(displayName = "Old value",
+ required = false,
+ description = "Only change the property value if it matches the configured `oldValue`.",
+ example = "false")
+ @Nullable
+ String oldValue;
+
+ @Option(displayName = "Regex",
+ description = "Default false. If enabled, `oldValue` will be interpreted as a Regular Expression, and capture group contents will be available in `newValue`",
+ required = false)
+ @Nullable
+ Boolean regex;
+
+ @Option(displayName = "Use relaxed binding",
+ description = "Whether to match the `propertyKey` using [relaxed binding](https://docs.spring.io/spring-boot/docs/2.5.6/reference/html/features.html#features.external-config.typesafe-configuration-properties.relaxed-binding) " +
+ "rules. Default is `true`. Set to `false` to use exact matching.",
+ required = false)
+ @Nullable
+ Boolean relaxedBinding;
+
+ public ChangeSpringPropertyValue(String propertyKey, String newValue, @Nullable String oldValue,
+ @Nullable Boolean regex, @Nullable Boolean relaxedBinding) {
+ this.propertyKey = propertyKey;
+ this.newValue = newValue;
+ this.oldValue = oldValue;
+ this.regex = regex;
+ this.relaxedBinding = relaxedBinding;
+ }
+
+ @Override
+ public Validated validate() {
+ return super.validate().and(
+ Validated.test("oldValue", "is required if `regex` is enabled", oldValue,
+ value -> !(Boolean.TRUE.equals(regex) && StringUtils.isNullOrEmpty(value))));
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ Recipe changeProperties = new org.openrewrite.properties.ChangePropertyValue(propertyKey, newValue, oldValue, regex, relaxedBinding);
+ Recipe changeYaml = new org.openrewrite.yaml.ChangePropertyValue(propertyKey, newValue, oldValue, regex, relaxedBinding, null);
+ return new TreeVisitor
+ * 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;
+
+import org.openrewrite.*;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.search.UsesType;
+import org.openrewrite.java.tree.J;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static java.util.stream.Collectors.toSet;
+import static org.openrewrite.java.tree.TypeUtils.isOfClassType;
+
+public class ImplicitWebAnnotationNames extends Recipe {
+ @Override
+ public String getDisplayName() {
+ return "Remove implicit web annotation names";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Removes implicit web annotation names.";
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return Preconditions.check(Preconditions.or(
+ new UsesType<>("org.springframework.web.bind.annotation.PathVariable", false),
+ new UsesType<>("org.springframework.web.bind.annotation.RequestParam", false),
+ new UsesType<>("org.springframework.web.bind.annotation.RequestHeader", false),
+ new UsesType<>("org.springframework.web.bind.annotation.RequestAttribute", false),
+ new UsesType<>("org.springframework.web.bind.annotation.CookieValue", false),
+ new UsesType<>("org.springframework.web.bind.annotation.ModelAttribute", false),
+ new UsesType<>("org.springframework.web.bind.annotation.SessionAttribute", false)
+ ), new ImplicitWebAnnotationNamesVisitor());
+ }
+
+ private static class ImplicitWebAnnotationNamesVisitor extends JavaIsoVisitor
+ * 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;
+
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.java.AnnotationMatcher;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.RemoveAnnotationVisitor;
+import org.openrewrite.java.search.FindAnnotations;
+import org.openrewrite.java.search.UsesType;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.Statement;
+
+public class NoAutowiredOnConstructor extends Recipe {
+ private static final AnnotationMatcher AUTOWIRED_ANNOTATION_MATCHER =
+ new AnnotationMatcher("@org.springframework.beans.factory.annotation.Autowired(true)");
+
+ @Override
+ public String getDisplayName() {
+ return "Remove the `@Autowired` annotation on inferred constructor";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Spring can infer an autowired constructor when there is a single constructor on the bean. " +
+ "This recipe removes unneeded `@Autowired` annotations on constructors.";
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return Preconditions.check(new UsesType<>("org.springframework.beans.factory.annotation.Autowired", false), new JavaIsoVisitor
+ * 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;
+
+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.JavaIsoVisitor;
+import org.openrewrite.java.RemoveAnnotationVisitor;
+import org.openrewrite.java.search.UsesType;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.TypeUtils;
+
+public class NoRepoAnnotationOnRepoInterface extends Recipe {
+
+ private static final String INTERFACE_REPOSITORY = "org.springframework.data.repository.Repository";
+ private static final String ANNOTATION_REPOSITORY = "org.springframework.stereotype.Repository";
+
+ @Override
+ public String getDisplayName() {
+ return "Remove unnecessary `@Repository` annotation from Spring Data `Repository` sub-interface";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Removes superfluous `@Repository` annotation from Spring Data `Repository` sub-interfaces.";
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return Preconditions.check(new UsesType<>(ANNOTATION_REPOSITORY, false), new JavaIsoVisitor
+ * 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;
+
+import org.jspecify.annotations.Nullable;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.java.AnnotationMatcher;
+import org.openrewrite.java.ChangeType;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.search.UsesType;
+import org.openrewrite.java.tree.Expression;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.Space;
+
+import java.time.Duration;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Replace method declaration @RequestMapping annotations with the associated variant
+ * as defined by the request method type (GET, POST, PUT, PATCH, DELETE)
+ *
+ * (HEAD, OPTIONS, TRACE) methods do not have associated RequestMapping variant and are not converted
+ *
+ * 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;
+
+import org.openrewrite.DelegatingExecutionContext;
+import org.openrewrite.ExecutionContext;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class SpringExecutionContextView extends DelegatingExecutionContext {
+
+ private static final String DEFAULT_APPLICATION_CONFIGURATION_PATHS = "org.openrewrite.java.spring.defaultApplicationConfigurationPaths";
+
+ public SpringExecutionContextView(ExecutionContext delegate) {
+ super(delegate);
+ }
+
+ public static SpringExecutionContextView view(ExecutionContext ctx) {
+ if (ctx instanceof SpringExecutionContextView) {
+ return (SpringExecutionContextView) ctx;
+ }
+ return new SpringExecutionContextView(ctx);
+ }
+
+ /**
+ * The path expressions used to find a spring boot application's default configuration file(s). The default masks used to
+ * find the application's root configuration are "**/application.properties", "**/application.yml", and "**/application.yaml"
+ *
+ * @param pathExpressions A list of expressions that will be used as masks to find an application's default configuration file(s)
+ * @return this
+ */
+ public SpringExecutionContextView setDefaultApplicationConfigurationPaths(List
+ * 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.boot2;
+
+import org.openrewrite.*;
+import org.openrewrite.java.AnnotationMatcher;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.java.JavaTemplate;
+import org.openrewrite.java.search.UsesType;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.Statement;
+import org.openrewrite.java.tree.TypeUtils;
+
+import java.util.Comparator;
+
+public class AddConfigurationAnnotationIfBeansPresent extends Recipe {
+
+ private static final String FQN_BEAN = "org.springframework.context.annotation.Bean";
+ private static final String CONFIGURATION_PACKAGE = "org.springframework.context.annotation";
+ private static final String CONFIGURATION_SIMPLE_NAME = "Configuration";
+ private static final String FQN_CONFIGURATION = CONFIGURATION_PACKAGE + "." + CONFIGURATION_SIMPLE_NAME;
+ private static final AnnotationMatcher BEAN_ANNOTATION_MATCHER = new AnnotationMatcher("@" + FQN_BEAN, true);
+ private static final AnnotationMatcher CONFIGURATION_ANNOTATION_MATCHER = new AnnotationMatcher("@" + FQN_CONFIGURATION, true);
+
+
+ @Override
+ public String getDisplayName() {
+ return "Add missing `@Configuration` annotation";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Class having `@Bean` annotation over any methods but missing `@Configuration` annotation over the declaring class would have `@Configuration` annotation added.";
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return Preconditions.check(new UsesType<>(FQN_BEAN, false), new JavaIsoVisitor
+ * 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.boot2;
+
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.RemoveAnnotation;
+import org.openrewrite.java.search.FindAnnotations;
+import org.openrewrite.java.search.UsesType;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.TypeUtils;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class UnnecessarySpringExtension extends Recipe {
+
+ // All the following annotations apply the @SpringExtension
+ private static final List
+ * 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.boot3;
+
+import org.openrewrite.*;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.search.UsesType;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.TypeTree;
+import org.openrewrite.java.tree.TypeUtils;
+
+public class PreciseBeanType extends Recipe {
+ private static final String BEAN = "org.springframework.context.annotation.Bean";
+
+ private static final String MSG_KEY = "returnType";
+
+ @Override
+ public String getDisplayName() {
+ return "Bean methods should return concrete types";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Replace Bean method return types with concrete types being returned. This is required for Spring 6 AOT.";
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return Preconditions.check(new UsesType<>(BEAN, false), new JavaIsoVisitor
+ * 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, ExecutionContext> getVisitor() {
+ return Preconditions.check(new UsesType<>(BEAN, false), new JavaIsoVisitor
+ * 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.security5;
+
+import org.openrewrite.Cursor;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.java.ChangeType;
+import org.openrewrite.java.JavaVisitor;
+import org.openrewrite.java.MethodMatcher;
+import org.openrewrite.java.tree.*;
+import org.openrewrite.marker.Markers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AuthorizeHttpRequests extends Recipe {
+
+ private static final String MSG_ADD_COMMENT = "add-comment";
+
+ private static final String AUTHORIZE_HTTP_REQUESTS = "authorizeHttpRequests";
+
+ private static final MethodMatcher MATCH_AUTHORIZE_REQUESTS = new MethodMatcher(
+ "org.springframework.security.config.annotation.web.builders.HttpSecurity authorizeRequests(..)");
+
+ private static final MethodMatcher MATCH_ACCESS_DECISION_MANAGER = new MethodMatcher(
+ "org.springframework.security.config.annotation.web.configurers.AbstractInterceptUrlConfigurer$AbstractInterceptUrlRegistry accessDecisionManager(..)");
+
+ @Override
+ public String getDisplayName() {
+ return "Replace `HttpSecurity.authorizeRequests(...)` with `HttpSecurity.authorizeHttpRequests(...)` and `ExpressionUrlAuthorizationConfigurer`, `AbstractInterceptUrlConfigurer` with `AuthorizeHttpRequestsConfigurer`, etc";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Replace `HttpSecurity.authorizeRequests(...)` deprecated in Spring Security 6 with `HttpSecurity.authorizeHttpRequests(...)` and all method calls on the resultant object respectively. Replace deprecated `AbstractInterceptUrlConfigurer` and its deprecated subclasses with `AuthorizeHttpRequestsConfigurer` and its corresponding subclasses.";
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return new JavaVisitor
+ * 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.security5;
+
+import org.jspecify.annotations.Nullable;
+import org.openrewrite.Cursor;
+import org.openrewrite.Tree;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.internal.StringUtils;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.MethodMatcher;
+import org.openrewrite.java.tree.*;
+import org.openrewrite.marker.Markers;
+import org.openrewrite.marker.Markup;
+
+import java.util.*;
+
+import static java.util.Collections.emptyList;
+import static java.util.Objects.requireNonNull;
+
+public class ConvertToSecurityDslVisitor extends JavaIsoVisitor {
+
+ private static final String MSG_FLATTEN_CHAIN = "http-security-dsl-flatten-invocation-chain";
+ private static final String MSG_TOP_INVOCATION = "top-method-invocation";
+
+ private static final String FQN_CUSTOMIZER = "org.springframework.security.config.Customizer";
+ private static final JavaType.FullyQualified CUSTOMIZER_SHALLOW_TYPE = JavaType.ShallowClass.build(FQN_CUSTOMIZER);
+
+ private static final MethodMatcher XSS_PROTECTION_ENABLED = new MethodMatcher("org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.XXssConfig xssProtectionEnabled(boolean)");
+
+ private final String securityFqn;
+ private final Collection
+ * 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.security5;
+
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.java.search.UsesType;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+public final class HttpSecurityLambdaDsl extends Recipe {
+
+ private static final String FQN_HTTP_SECURITY = "org.springframework.security.config.annotation.web.builders.HttpSecurity";
+
+ private static final Collection
+ * 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.security5;
+
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.java.search.UsesType;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+public final class ServerHttpSecurityLambdaDsl extends Recipe {
+
+ private static final String FQN_SERVER_HTTP_SECURITY = "org.springframework.security.config.web.server.ServerHttpSecurity";
+
+ private static final Collection
+ * 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.security5;
+
+import org.jspecify.annotations.Nullable;
+import org.openrewrite.*;
+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.search.UsesType;
+import org.openrewrite.java.tree.*;
+import org.openrewrite.marker.Markers;
+import org.openrewrite.marker.SearchResult;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+import static java.util.Collections.emptyList;
+
+/**
+ * @author Alex Boyko
+ */
+public class WebSecurityConfigurerAdapter extends Recipe {
+
+ private static final Collection
- * 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.staticanalysis;
-
-import org.jspecify.annotations.NonNull;
-import org.openrewrite.ExecutionContext;
-import org.openrewrite.Preconditions;
-import org.openrewrite.Recipe;
-import org.openrewrite.TreeVisitor;
-import org.openrewrite.java.JavaIsoVisitor;
-import org.openrewrite.java.JavaTemplate;
-import org.openrewrite.java.search.FindAnnotations;
-import org.openrewrite.java.search.UsesJavaVersion;
-import org.openrewrite.java.search.UsesType;
-import org.openrewrite.java.tree.J;
-import org.openrewrite.java.tree.JavaType;
-import org.openrewrite.java.tree.TypeUtils;
-
-import java.time.Duration;
-import java.util.Comparator;
-
-public class AddSerialAnnotationToSerialVersionUID extends Recipe {
- @Override
- public String getDisplayName() {
- return "Add `@Serial` annotation to `serialVersionUID`";
- }
-
- @Override
- public String getDescription() {
- return "Annotation any `serialVersionUID` fields with `@Serial` to indicate it's part of the serialization mechanism.";
- }
-
- @Override
- public Duration getEstimatedEffortPerOccurrence() {
- return Duration.ofMinutes(1);
- }
-
- @Override
- @NonNull
- public TreeVisitor, ExecutionContext> getVisitor() {
- return Preconditions.check(
- Preconditions.and(
- new UsesJavaVersion<>(14),
- new UsesType<>("java.io.Serializable", true)
- ),
- new JavaIsoVisitor
- * 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.staticanalysis;
-
-import org.jspecify.annotations.Nullable;
-import org.openrewrite.*;
-import org.openrewrite.internal.ListUtils;
-import org.openrewrite.java.JavaIsoVisitor;
-import org.openrewrite.java.JavaTemplate;
-import org.openrewrite.java.tree.J;
-import org.openrewrite.java.tree.JavaType;
-import org.openrewrite.java.tree.Space;
-import org.openrewrite.java.tree.TypeUtils;
-import org.openrewrite.marker.Markers;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class AddSerialVersionUidToSerializable extends Recipe {
-
- @Override
- public String getDisplayName() {
- return "Add `serialVersionUID` to a `Serializable` class when missing";
- }
-
- @Override
- public String getDescription() {
- return "A `serialVersionUID` field is strongly recommended in all `Serializable` classes. If this is not " +
- "defined on a `Serializable` class, the compiler will generate this value. If a change is later made " +
- "to the class, the generated value will change and attempts to deserialize the class will fail.";
- }
-
- @Override
- public Set
- * 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.staticanalysis;
-
-import org.jspecify.annotations.Nullable;
-import org.openrewrite.*;
-import org.openrewrite.java.JavaIsoVisitor;
-import org.openrewrite.java.JavaParser;
-import org.openrewrite.java.MethodMatcher;
-import org.openrewrite.java.search.UsesMethod;
-import org.openrewrite.java.tree.*;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
-
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
-
-public class ChainStringBuilderAppendCalls extends Recipe {
- private static final MethodMatcher STRING_BUILDER_APPEND = new MethodMatcher("java.lang.StringBuilder append(String)");
-
- @SuppressWarnings("ALL") // Stop NoMutableStaticFieldsInRecipes from suggesting to remove this mutable static field
- private static J.Binary additiveBinaryTemplate = null;
-
- @Override
- public String getDisplayName() {
- return "Chain `StringBuilder.append()` calls";
- }
-
- @Override
- public String getDescription() {
- return "String concatenation within calls to `StringBuilder.append()` causes unnecessary memory allocation. Except for concatenations of String literals, which are joined together at compile time. Replaces inefficient concatenations with chained calls to `StringBuilder.append()`.";
- }
-
- @Override
- public @Nullable Duration getEstimatedEffortPerOccurrence() {
- return Duration.ofMinutes(2);
- }
-
- @Override
- public TreeVisitor, ExecutionContext> getVisitor() {
- return Preconditions.check(new UsesMethod<>(STRING_BUILDER_APPEND), Repeat.repeatUntilStable(new JavaIsoVisitor
- * 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.staticanalysis;
-
-import org.jspecify.annotations.Nullable;
-import org.openrewrite.*;
-import org.openrewrite.java.JavaVisitor;
-import org.openrewrite.java.VariableNameUtils;
-import org.openrewrite.java.search.SemanticallyEqual;
-import org.openrewrite.java.search.UsesJavaVersion;
-import org.openrewrite.java.tree.*;
-import org.openrewrite.java.tree.J.VariableDeclarations.NamedVariable;
-import org.openrewrite.marker.Markers;
-import org.openrewrite.staticanalysis.groovy.GroovyFileChecker;
-import org.openrewrite.staticanalysis.kotlin.KotlinFileChecker;
-
-import java.time.Duration;
-import java.util.*;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static java.util.Collections.emptyList;
-import static java.util.Objects.requireNonNull;
-import static org.openrewrite.Tree.randomId;
-import static org.openrewrite.java.VariableNameUtils.GenerationStrategy.INCREMENT_NUMBER;
-
-public class InstanceOfPatternMatch extends Recipe {
-
- @Override
- public String getDisplayName() {
- return "Changes code to use Java 17's `instanceof` pattern matching";
- }
-
- @Override
- public String getDescription() {
- return "Adds pattern variables to `instanceof` expressions wherever the same (side effect free) expression is referenced in a corresponding type cast expression within the flow scope of the `instanceof`." +
- " Currently, this recipe supports `if` statements and ternary operator expressions.";
- }
-
- @Override
- public Duration getEstimatedEffortPerOccurrence() {
- return Duration.ofMinutes(1);
- }
-
- @Override
- public TreeVisitor, ExecutionContext> getVisitor() {
- TreeVisitor, ExecutionContext> preconditions = Preconditions.and(
- new UsesJavaVersion<>(17),
- Preconditions.not(new KotlinFileChecker<>()),
- Preconditions.not(new GroovyFileChecker<>())
- );
-
- return Preconditions.check(preconditions, new JavaVisitor
- * 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.staticanalysis;
-
-import org.openrewrite.*;
-import org.openrewrite.java.JavaIsoVisitor;
-import org.openrewrite.java.JavaTemplate;
-import org.openrewrite.java.MethodMatcher;
-import org.openrewrite.java.search.UsesJavaVersion;
-import org.openrewrite.java.tree.Expression;
-import org.openrewrite.java.tree.J;
-import org.openrewrite.java.tree.JavaType;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
-
-public class ReplaceDeprecatedRuntimeExecMethods extends Recipe {
- private static final MethodMatcher RUNTIME_EXEC_CMD = new MethodMatcher("java.lang.Runtime exec(String)");
- private static final MethodMatcher RUNTIME_EXEC_CMD_ENVP = new MethodMatcher("java.lang.Runtime exec(String, String[])");
- private static final MethodMatcher RUNTIME_EXEC_CMD_ENVP_FILE = new MethodMatcher("java.lang.Runtime exec(String, String[], java.io.File)");
-
- @Override
- public String getDisplayName() {
- return "Replace deprecated `Runtime#exec()` methods";
- }
-
- @Override
- public String getDescription() {
- return "Replace `Runtime#exec(String)` methods to use `exec(String[])` instead because the former is deprecated " +
- "after Java 18 and is no longer recommended for use by the Java documentation.";
- }
-
- @Override
- public Duration getEstimatedEffortPerOccurrence() {
- return Duration.ofMinutes(3);
- }
-
- @Override
- public TreeVisitor, ExecutionContext> getVisitor() {
- return Preconditions.check(new UsesJavaVersion<>(18), new JavaIsoVisitor
- * 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.staticanalysis.groovy;
-
-import org.jspecify.annotations.Nullable;
-import org.openrewrite.Tree;
-import org.openrewrite.TreeVisitor;
-import org.openrewrite.groovy.tree.G;
-import org.openrewrite.marker.SearchResult;
-
-/**
- * Add a search marker if vising a Groovy file
- */
-public class GroovyFileChecker extends TreeVisitor
- * 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.staticanalysis.kotlin;
-
-import org.jspecify.annotations.Nullable;
-import org.openrewrite.Tree;
-import org.openrewrite.TreeVisitor;
-import org.openrewrite.java.tree.J;
-import org.openrewrite.marker.SearchResult;
-
-/**
- * Add a search marker if vising a Kotlin file
- */
-public class KotlinFileChecker extends TreeVisitor
-# 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.
-#
----
-type: specs.openrewrite.org/v1beta/recipe
-name: org.springframework.ide.vscode.rewrite.boot3.UpgradeSpringBoot_3_4
-displayName: Migrate to Spring Boot 3.4
-description: >-
- Migrate applications to the latest Spring Boot 3.4 release. This recipe will modify an
- application's build files and migrate configuration settings that have
- changes between versions.
-tags:
- - spring
- - boot
-recipeList:
- - org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3
- - org.openrewrite.java.spring.boot3.SpringBootProperties_3_4
- - org.openrewrite.java.dependencies.UpgradeDependencyVersion:
- groupId: org.springframework.boot
- artifactId: "*"
- newVersion: 3.4.x
- overrideManagedVersion: false
- - org.openrewrite.maven.UpgradePluginVersion:
- groupId: org.springframework.boot
- artifactId: spring-boot-maven-plugin
- newVersion: 3.4.x
- - org.openrewrite.java.dependencies.UpgradeDependencyVersion:
- groupId: org.springframework
- artifactId: "*"
- newVersion: 6.2.x
- - org.openrewrite.maven.UpgradeParentVersion:
- groupId: org.springframework.boot
- artifactId: spring-boot-starter-parent
- newVersion: 3.4.x
- - org.openrewrite.gradle.plugins.UpgradePluginVersion:
- pluginIdPattern: org.springframework.boot
- newVersion: 3.4.x
-
diff --git a/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/UpgradeSpringBoot_3_5.yml b/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/UpgradeSpringBoot_3_5.yml
deleted file mode 100644
index 858cdedac3..0000000000
--- a/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/UpgradeSpringBoot_3_5.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# Copyright 2024 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.
-#
----
-type: specs.openrewrite.org/v1beta/recipe
-name: org.springframework.ide.vscode.rewrite.boot3.UpgradeSpringBoot_3_5
-displayName: Migrate to Spring Boot 3.5
-description: >-
- Migrate applications to the latest Spring Boot 3.5 release. This recipe will modify an
- application's build files and migrate configuration settings that have
- changes between versions.
-tags:
- - spring
- - boot
-recipeList:
- - org.springframework.ide.vscode.rewrite.boot3.UpgradeSpringBoot_3_4
- - org.openrewrite.java.spring.boot3.SpringBootProperties_3_5
- - org.openrewrite.java.dependencies.UpgradeDependencyVersion:
- groupId: org.springframework.boot
- artifactId: "*"
- newVersion: 3.5.x
- overrideManagedVersion: false
- - org.openrewrite.maven.UpgradePluginVersion:
- groupId: org.springframework.boot
- artifactId: spring-boot-maven-plugin
- newVersion: 3.5.x
- - org.openrewrite.maven.UpgradeParentVersion:
- groupId: org.springframework.boot
- artifactId: spring-boot-starter-parent
- newVersion: 3.5.x
- - org.openrewrite.gradle.plugins.UpgradePluginVersion:
- pluginIdPattern: org.springframework.boot
- newVersion: 3.5.x
-
diff --git a/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/spring-boot-34-properties.yml b/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/spring-boot-34-properties.yml
deleted file mode 100644
index 5af7958f03..0000000000
--- a/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/spring-boot-34-properties.yml
+++ /dev/null
@@ -1,120 +0,0 @@
-#
-# Copyright 2024 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.
-#
-# This file is automatically generated by the GeneratePropertiesMigratorConfiguration class.
-# Do not edit this file manually. Update the Spring Boot property metadata upstream instead.
----
-type: specs.openrewrite.org/v1beta/recipe
-name: org.openrewrite.java.spring.boot3.SpringBootProperties_3_4
-displayName: Migrate Spring Boot properties to 3.4
-description: Migrate properties found in `application.properties` and `application.yml`.
-tags:
- - spring
- - boot
-recipeList:
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.auditevents.enabled
- newPropertyKey: management.endpoint.auditevents.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.beans.enabled
- newPropertyKey: management.endpoint.beans.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.caches.enabled
- newPropertyKey: management.endpoint.caches.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.conditions.enabled
- newPropertyKey: management.endpoint.conditions.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.configprops.enabled
- newPropertyKey: management.endpoint.configprops.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.env.enabled
- newPropertyKey: management.endpoint.env.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.flyway.enabled
- newPropertyKey: management.endpoint.flyway.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.health.enabled
- newPropertyKey: management.endpoint.health.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.heapdump.enabled
- newPropertyKey: management.endpoint.heapdump.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.httpexchanges.enabled
- newPropertyKey: management.endpoint.httpexchanges.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.info.enabled
- newPropertyKey: management.endpoint.info.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.integrationgraph.enabled
- newPropertyKey: management.endpoint.integrationgraph.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.liquibase.enabled
- newPropertyKey: management.endpoint.liquibase.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.logfile.enabled
- newPropertyKey: management.endpoint.logfile.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.loggers.enabled
- newPropertyKey: management.endpoint.loggers.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.mappings.enabled
- newPropertyKey: management.endpoint.mappings.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.metrics.enabled
- newPropertyKey: management.endpoint.metrics.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.prometheus.enabled
- newPropertyKey: management.endpoint.prometheus.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.quartz.enabled
- newPropertyKey: management.endpoint.quartz.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.sbom.enabled
- newPropertyKey: management.endpoint.sbom.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.scheduledtasks.enabled
- newPropertyKey: management.endpoint.scheduledtasks.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.sessions.enabled
- newPropertyKey: management.endpoint.sessions.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.shutdown.enabled
- newPropertyKey: management.endpoint.shutdown.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.startup.enabled
- newPropertyKey: management.endpoint.startup.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoint.threaddump.enabled
- newPropertyKey: management.endpoint.threaddump.access
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.endpoints.enabled-by-default
- newPropertyKey: management.endpoints.access.default
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.gson.lenient
- newPropertyKey: spring.gson.strictness
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.kafka.retry.topic.delay
- newPropertyKey: spring.kafka.retry.topic.backoff.delay
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.kafka.retry.topic.max-delay
- newPropertyKey: spring.kafka.retry.topic.backoff.maxDelay
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.kafka.retry.topic.multiplier
- newPropertyKey: spring.kafka.retry.topic.backoff.multiplier
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.kafka.retry.topic.random-back-off
- newPropertyKey: spring.kafka.retry.topic.backoff.random
-
diff --git a/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/spring-boot-35-properties.yml b/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/spring-boot-35-properties.yml
deleted file mode 100644
index d95c8d77ba..0000000000
--- a/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/spring-boot-35-properties.yml
+++ /dev/null
@@ -1,94 +0,0 @@
-# This file is automatically generated by the GeneratePropertiesMigratorConfiguration class.
-# Do not edit this file manually. Update the Spring Boot property metadata upstream instead.
----
-type: specs.openrewrite.org/v1beta/recipe
-name: org.openrewrite.java.spring.boot3.SpringBootProperties_3_5
-displayName: Migrate Spring Boot properties to 3.5
-description: Migrate properties found in `application.properties` and `application.yml`.
-tags:
- - spring
- - boot
-recipeList:
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: management.promethus.metrics.export.pushgateway.base-url
- newPropertyKey: management.prometheus.metrics.export.pushgateway.address
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.codec.log-request-details
- newPropertyKey: spring.http.codec.log-request-details
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.codec.max-in-memory-size
- newPropertyKey: spring.http.codec.max-in-memory-size
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.graphql.path
- newPropertyKey: spring.graphql.http.path
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.graphql.sse.timeout
- newPropertyKey: spring.graphql.http.sse.timeout
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.auto-escape
- newPropertyKey: spring.groovy.template.auto-escape
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.auto-indent
- newPropertyKey: spring.groovy.template.auto-indent
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.auto-indent-string
- newPropertyKey: spring.groovy.template.auto-indent-string
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.auto-new-line
- newPropertyKey: spring.groovy.template.auto-new-line
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.base-template-class
- newPropertyKey: spring.groovy.template.base-template-class
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.cache-templates
- newPropertyKey: spring.groovy.template.cache
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.declaration-encoding
- newPropertyKey: spring.groovy.template.declaration-encoding
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.expand-empty-elements
- newPropertyKey: spring.groovy.template.expand-empty-elements
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.locale
- newPropertyKey: spring.groovy.template.locale
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.new-line-string
- newPropertyKey: spring.groovy.template.new-line-string
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.resource-loader-path
- newPropertyKey: spring.groovy.template.resource-loader-path
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.groovy.template.configuration.use-double-quotes
- newPropertyKey: spring.groovy.template.use-double-quotes
- - org.openrewrite.java.spring.ChangeSpringPropertyKey:
- oldPropertyKey: spring.mvc.converters.preferred-json-mapper
- newPropertyKey: spring.http.converters.preferred-json-mapper
-
- - org.openrewrite.java.spring.CommentOutSpringPropertyKey:
- propertyKey: management.signalfx.metrics.export.access-token
- comment: "This property is deprecated: Deprecated in Micrometer 1.15.0"
- - org.openrewrite.java.spring.CommentOutSpringPropertyKey:
- propertyKey: management.signalfx.metrics.export.batch-size
- comment: "This property is deprecated: Deprecated in Micrometer 1.15.0"
- - org.openrewrite.java.spring.CommentOutSpringPropertyKey:
- propertyKey: management.signalfx.metrics.export.connect-timeout
- comment: "This property is deprecated: Deprecated in Micrometer 1.15.0"
- - org.openrewrite.java.spring.CommentOutSpringPropertyKey:
- propertyKey: management.signalfx.metrics.export.enabled
- comment: "This property is deprecated: Deprecated in Micrometer 1.15.0"
- - org.openrewrite.java.spring.CommentOutSpringPropertyKey:
- propertyKey: management.signalfx.metrics.export.published-histogram-type
- comment: "This property is deprecated: Deprecated in Micrometer 1.15.0"
- - org.openrewrite.java.spring.CommentOutSpringPropertyKey:
- propertyKey: management.signalfx.metrics.export.read-timeout
- comment: "This property is deprecated: Deprecated in Micrometer 1.15.0"
- - org.openrewrite.java.spring.CommentOutSpringPropertyKey:
- propertyKey: management.signalfx.metrics.export.source
- comment: "This property is deprecated: Deprecated in Micrometer 1.15.0"
- - org.openrewrite.java.spring.CommentOutSpringPropertyKey:
- propertyKey: management.signalfx.metrics.export.step
- comment: "This property is deprecated: Deprecated in Micrometer 1.15.0"
- - org.openrewrite.java.spring.CommentOutSpringPropertyKey:
- propertyKey: management.signalfx.metrics.export.uri
- comment: "This property is deprecated: Deprecated in Micrometer 1.15.0"
-
diff --git a/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/upgrade-boot3.yml b/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/upgrade-boot3.yml
deleted file mode 100644
index 517ff400ac..0000000000
--- a/headless-services/commons/commons-rewrite/src/main/resources/META-INF/rewrite/upgrade-boot3.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Copyright 2022 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.
-#
----
-########################################################################################################################
-# SpringBoot 3_0
-#type: specs.openrewrite.org/v1beta/recipe
-#name: org.springframework.sts.java.spring.boot3.UpgradeSpringBoot_3_0
-#displayName: Upgrade to Spring Boot 3.0 from 2.7
-#description: 'Upgrade to Spring Boot 3.0 from prior 2.x version.'
-#recipeList:
-# - org.openrewrite.maven.AddRepository:
-# id: spring-snapshots
-# url: https://repo.spring.io/snapshot
-# snapshotsEnabled: true
-# - org.openrewrite.maven.AddRepository:
-# id: spring-milestones
-# url: https://repo.spring.io/milestone
-# snapshotsEnabled: false
-# - org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0
-#---
diff --git a/headless-services/commons/commons-rewrite/src/main/resources/init.gradle b/headless-services/commons/commons-rewrite/src/main/resources/init.gradle
index 8e02bfb7a8..83af97635a 100644
--- a/headless-services/commons/commons-rewrite/src/main/resources/init.gradle
+++ b/headless-services/commons/commons-rewrite/src/main/resources/init.gradle
@@ -28,8 +28,7 @@ initscript {
}
dependencies {
- classpath 'org.openrewrite.gradle.tooling:plugin:2.8.0'
- classpath 'org.openrewrite:rewrite-maven:8.42.5'
+ classpath 'org.openrewrite.gradle.tooling:plugin:8.65.0'
}
}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/AddSpringPropertyTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/AddSpringPropertyTest.java
new file mode 100644
index 0000000000..b07cee8643
--- /dev/null
+++ b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/AddSpringPropertyTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.test.RewriteTest;
+
+import java.util.List;
+
+import static org.openrewrite.properties.Assertions.properties;
+import static org.openrewrite.yaml.Assertions.yaml;
+
+
+class AddSpringPropertyTest implements RewriteTest {
+
+ @DocumentExample
+ @Test
+ void addNestedIntoExisting() {
+ rewriteRun(
+ spec -> spec.recipe(new AddSpringProperty("server.servlet.path", "/tmp/my-server-path", null, List.of("*"))),
+ //language=properties
+ properties(
+ """
+ server.port=8080
+ """,
+ """
+ server.port=8080
+ server.servlet.path=/tmp/my-server-path
+ """
+ ),
+ //language=yaml
+ yaml(
+ """
+ server:
+ port: 8080
+ """,
+ """
+ server:
+ port: 8080
+ servlet:
+ path: /tmp/my-server-path
+ """
+ )
+ );
+ }
+
+ @Test
+ void addPropertyToRoot() {
+ rewriteRun(
+ spec -> spec.recipe(new AddSpringProperty("fred", "fred", null, List.of("*"))),
+ //language=properties
+ properties(
+ """
+ servlet.session.cookie.path=/cookie-monster
+ """,
+ """
+ fred=fred
+ servlet.session.cookie.path=/cookie-monster
+ """
+ ),
+ //language=yaml
+ yaml(
+ """
+ server:
+ port: 8888
+ """,
+ """
+ server:
+ port: 8888
+ fred: fred
+ """
+ )
+ );
+ }
+
+ @Test
+ void propertyAlreadyExists() {
+ rewriteRun(
+ spec -> spec.recipe(new AddSpringProperty("fred", "fred", null, List.of("*"))),
+ //language=properties
+ properties(
+ """
+ servlet.session.cookie.path=/cookie-monster
+ fred=doNotChangeThis
+ """
+ ),
+ //language=yaml
+ yaml(
+ """
+ server:
+ port: 8888
+ fred: doNotChangeThis
+ """
+ )
+ );
+ }
+
+ @Test
+ void addPropertyWithComment() {
+ rewriteRun(
+ spec -> spec.recipe(new AddSpringProperty("server.servlet.path", "/tmp/my-server-path", "This property was added", List.of("*"))),
+ //language=properties
+ properties(
+ """
+ server.port=8080
+ """,
+ """
+ server.port=8080
+ # This property was added
+ server.servlet.path=/tmp/my-server-path
+ """
+ ),
+ //language=yaml
+ yaml(
+ """
+ server:
+ port: 8080
+ """,
+ """
+ server:
+ port: 8080
+ servlet:
+ # This property was added
+ path: /tmp/my-server-path
+ """
+ )
+ );
+ }
+
+ @Test
+ void makeChangeToMatchingFiles() {
+ rewriteRun(
+ spec -> spec.recipe(new AddSpringProperty("server.servlet.path", "/tmp/my-server-path", null, List.of("**/application.properties", "**/application.yml"))),
+ properties(
+ //language=properties
+ """
+ server.port=8080
+ """,
+ //language=properties
+ """
+ server.port=8080
+ server.servlet.path=/tmp/my-server-path
+ """,
+ s -> s.path("src/main/resources/application.properties")
+ ),
+ yaml(
+ //language=yaml
+ """
+ server:
+ port: 8080
+ """,
+ //language=yaml
+ """
+ server:
+ port: 8080
+ servlet:
+ path: /tmp/my-server-path
+ """,
+ s -> s.path("src/main/resources/application.yml")
+ )
+ );
+ }
+
+ @Test
+ void doNotChangeToFilesThatDoNotMatch() {
+ rewriteRun(
+ spec -> spec.recipe(new AddSpringProperty("server.servlet.path", "/tmp/my-server-path", null, List.of("**/application.properties", "**/application.yml"))),
+ properties(
+ //language=properties
+ """
+ server.port=8080
+ """,
+ s -> s.path("src/main/resources/application-test.properties")
+ ),
+ yaml(
+ //language=yaml
+ """
+ server:
+ port: 8080
+ """,
+ s -> s.path("src/main/resources/application-dev.yml")
+ )
+ );
+ }
+}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/ChangeSpringPropertyValueTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/ChangeSpringPropertyValueTest.java
new file mode 100644
index 0000000000..299d6cc3db
--- /dev/null
+++ b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/ChangeSpringPropertyValueTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2023 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;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.properties.Assertions.properties;
+import static org.openrewrite.yaml.Assertions.yaml;
+
+class ChangeSpringPropertyValueTest implements RewriteTest {
+ @DocumentExample
+ @Test
+ void propFile() {
+ rewriteRun(
+ spec -> spec.recipe(new ChangeSpringPropertyValue("server.port", "8081", null, null, null)),
+ properties("server.port=8080", "server.port=8081")
+ );
+ }
+
+ @Test
+ void yamlDotSeparated() {
+ rewriteRun(
+ spec -> spec.recipe(new ChangeSpringPropertyValue("server.port", "8081", null, null, null)),
+ yaml("server.port: 8080", "server.port: 8081")
+ );
+ }
+
+ @Test
+ void yamlIndented() {
+ rewriteRun(
+ spec -> spec.recipe(new ChangeSpringPropertyValue("server.port", "8081", null, null, null)),
+ yaml("server:\n port: 8080", "server:\n port: 8081")
+ );
+ }
+
+ @Test
+ void regex() {
+ rewriteRun(
+ spec -> spec.recipe(new ChangeSpringPropertyValue("server.port", "80$1", "^([0-9]{2})$", true, null)),
+ properties("server.port=53", "server.port=8053"),
+ yaml("server.port: 53", "server.port: 8053")
+ );
+ }
+}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/ImplicitWebAnnotationNamesTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/ImplicitWebAnnotationNamesTest.java
new file mode 100644
index 0000000000..2f538876ec
--- /dev/null
+++ b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/ImplicitWebAnnotationNamesTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+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 ImplicitWebAnnotationNamesTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new ImplicitWebAnnotationNames())
+ .parser(JavaParser.fromJavaVersion().classpath("spring-web"));
+ }
+
+ @DocumentExample
+ @Test
+ void removeUnnecessaryAnnotationArgument() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.http.ResponseEntity;
+ import org.springframework.web.bind.annotation.*;
+
+ @RestController
+ @RequestMapping("/users")
+ public class UsersController {
+ @GetMapping("/{id}")
+ public ResponseEntity
+ * 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;
+
+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 NoAutowiredOnConstructorTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new NoAutowiredOnConstructor())
+ .parser(JavaParser.fromJavaVersion().classpath("spring-beans", "spring-boot", "spring-context", "spring-core"));
+ }
+
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/78")
+ @Test
+ void removeLeadingAutowiredAnnotation() {
+ //language=java
+ rewriteRun(
+ java("@org.springframework.stereotype.Component public class TestSourceA {}"),
+ java("@org.springframework.stereotype.Component public class TestSourceB {}"),
+ java("@org.springframework.stereotype.Component public class TestSourceC {}"),
+ java(
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+
+ @Autowired
+ public class TestConfiguration {
+ private final TestSourceA testSourceA;
+ private TestSourceB testSourceB;
+
+ @Autowired
+ private TestSourceC testSourceC;
+
+ @Autowired
+ public TestConfiguration(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+
+ @Autowired
+ public void setTestSourceB(TestSourceB testSourceB) {
+ this.testSourceB = testSourceB;
+ }
+ }
+ """,
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+
+ @Autowired
+ public class TestConfiguration {
+ private final TestSourceA testSourceA;
+ private TestSourceB testSourceB;
+
+ @Autowired
+ private TestSourceC testSourceC;
+
+ public TestConfiguration(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+
+ @Autowired
+ public void setTestSourceB(TestSourceB testSourceB) {
+ this.testSourceB = testSourceB;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/78")
+ @Test
+ void removeLeadingAutowiredAnnotationNoModifiers() {
+ //language=java
+ rewriteRun(
+ java("@org.springframework.stereotype.Component public class TestSourceA {}"),
+ java("@org.springframework.stereotype.Component public class TestSourceB {}"),
+ java("@org.springframework.stereotype.Component public class TestSourceC {}"),
+ java(
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+
+ public class TestConfiguration {
+ private final TestSourceA testSourceA;
+ private TestSourceB testSourceB;
+
+ @Autowired
+ private TestSourceC testSourceC;
+
+ @Autowired
+ TestConfiguration(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+
+ @Autowired
+ public void setTestSourceB(TestSourceB testSourceB) {
+ this.testSourceB = testSourceB;
+ }
+ }
+ """,
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+
+ public class TestConfiguration {
+ private final TestSourceA testSourceA;
+ private TestSourceB testSourceB;
+
+ @Autowired
+ private TestSourceC testSourceC;
+
+ TestConfiguration(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+
+ @Autowired
+ public void setTestSourceB(TestSourceB testSourceB) {
+ this.testSourceB = testSourceB;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/78")
+ @Test
+ void removeAutowiredWithMultipleAnnotation() {
+ //language=java
+ rewriteRun(
+ java("@org.springframework.stereotype.Component public class TestSourceA {}"),
+ java(
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos1 {
+ private final TestSourceA testSourceA;
+
+ @Autowired
+ @Deprecated
+ @Qualifier
+ public AnnotationPos1(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """,
+ """
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos1 {
+ private final TestSourceA testSourceA;
+
+ @Deprecated
+ @Qualifier
+ public AnnotationPos1(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """
+ ),
+ java(
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos2 {
+ private final TestSourceA testSourceA;
+
+ @Deprecated
+ @Autowired
+ @Qualifier
+ public AnnotationPos2(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """,
+ """
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos2 {
+ private final TestSourceA testSourceA;
+
+ @Deprecated
+ @Qualifier
+ public AnnotationPos2(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """
+ ),
+ java(
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos3 {
+ private final TestSourceA testSourceA;
+
+ @Deprecated
+ @Qualifier
+ @Autowired
+ public AnnotationPos3(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """,
+ """
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos3 {
+ private final TestSourceA testSourceA;
+
+ @Deprecated
+ @Qualifier
+ public AnnotationPos3(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/78")
+ @Test
+ void removeAutowiredWithMultipleInLineAnnotation() {
+ //language=java
+ rewriteRun(
+ java("@org.springframework.stereotype.Component public class TestSourceA {}"),
+ java(
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos1 {
+ private final TestSourceA testSourceA;
+
+ @Autowired @Deprecated @Qualifier
+ public AnnotationPos1(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """,
+ """
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos1 {
+ private final TestSourceA testSourceA;
+
+ @Deprecated @Qualifier
+ public AnnotationPos1(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """
+ ),
+ java(
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos2 {
+ private final TestSourceA testSourceA;
+
+ @Deprecated @Autowired @Qualifier
+ public AnnotationPos2(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """,
+ """
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos2 {
+ private final TestSourceA testSourceA;
+
+ @Deprecated @Qualifier
+ public AnnotationPos2(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """
+ ),
+ java(
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos3 {
+ private final TestSourceA testSourceA;
+
+ @Deprecated @Qualifier @Autowired
+ public AnnotationPos3(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """,
+ """
+ import org.springframework.beans.factory.annotation.Qualifier;
+
+ public class AnnotationPos3 {
+ private final TestSourceA testSourceA;
+
+ @Deprecated @Qualifier
+ public AnnotationPos3(TestSourceA testSourceA) {
+ this.testSourceA = testSourceA;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/78")
+ @Test
+ void oneNamePrefixAnnotation() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import javax.sql.DataSource;
+ import org.springframework.beans.factory.annotation.Autowired;
+
+ public class DatabaseConfiguration {
+ private final DataSource dataSource;
+
+ public @Autowired DatabaseConfiguration(DataSource dataSource) {
+ }
+ }
+ """,
+ """
+ import javax.sql.DataSource;
+
+ public class DatabaseConfiguration {
+ private final DataSource dataSource;
+
+ public DatabaseConfiguration(DataSource dataSource) {
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/78")
+ @Test
+ void multipleNamePrefixAnnotationsPos1() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import javax.sql.DataSource;
+ import org.springframework.beans.factory.annotation.Autowired;
+
+ public class DatabaseConfiguration {
+ private final DataSource dataSource;
+
+ public @Autowired @Deprecated DatabaseConfiguration(DataSource dataSource) {
+ }
+ }
+ """,
+ """
+ import javax.sql.DataSource;
+
+ public class DatabaseConfiguration {
+ private final DataSource dataSource;
+
+ public @Deprecated DatabaseConfiguration(DataSource dataSource) {
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/78")
+ @Test
+ void multipleNamePrefixAnnotationsPos2() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import javax.sql.DataSource;
+ import org.springframework.beans.factory.annotation.Autowired;
+
+ public class DatabaseConfiguration {
+ private final DataSource dataSource;
+
+ public @SuppressWarnings("") @Autowired @Deprecated DatabaseConfiguration(DataSource dataSource) {
+ }
+ }
+ """,
+ """
+ import javax.sql.DataSource;
+
+ public class DatabaseConfiguration {
+ private final DataSource dataSource;
+
+ public @SuppressWarnings("") @Deprecated DatabaseConfiguration(DataSource dataSource) {
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/78")
+ @Test
+ void multipleNamePrefixAnnotationsPos3() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import javax.sql.DataSource;
+ import org.springframework.beans.factory.annotation.Autowired;
+
+ public class DatabaseConfiguration {
+ private final DataSource dataSource;
+
+ public @SuppressWarnings("") @Deprecated @Autowired DatabaseConfiguration(DataSource dataSource) {
+ }
+ }
+ """,
+ """
+ import javax.sql.DataSource;
+
+ public class DatabaseConfiguration {
+ private final DataSource dataSource;
+
+ public @SuppressWarnings("") @Deprecated DatabaseConfiguration(DataSource dataSource) {
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/78")
+ @Test
+ void keepAutowiredAnnotationsWhenMultipleConstructorsExist() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.springframework.core.io.Resource;
+ import java.io.PrintStream;
+
+ public class MyAppResourceService {
+ private final Resource someResource;
+ private final PrintStream printStream;
+
+ public MyAppResourceService(Resource someResource) {
+ this.someResource = someResource;
+ this.printStream = System.out;
+ }
+
+ @Autowired
+ public MyAppResourceService(Resource someResource, PrintStream printStream) {
+ this.someResource = someResource;
+ this.printStream = printStream;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void optionalAutowiredAnnotations() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+ import javax.sql.DataSource;
+
+ public class DatabaseConfiguration {
+ private final DataSource dataSource;
+
+ public DatabaseConfiguration(@Autowired(required = false) DataSource dataSource) {
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noAutowiredAnnotations() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.context.annotation.Primary;
+ import javax.sql.DataSource;
+
+ public class DatabaseConfiguration {
+ private final DataSource dataSource;
+
+ @Primary
+ public DatabaseConfiguration(DataSource dataSource) {
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void ignoreConfigurationProperties() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.springframework.boot.context.properties.ConfigurationProperties;
+ import org.springframework.core.env.Environment;
+ @ConfigurationProperties
+ public class ArchivingWorkflowListenerProperties {
+ private final Environment environment;
+ @Autowired
+ public ArchivingWorkflowListenerProperties(Environment environment) {
+ this.environment = environment;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/479")
+ void ignoreLombokConstructors() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ package lombok;
+
+ import java.lang.annotation.ElementType;
+ import java.lang.annotation.Retention;
+ import java.lang.annotation.RetentionPolicy;
+ import java.lang.annotation.Target;
+
+ @Target({ElementType.TYPE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NoArgsConstructor {
+ }
+ """
+ ),
+ java(
+ """
+ import lombok.NoArgsConstructor;
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.springframework.core.env.Environment;
+ @NoArgsConstructor
+ public class ArchivingWorkflowListenerProperties {
+ private final Environment environment;
+ @Autowired
+ public ArchivingWorkflowListenerProperties(Environment environment) {
+ this.environment = environment;
+ }
+ }
+ """
+ )
+ );
+ }
+}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/NoRepoAnnotationOnRepoInterfaceTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/NoRepoAnnotationOnRepoInterfaceTest.java
new file mode 100644
index 0000000000..0d4058aa64
--- /dev/null
+++ b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/NoRepoAnnotationOnRepoInterfaceTest.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2022 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;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class NoRepoAnnotationOnRepoInterfaceTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new NoRepoAnnotationOnRepoInterface())
+ .parser(JavaParser.fromJavaVersion().classpath("spring-context", "spring-beans", "spring-data"));
+ }
+
+ @DocumentExample
+ @Test
+ void simpleCase() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.stereotype.Repository;
+
+ @Repository
+ public interface MyRepo extends org.springframework.data.repository.Repository {
+ }
+ """,
+ """
+
+ public interface MyRepo extends org.springframework.data.repository.Repository {
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void simpleCaseWithNoParameters() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.stereotype.Repository;
+
+ @Repository( )
+ public interface MyRepo extends org.springframework.data.repository.Repository {
+ }
+ """,
+ """
+
+ public interface MyRepo extends org.springframework.data.repository.Repository {
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void crudRepoClass() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import java.util.Optional;
+
+ import org.springframework.data.repository.CrudRepository;
+ import org.springframework.stereotype.Repository;
+
+ @Repository
+ public class MyRepo implements CrudRepository
+ * 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.boot2;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class AddConfigurationAnnotationIfBeansPresentTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new AddConfigurationAnnotationIfBeansPresent())
+ .parser(JavaParser.fromJavaVersion()
+ .classpath("spring-beans", "spring-context", "spring-boot", "spring-security", "spring-web", "spring-core"));
+ }
+
+ @Test
+ void enableWebSecurityNoBeans() {
+ rewriteRun(
+ java(
+ """
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+
+ @EnableWebSecurity
+ class A {}
+ """
+ )
+ );
+ }
+
+ @DocumentExample
+ @Test
+ void enableWebSecurityWithBeans() {
+ rewriteRun(
+ java(
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+
+ @EnableWebSecurity
+ class A {
+ @Bean String hello() { return "hello"; }
+ }
+ """,
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+
+ @Configuration
+ @EnableWebSecurity
+ class A {
+ @Bean String hello() { return "hello"; }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void configurationMetaAnnotation() {
+ rewriteRun(
+ java(
+ """
+ import org.springframework.boot.autoconfigure.SpringBootApplication;
+ import org.springframework.context.annotation.Bean;
+
+ @SpringBootApplication
+ class A {
+ @Bean String hello() { return "hello"; }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void abstractClassWithBeans() {
+ rewriteRun(
+ java(
+ """
+ import org.springframework.context.annotation.Bean;
+
+ abstract class A {
+ @Bean String hello() { return "hello"; }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noAnnotationsWithBean() {
+ rewriteRun(
+ java(
+ """
+ import org.springframework.context.annotation.Bean;
+
+ class A {
+ @Bean String hello() { return "hello"; }
+ }
+ """,
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.context.annotation.Configuration;
+
+ @Configuration
+ class A {
+ @Bean String hello() { return "hello"; }
+ }
+ """
+ )
+ );
+ }
+
+}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/boot2/UnnecessarySpringExtensionTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/boot2/UnnecessarySpringExtensionTest.java
new file mode 100644
index 0000000000..68519fa44e
--- /dev/null
+++ b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/boot2/UnnecessarySpringExtensionTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.boot2;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.openrewrite.Issue;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.java.spring.Jars;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class UnnecessarySpringExtensionTest implements RewriteTest {
+// override val parser: JavaParser
+// get() = JavaParser.fromJavaVersion()
+// .classpath("spring-context", "spring-test", "spring-boot-test", "junit-jupiter-api", "spring-boot-test-autoconfigure", "spring-batch-test")
+// .build()
+//
+// override val recipe: Recipe
+// get() = UnnecessarySpringExtension()
+
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new UnnecessarySpringExtension())
+ .parser(JavaParser.fromJavaVersion()
+ .classpath(Jars.BOOT_2_7.get()));
+ }
+
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/43")
+ @Test
+ void removeSpringExtensionIfSpringBootTestIsPresent() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.junit.jupiter.api.extension.ExtendWith;
+ import org.springframework.boot.test.context.SpringBootTest;
+ import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+ @SpringBootTest
+ @ExtendWith(SpringExtension.class)
+ class Test {
+ }
+ """,
+ """
+ import org.springframework.boot.test.context.SpringBootTest;
+
+ @SpringBootTest
+ class Test {
+ }
+ """
+ )
+ );
+ }
+
+ @Issue("https://github.com/openrewrite/rewrite-spring/issues/72")
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "org.springframework.boot.test.autoconfigure.jdbc.JdbcTest",
+ "org.springframework.boot.test.autoconfigure.web.client.RestClientTest",
+ "org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest",
+ "org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest",
+ "org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest",
+ "org.springframework.boot.test.autoconfigure.webservices.client.WebServiceClientTest",
+ "org.springframework.boot.test.autoconfigure.jooq.JooqTest",
+ "org.springframework.boot.test.autoconfigure.json.JsonTest",
+ "org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest",
+ "org.springframework.boot.test.autoconfigure.data.jdbc.DataJdbcTest",
+ "org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest",
+ "org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest",
+ "org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest",
+ "org.springframework.boot.test.autoconfigure.data.r2dbc.DataR2dbcTest",
+ "org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest",
+ "org.springframework.batch.test.context.SpringBatchTest"
+ })
+ void removeSpringExtensionForTestSliceAnnotations(String annotationName) {
+ rewriteRun(
+ java(
+ """
+ import org.junit.jupiter.api.extension.ExtendWith;
+ import %s;
+ import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+ @%s
+ @ExtendWith(SpringExtension.class)
+ class Test {
+ }
+ """.formatted(annotationName, annotationName.substring(annotationName.lastIndexOf('.') + 1)),
+ """
+ import %s;
+
+ @%s
+ class Test {
+ }
+ """.formatted(annotationName, annotationName.substring(annotationName.lastIndexOf('.') + 1))
+ )
+ );
+ }
+}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/boot3/PreciseBeanTypeTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/boot3/PreciseBeanTypeTest.java
new file mode 100644
index 0000000000..e788fc5357
--- /dev/null
+++ b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/boot3/PreciseBeanTypeTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2022 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.boot3;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class PreciseBeanTypeTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new PreciseBeanType())
+ .parser(JavaParser.fromJavaVersion()
+ .classpath("spring-context", "spring-boot"));
+ }
+
+ @DocumentExample
+ @Test
+ void simplestCase() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.context.annotation.Bean;
+ import java.util.List;
+ import java.util.ArrayList;
+
+ class A {
+ @Bean
+ List bean1() {
+ return new ArrayList();
+ }
+ }
+ """,
+ """
+ import org.springframework.context.annotation.Bean;
+ import java.util.ArrayList;
+
+ class A {
+ @Bean
+ ArrayList bean1() {
+ return new ArrayList();
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void nestedCase() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.context.annotation.Bean;
+ import java.util.List;
+ import java.util.ArrayList;
+ import java.util.Stack;
+ import java.util.concurrent.Callable;
+
+ class A {
+ @Bean
+ List bean1() {
+ Callable
+ * 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/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/security5/AuthorizeHttpRequestsTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/security5/AuthorizeHttpRequestsTest.java
new file mode 100644
index 0000000000..d0c397ce58
--- /dev/null
+++ b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/security5/AuthorizeHttpRequestsTest.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2023 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.security5;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.java.spring.Jars;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class AuthorizeHttpRequestsTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new AuthorizeHttpRequests())
+ .parser(JavaParser.fromJavaVersion()
+ .classpath(Jars.BOOT_2_7.get()));
+ }
+
+ @DocumentExample
+ @Test
+ void noArgAuthorizeRequests() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated()
+ .and()
+ .formLogin()
+ .loginPage("/login")
+ .permitAll()
+ .and()
+ .rememberMe();
+ }
+ }
+ """,
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeHttpRequests()
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated()
+ .and()
+ .formLogin()
+ .loginPage("/login")
+ .permitAll()
+ .and()
+ .rememberMe();
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Disabled
+ @Test
+ void noArgAuthorizeRequestsWithVars() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ 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
+ * 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.security5;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.java.spring.Jars;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class HttpSecurityLambdaDslTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new HttpSecurityLambdaDsl())
+ .parser(JavaParser.fromJavaVersion()
+ .classpath(Jars.BOOT_2_7.get()));
+ }
+
+ @DocumentExample
+ @Test
+ void simple() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated();
+ }
+ }
+ """,
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests(requests -> requests
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated());
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void advanced() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated()
+ .and()
+ .formLogin()
+ .loginPage("/login")
+ .permitAll()
+ .and()
+ .rememberMe();
+ }
+ }
+ """,
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ import static org.springframework.security.config.Customizer.withDefaults;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests(requests -> requests
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated())
+ .formLogin(login -> login
+ .loginPage("/login")
+ .permitAll())
+ .rememberMe(withDefaults());
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void handleDisableChain() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.csrf().disable();
+ }
+ }
+ """,
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.csrf(csrf -> csrf.disable());
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void retainComments() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // matcher order matters
+ http.authorizeRequests()
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated();
+ }
+ }
+ """,
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // matcher order matters
+ http.authorizeRequests(requests -> requests
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated());
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void retainFormatting() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.authorizeRequests()
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated();
+
+ http.csrf().disable();
+ }
+ }
+ """,
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.authorizeRequests(requests -> requests
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated());
+
+ http.csrf(csrf -> csrf.disable());
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void disableIsTerminal() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.csrf().disable()
+ .authorizeRequests()
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated();
+ }
+ }
+ """,
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.csrf(csrf -> csrf.disable())
+ .authorizeRequests(requests -> requests
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated());
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void disableAfterOptions() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.csrf().ignoringAntMatchers("").disable()
+ .authorizeRequests()
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated();
+ }
+ }
+ """,
+ """
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @EnableWebSecurity
+ public class ConventionalSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.csrf(csrf -> csrf.ignoringAntMatchers("").disable())
+ .authorizeRequests(requests -> requests
+ .antMatchers("/blog/**").permitAll()
+ .anyRequest().authenticated());
+ }
+ }
+ """
+ )
+ );
+ }
+}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/security5/ServerHttpSecurityLambdaDslTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/security5/ServerHttpSecurityLambdaDslTest.java
new file mode 100644
index 0000000000..d816bed4c9
--- /dev/null
+++ b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/security5/ServerHttpSecurityLambdaDslTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2023 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.security5;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.java.spring.Jars;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class ServerHttpSecurityLambdaDslTest implements RewriteTest {
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new ServerHttpSecurityLambdaDsl())
+ .parser(JavaParser.fromJavaVersion()
+ .classpath(Jars.BOOT_2_7.get()));
+ }
+
+ @DocumentExample
+ @Test
+ void simple() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+ import org.springframework.security.config.web.server.ServerHttpSecurity;
+ import org.springframework.security.web.server.SecurityWebFilterChain;
+
+ @EnableWebFluxSecurity
+ public class SecurityConfig {
+ @Bean
+ SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ http.authorizeExchange()
+ .pathMatchers("/blog/**").permitAll()
+ .anyExchange().authenticated();
+ return http.build();
+ }
+ }
+ """,
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+ import org.springframework.security.config.web.server.ServerHttpSecurity;
+ import org.springframework.security.web.server.SecurityWebFilterChain;
+
+ @EnableWebFluxSecurity
+ public class SecurityConfig {
+ @Bean
+ SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ http.authorizeExchange(exchange -> exchange
+ .pathMatchers("/blog/**").permitAll()
+ .anyExchange().authenticated());
+ return http.build();
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void advanced() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+ import org.springframework.security.config.web.server.ServerHttpSecurity;
+ import org.springframework.security.web.server.SecurityWebFilterChain;
+
+ @EnableWebFluxSecurity
+ public class SecurityConfig {
+ @Bean
+ SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ http
+ .authorizeExchange()
+ .pathMatchers("/blog/**").permitAll()
+ .anyExchange().authenticated()
+ .and()
+ .httpBasic()
+ .and()
+ .formLogin()
+ .loginPage("/login");
+ return http.build();
+ }
+ }
+ """,
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+ import org.springframework.security.config.web.server.ServerHttpSecurity;
+ import org.springframework.security.web.server.SecurityWebFilterChain;
+
+ import static org.springframework.security.config.Customizer.withDefaults;
+
+ @EnableWebFluxSecurity
+ public class SecurityConfig {
+ @Bean
+ SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ http
+ .authorizeExchange(exchange -> exchange
+ .pathMatchers("/blog/**").permitAll()
+ .anyExchange().authenticated())
+ .httpBasic(withDefaults())
+ .formLogin(login -> login
+ .loginPage("/login"));
+ return http.build();
+ }
+ }
+ """
+ )
+ );
+ }
+
+}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/security5/WebSecurityConfigurerAdapterTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/security5/WebSecurityConfigurerAdapterTest.java
new file mode 100644
index 0000000000..be0f31a3e9
--- /dev/null
+++ b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/security5/WebSecurityConfigurerAdapterTest.java
@@ -0,0 +1,739 @@
+/*
+ * Copyright 2022 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.security5;
+
+import static org.openrewrite.java.Assertions.java;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.java.spring.Jars;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+/**
+ * @author Alex Boyko
+ */
+class WebSecurityConfigurerAdapterTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new WebSecurityConfigurerAdapter())
+ .parser(JavaParser.fromJavaVersion()
+ .classpath(Jars.BOOT_2_7.get()));
+ }
+
+ @DocumentExample
+ @Test
+ void configureHttpSecurityMethod() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ package com.example.websecuritydemo;
+
+ import static org.springframework.security.config.Customizer.withDefaults;
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+
+ @Configuration
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeHttpRequests((authz) -> authz
+ .anyRequest().authenticated()
+ )
+ .httpBasic(withDefaults());
+ }
+
+ void someMethod() {}
+
+ }
+ """,
+ """
+ package com.example.websecuritydemo;
+
+ import static org.springframework.security.config.Customizer.withDefaults;
+
+ 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.web.SecurityFilterChain;
+
+ @Configuration
+ public class SecurityConfiguration {
+
+ @Bean
+ SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+ http
+ .authorizeHttpRequests((authz) -> authz
+ .anyRequest().authenticated()
+ )
+ .httpBasic(withDefaults());
+ return http.build();
+ }
+
+ void someMethod() {}
+
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noConfigurationAnnotation() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ package com.example.websecuritydemo;
+
+ import static org.springframework.security.config.Customizer.withDefaults;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeHttpRequests((authz) -> authz
+ .anyRequest().authenticated()
+ )
+ .httpBasic(withDefaults());
+ }
+
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void configureWebSecurityMethod() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.config.annotation.web.builders.WebSecurity;
+
+ @Configuration
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Override
+ public void configure(WebSecurity web) {
+ web.ignoring().antMatchers("/ignore1", "/ignore2");
+ }
+ }
+ """,
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.web.builders.WebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
+
+ @Configuration
+ public class SecurityConfiguration {
+
+ @Bean
+ WebSecurityCustomizer webSecurityCustomizer() {
+ return (web) -> {
+ web.ignoring().antMatchers("/ignore1", "/ignore2");
+ };
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void configureAuthManagerMethod() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+ import org.springframework.security.ldap.userdetails.PersonContextMapper;
+
+ @Configuration
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) {
+ auth
+ .ldapAuthentication()
+ .userDetailsContextMapper(new PersonContextMapper())
+ .userDnPatterns("uid={0},ou=people")
+ .contextSource()
+ .port(0);
+ }
+ }
+ """,
+ """
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+ import org.springframework.security.ldap.userdetails.PersonContextMapper;
+
+ @Configuration
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ /*~~(Migrate manually based on https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter)~~>*/@Override
+ protected void configure(AuthenticationManagerBuilder auth) {
+ auth
+ .ldapAuthentication()
+ .userDetailsContextMapper(new PersonContextMapper())
+ .userDnPatterns("uid={0},ou=people")
+ .contextSource()
+ .port(0);
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void overrideUnapplicableMethod() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import static org.springframework.security.config.Customizer.withDefaults;
+
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.authentication.AuthenticationManager;
+ import org.springframework.security.core.userdetails.UserDetailsService;
+
+ @Configuration
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeHttpRequests((authz) -> authz
+ .anyRequest().authenticated()
+ )
+ .httpBasic(withDefaults());
+ }
+
+ @Override
+ public UserDetailsService userDetailsServiceBean() throws Exception {
+ return null;
+ }
+
+ @Override
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return null;
+ }
+ }
+ """,
+ """
+ import static org.springframework.security.config.Customizer.withDefaults;
+
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.authentication.AuthenticationManager;
+ import org.springframework.security.core.userdetails.UserDetailsService;
+
+ @Configuration
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeHttpRequests((authz) -> authz
+ .anyRequest().authenticated()
+ )
+ .httpBasic(withDefaults());
+ }
+
+ /*~~(Migrate manually based on https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter)~~>*/@Override
+ public UserDetailsService userDetailsServiceBean() throws Exception {
+ return null;
+ }
+
+ /*~~(Migrate manually based on https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter)~~>*/@Override
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return null;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void unapplicableMethodInvocation() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import static org.springframework.security.config.Customizer.withDefaults;
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+
+ @Configuration
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) {
+ System.out.println(getApplicationContext());
+ http
+ .authorizeHttpRequests((authz) -> authz
+ .anyRequest().authenticated()
+ )
+ .httpBasic(withDefaults());
+ }
+
+ public void someMethod() {}
+ }
+ """,
+ """
+ import static org.springframework.security.config.Customizer.withDefaults;
+
+ 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.web.SecurityFilterChain;
+
+ @Configuration
+ public class SecurityConfiguration {
+
+ @Bean
+ SecurityFilterChain filterChain(HttpSecurity http) {
+ System.out.println(getApplicationContext());
+ http
+ .authorizeHttpRequests((authz) -> authz
+ .anyRequest().authenticated()
+ )
+ .httpBasic(withDefaults());
+ return http.build();
+ }
+
+ public void someMethod() {}
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void configureHttpSecurityMethodWithNotApplicableMethodInNonStaticInnerClass() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import static org.springframework.security.config.Customizer.withDefaults;
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+
+ @Configuration
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeHttpRequests((authz) -> authz
+ .anyRequest().authenticated()
+ )
+ .httpBasic(withDefaults());
+ }
+
+ @Configuration
+ public class InnerSecurityConfiguration {
+ protected void configure() throws Exception {
+ System.out.println(getApplicationContext());
+ }
+ }
+ }
+ """,
+ """
+ import static org.springframework.security.config.Customizer.withDefaults;
+
+ 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.web.SecurityFilterChain;
+
+ @Configuration
+ public class SecurityConfiguration {
+
+ @Bean
+ SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+ http
+ .authorizeHttpRequests((authz) -> authz
+ .anyRequest().authenticated()
+ )
+ .httpBasic(withDefaults());
+ return http.build();
+ }
+
+ @Configuration
+ public class InnerSecurityConfiguration {
+ protected void configure() throws Exception {
+ System.out.println(getApplicationContext());
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void multipleClasses() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.core.annotation.Order;
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.core.userdetails.UserDetailsService;
+ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+
+ @EnableWebSecurity
+ public class MultiHttpSecurityConfig {
+ @Bean
+ public UserDetailsService userDetailsService() throws Exception {
+ InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
+ return manager;
+ }
+
+ @Configuration
+ @Order(1)
+ public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .antMatcher("/api/**")
+ .authorizeRequests()
+ .anyRequest().hasRole("ADMIN")
+ .and()
+ .httpBasic();
+ }
+ }
+
+ @Configuration
+ public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .anyRequest().authenticated()
+ .and()
+ .formLogin();
+ }
+ }
+ }
+ """,
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.core.userdetails.UserDetailsService;
+ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+ import org.springframework.security.web.SecurityFilterChain;
+
+ @EnableWebSecurity
+ public class MultiHttpSecurityConfig {
+ @Bean
+ public UserDetailsService userDetailsService() throws Exception {
+ InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
+ return manager;
+ }
+
+ @Bean
+ SecurityFilterChain apiWebSecurityConfigurationSecurityFilterChain(HttpSecurity http) throws Exception {
+ http
+ .antMatcher("/api/**")
+ .authorizeRequests()
+ .anyRequest().hasRole("ADMIN")
+ .and()
+ .httpBasic();
+ return http.build();
+ }
+
+ @Bean
+ SecurityFilterChain formLoginSecurityFilterChain(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .anyRequest().authenticated()
+ .and()
+ .formLogin();
+ return http.build();
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void multipleClassesNoFlattening() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.core.annotation.Order;
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.core.userdetails.UserDetailsService;
+ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+
+ @EnableWebSecurity
+ public class MultiHttpSecurityConfig {
+ private int a;
+
+ @Bean
+ public UserDetailsService userDetailsService() throws Exception {
+ InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
+ return manager;
+ }
+
+ @Configuration
+ @Order(1)
+ public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
+ private String a;
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .antMatcher("/api/**")
+ .authorizeRequests()
+ .anyRequest().hasRole("ADMIN")
+ .and()
+ .httpBasic();
+ }
+ }
+
+ @Configuration
+ public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .anyRequest().authenticated()
+ .and()
+ .formLogin();
+ }
+ }
+ }
+ """,
+ """
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.core.annotation.Order;
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+ import org.springframework.security.core.userdetails.UserDetailsService;
+ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+ import org.springframework.security.web.SecurityFilterChain;
+
+ @EnableWebSecurity
+ public class MultiHttpSecurityConfig {
+ private int a;
+
+ @Bean
+ public UserDetailsService userDetailsService() throws Exception {
+ InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
+ return manager;
+ }
+
+ @Configuration
+ @Order(1)
+ public static class ApiWebSecurityConfigurationAdapter {
+ private String a;
+
+ @Bean
+ SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+ http
+ .antMatcher("/api/**")
+ .authorizeRequests()
+ .anyRequest().hasRole("ADMIN")
+ .and()
+ .httpBasic();
+ return http.build();
+ }
+ }
+
+ @Bean
+ SecurityFilterChain formLoginSecurityFilterChain(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .anyRequest().authenticated()
+ .and()
+ .formLogin();
+ return http.build();
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void inMemoryConfig() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ package com.example.websecuritydemo;
+
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.core.userdetails.User;
+ import org.springframework.security.core.userdetails.UserDetails;
+
+ @Configuration
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER")
+ .build();
+ auth.inMemoryAuthentication().withUser(user);
+ }
+ }
+ """,
+ """
+ package com.example.websecuritydemo;
+
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.core.userdetails.User;
+ import org.springframework.security.core.userdetails.UserDetails;
+ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+
+ @Configuration
+ public class SecurityConfiguration {
+ @Bean
+ InMemoryUserDetailsManager inMemoryAuthManager() throws Exception {
+ UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER")
+ .build();
+ return new InMemoryUserDetailsManager(user);
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void inMemoryConfigWithUserBuilder() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ package com.example.websecuritydemo;
+
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+ import org.springframework.security.core.userdetails.User;
+ import org.springframework.security.core.userdetails.User.UserBuilder;
+
+ @Configuration
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ UserBuilder builder = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER");
+ auth.inMemoryAuthentication().withUser(builder);
+ }
+ }
+ """,
+ """
+ package com.example.websecuritydemo;
+
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.core.userdetails.User;
+ import org.springframework.security.core.userdetails.User.UserBuilder;
+ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+
+ @Configuration
+ public class SecurityConfiguration {
+ @Bean
+ InMemoryUserDetailsManager inMemoryAuthManager() throws Exception {
+ UserBuilder builder = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER");
+ return new InMemoryUserDetailsManager(builder.build());
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void inMemoryConfigWithUserString() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ package com.example.websecuritydemo;
+
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+ import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+ @Configuration
+ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.inMemoryAuthentication().withUser("user");
+ }
+ }
+ """,
+ """
+ package com.example.websecuritydemo;
+
+ import org.springframework.context.annotation.Bean;
+ import org.springframework.context.annotation.Configuration;
+ import org.springframework.security.core.userdetails.User;
+ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+
+ @Configuration
+ public class SecurityConfiguration {
+ @Bean
+ InMemoryUserDetailsManager inMemoryAuthManager() throws Exception {
+ return new InMemoryUserDetailsManager(User.builder().username("user").build());
+ }
+ }
+ """
+ )
+ );
+ }
+}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToSerialVersionUIDTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToSerialVersionUIDTest.java
deleted file mode 100644
index cb3beed753..0000000000
--- a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToSerialVersionUIDTest.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright 2024 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.staticanalysis;
-
-import org.junit.jupiter.api.Test;
-import org.openrewrite.DocumentExample;
-import org.openrewrite.test.RecipeSpec;
-import org.openrewrite.test.RewriteTest;
-
-import static org.openrewrite.java.Assertions.java;
-import static org.openrewrite.java.Assertions.javaVersion;
-
-class AddSerialAnnotationToSerialVersionUIDTest implements RewriteTest {
- @Override
- public void defaults(RecipeSpec spec) {
- spec.recipe(new AddSerialAnnotationToSerialVersionUID())
- .allSources(sourceSpec -> sourceSpec.markers(javaVersion(17)));
- }
-
- @DocumentExample
- @Test
- void addSerialAnnotation() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- class Example implements Serializable {
- private static final long serialVersionUID = 1L;
- }
- """,
- """
- import java.io.Serial;
- import java.io.Serializable;
-
- class Example implements Serializable {
- @Serial
- private static final long serialVersionUID = 1L;
- }
- """
- )
- );
- }
-
- @Test
- void shouldAddToNewFieldWhenChained() {
- rewriteRun(
- spec -> spec.recipes(
- new AddSerialVersionUidToSerializable(),
- new AddSerialAnnotationToSerialVersionUID()),
- //language=java
- java(
- """
- import java.io.Serializable;
-
- class Example implements Serializable {
- }
- """,
- """
- import java.io.Serial;
- import java.io.Serializable;
-
- class Example implements Serializable {
- @Serial
- private static final long serialVersionUID = 1;
- }
- """
- )
- );
- }
-
- @Test
- void shouldNoopIfAlreadyPresent() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
- import java.io.Serial;
-
- class Example implements Serializable {
- String var1 = "first variable";
- @Serial
- private static final long serialVersionUID = 1L;
- int var3 = 666;
- }
- """
- )
- );
- }
-
- @Test
- void shouldNotAnnotateNonSerializableClass() {
- rewriteRun(
- //language=java
- java(
- """
- class Example {
- private static final long serialVersionUID = 1L;
- }
- """
- )
- );
- }
-
- @Test
- void shouldNotAnnotateOnJava11() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- class Example implements Serializable {
- private static final long serialVersionUID = 1L;
- }
- """,
- spec -> spec.markers(javaVersion(11))
- )
- );
- }
-
- @Test
- void shouldNotAnnotateOtherFields() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- class Example implements Serializable {
- static final long serialVersionUID = 1L;
- private final long serialVersionUID = 1L;
- private static long serialVersionUID = 1L;
- private static final int serialVersionUID = 1L;
- private static final long foo = 1L;
-
- void doSomething() {
- long serialVersionUID = 1L;
- }
- }
- """
- )
- );
- }
-
- @Test
- void shouldAnnotatedFieldsInInnerClasses() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- class Outer implements Serializable {
- private static final long serialVersionUID = 1;
- static class Inner implements Serializable {
- private static final long serialVersionUID = 1;
- }
- }
- """,
- """
- import java.io.Serial;
- import java.io.Serializable;
-
- class Outer implements Serializable {
- @Serial
- private static final long serialVersionUID = 1;
- static class Inner implements Serializable {
- @Serial
- private static final long serialVersionUID = 1;
- }
- }
- """
- )
- );
- }
-}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/AddSerialVersionUidToSerializableTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/AddSerialVersionUidToSerializableTest.java
deleted file mode 100644
index 696f002486..0000000000
--- a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/AddSerialVersionUidToSerializableTest.java
+++ /dev/null
@@ -1,275 +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.staticanalysis;
-
-import org.junit.jupiter.api.Test;
-import org.openrewrite.DocumentExample;
-import org.openrewrite.test.RecipeSpec;
-import org.openrewrite.test.RewriteTest;
-
-import static org.openrewrite.java.Assertions.java;
-
-@SuppressWarnings("MissingSerialAnnotation")
-class AddSerialVersionUidToSerializableTest implements RewriteTest {
-
- @Override
- public void defaults(RecipeSpec spec) {
- spec.recipe(new AddSerialVersionUidToSerializable());
- }
-
- @Test
- void doNothingNotSerializable() {
- rewriteRun(
- //language=java
- java(
- """
- public class Example {
- private String fred;
- private int numberOfFreds;
- }
- """
- )
- );
- }
-
- @DocumentExample
- @Test
- void addSerialVersionUID() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- public class Example implements Serializable {
- private String fred;
- private int numberOfFreds;
- }
- """,
- """
- import java.io.Serializable;
-
- public class Example implements Serializable {
- private static final long serialVersionUID = 1;
- private String fred;
- private int numberOfFreds;
- }
- """
- )
- );
- }
-
- @Test
- void fixSerialVersionUIDModifiers() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- public class Example implements Serializable {
- private final long serialVersionUID = 1;
- private String fred;
- private int numberOfFreds;
- }
- """,
- """
- import java.io.Serializable;
-
- public class Example implements Serializable {
- private static final long serialVersionUID = 1;
- private String fred;
- private int numberOfFreds;
- }
- """
- )
- );
- }
-
- @Test
- void fixSerialVersionUIDNoModifiers() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- public class Example implements Serializable {
- long serialVersionUID = 1;
- private String fred;
- private int numberOfFreds;
- }
- """,
- """
- import java.io.Serializable;
-
- public class Example implements Serializable {
- private static final long serialVersionUID = 1;
- private String fred;
- private int numberOfFreds;
- }
- """
- )
- );
- }
-
- @Test
- void fixSerialVersionUIDNoModifiersWrongType() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- public class Example implements Serializable {
- Long serialVersionUID = 1L;
- private String fred;
- private int numberOfFreds;
- }
- """,
- """
- import java.io.Serializable;
-
- public class Example implements Serializable {
- private static final long serialVersionUID = 1L;
- private String fred;
- private int numberOfFreds;
- }
- """
- )
- );
- }
-
- @Test
- void uidAlreadyPresent() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- public class Example implements Serializable {
- private static final long serialVersionUID = 1;
- private String fred;
- private int numberOfFreds;
- }
- """
- )
- );
- }
-
- @Test
- void methodDeclarationsAreNotVisited() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- public class Example implements Serializable {
- private String fred;
- private int numberOfFreds;
- void doSomething() {
- int serialVersionUID = 1;
- }
- }
- """,
- """
- import java.io.Serializable;
-
- public class Example implements Serializable {
- private static final long serialVersionUID = 1;
- private String fred;
- private int numberOfFreds;
- void doSomething() {
- int serialVersionUID = 1;
- }
- }
- """
- )
- );
- }
-
- @Test
- void doNotAlterAnInterface() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- public interface Example extends Serializable {
- }
- """
- )
- );
- }
-
- @Test
- void doNotAlterAnException() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- public class MyException extends Exception implements Serializable {
- }
- """
- )
- );
- }
-
- @Test
- void doNotAlterARuntimeException() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
-
- public class MyException extends RuntimeException implements Serializable {
- }
- """
- )
- );
- }
-
- @Test
- void serializableInnerClass() {
- rewriteRun(
- //language=java
- java(
- """
- import java.io.Serializable;
- public class Outer implements Serializable {
- public static class Inner implements Serializable {
- }
- }
- """,
- """
- import java.io.Serializable;
- public class Outer implements Serializable {
- private static final long serialVersionUID = 1;
- public static class Inner implements Serializable {
- private static final long serialVersionUID = 1;
- }
- }
- """
- )
- );
- }
-}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/ChainStringBuilderAppendCallsTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/ChainStringBuilderAppendCallsTest.java
deleted file mode 100644
index a57b908df9..0000000000
--- a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/ChainStringBuilderAppendCallsTest.java
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright 2023 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.staticanalysis;
-
-import org.junit.jupiter.api.Test;
-import org.openrewrite.DocumentExample;
-import org.openrewrite.test.RecipeSpec;
-import org.openrewrite.test.RewriteTest;
-
-import static org.openrewrite.java.Assertions.java;
-
-@SuppressWarnings({"StringConcatenationInsideStringBufferAppend", "StringBufferReplaceableByString"})
-class ChainStringBuilderAppendCallsTest implements RewriteTest {
- @Override
- public void defaults(RecipeSpec spec) {
- spec.recipe(new ChainStringBuilderAppendCalls());
- }
-
- @DocumentExample(value = "Chain `StringBuilder.append()` calls instead of the '+' operator to efficiently concatenate strings and numbers.")
- @Test
- void objectsConcatenation() {
- rewriteRun(
- //language=java
- java(
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append("A" + op + "B");
- sb.append(1 + op + 2);
- }
- }
- """,
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append("A").append(op).append("B");
- sb.append(1).append(op).append(2);
- }
- }
- """
- )
- );
- }
-
- @Test
- void literalConcatenationIgnored() {
- rewriteRun(
- //language=java
- java(
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- sb.append("A" + "B" + "C");
- }
- }
- """
- )
- );
- }
-
- @DocumentExample("Grouping concatenation.")
- @Test
- void groupedStringsConcatenation() {
- rewriteRun(
- //language=java
- java(
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append("A" + "B" + "C" + op + "D" + "E");
- }
- }
- """,
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append("A" + "B" + "C").append(op).append("D" + "E");
- }
- }
- """
- )
- );
- }
-
- @Test
- void unWrap() {
- rewriteRun(
- //language=java
- java(
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append(("A" + op + "B"));
- }
- }
- """,
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append("A").append(op).append("B");
- }
- }
- """
- )
- );
- }
-
- @Test
- void chainedAppend() {
- rewriteRun(
- //language=java
- java(
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append(("A" + op)).append("B");
- }
- }
- """,
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append("A").append(op).append("B");
- }
- }
- """
- )
- );
- }
-
- @Test
- void runMultipleTimes() {
- rewriteRun(
- //language=java
- java(
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append(("A" + op) + "B");
- }
- }
- """,
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append("A").append(op).append("B");
- }
- }
- """
- )
- );
- }
-
- @Test
- void correctlyGroupConcatenations() {
- rewriteRun(
- //language=java
- java(
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append(op + 1 + 2 + "A" + "B" + 'x');
- sb.append(1 + 2 + op + 3 + 4);
- sb.append(1 + 2 + name() + 3 + 4);
- sb.append(op + (1 + 2));
- }
- String name() { return "name"; }
- }
- """,
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- String op = "+";
- sb.append(op).append(1).append(2).append("A" + "B").append('x');
- sb.append(1 + 2).append(op).append(3).append(4);
- sb.append(1 + 2).append(name()).append(3).append(4);
- sb.append(op).append(1 + 2);
- }
- String name() { return "name"; }
- }
- """
- )
- );
- }
-
- @Test
- void appendMethods() {
- rewriteRun(
- //language=java
- java(
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- sb.append(str1() + str2() + str3());
- }
-
- String str1() { return "A"; }
- String str2() { return "B"; }
- String str3() { return "C"; }
- }
- """,
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder();
- sb.append(str1()).append(str2()).append(str3());
- }
-
- String str1() { return "A"; }
- String str2() { return "B"; }
- String str3() { return "C"; }
- }
- """
- )
- );
- }
-
- @Test
- void ChainedAppendWithConstructor() {
- rewriteRun(
- //language=java
- java(
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder().append("A" + operator() + "B");
- }
-
- String operator() { return "+"; }
- }
- """,
- """
- class A {
- void method1() {
- StringBuilder sb = new StringBuilder().append("A").append(operator()).append("B");
- }
-
- String operator() { return "+"; }
- }
- """
- )
- );
- }
-
- @Test
- void methodArgument() {
- rewriteRun(
- //language=java
- java(
- """
- class A {
- void method1() {
- String op = "+";
- print(new StringBuilder().append("A" + op + "C").toString());
- }
-
- void print(String str) {
- }
- }
- """,
- """
- class A {
- void method1() {
- String op = "+";
- print(new StringBuilder().append("A").append(op).append("C").toString());
- }
-
- void print(String str) {
- }
- }
- """
- )
- );
- }
-}
diff --git a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/InstanceOfPatternMatchTest.java b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/InstanceOfPatternMatchTest.java
deleted file mode 100644
index 4eaee8b51a..0000000000
--- a/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/staticanalysis/InstanceOfPatternMatchTest.java
+++ /dev/null
@@ -1,1296 +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.staticanalysis;
-
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.openrewrite.Issue;
-import org.openrewrite.test.RecipeSpec;
-import org.openrewrite.test.RewriteTest;
-
-import static org.openrewrite.java.Assertions.java;
-import static org.openrewrite.java.Assertions.version;
-
-@SuppressWarnings({"RedundantCast", "DataFlowIssue", "ConstantValue", "ImplicitArrayToString", "PatternVariableCanBeUsed", "UnnecessaryLocalVariable", "SizeReplaceableByIsEmpty", "rawtypes", "ResultOfMethodCallIgnored", "ArraysAsListWithZeroOrOneArgument", "DuplicateCondition"})
-class InstanceOfPatternMatchTest implements RewriteTest {
-
- @Override
- public void defaults(RecipeSpec spec) {
- spec.recipe(new InstanceOfPatternMatch())
- .allSources(sourceSpec -> version(sourceSpec, 17));
- }
-
-
- @Nested
- class If {
- @Test
- void ifConditionWithoutPattern() {
- rewriteRun(
- //language=java
- java(
- """
- public class A {
- void test(Object o) {
- Object s = 1;
- if (o instanceof String && ((String) (o)).length() > 0) {
- if (((String) o).length() > 1) {
- System.out.println(o);
- }
- }
- }
- }
- """,
- """
- public class A {
- void test(Object o) {
- Object s = 1;
- if (o instanceof String string && string.length() > 0) {
- if (string.length() > 1) {
- System.out.println(o);
- }
- }
- }
- }
- """
- )
- );
- }
-
- @Test
- void multipleCasts() {
- rewriteRun(
- //language=java
- java(
- """
- public class A {
- void test(Object o, Object o2) {
- Object string = 1;
- if (o instanceof String && o2 instanceof Integer) {
- System.out.println((String) o);
- System.out.println((Integer) o2);
- }
- }
- }
- """,
- """
- public class A {
- void test(Object o, Object o2) {
- Object string = 1;
- if (o instanceof String string1 && o2 instanceof Integer integer) {
- System.out.println(string1);
- System.out.println(integer);
- }
- }
- }
- """
- )
- );
- }
-
- @Test
- void longNames() {
- rewriteRun(
- //language=java
- java(
- """
- import java.util.ArrayList;
- public class A {
- void test(Object o) {
- Object list = 1;
- if (o instanceof ArrayList>) {
- System.out.println((ArrayList>) o);
- }
- }
- }
- """,
- """
- import java.util.ArrayList;
- public class A {
- void test(Object o) {
- Object list = 1;
- if (o instanceof ArrayList> arrayList) {
- System.out.println(arrayList);
- }
- }
- }
- """
- )
- );
- }
-
- @Test
- void typeParameters_1() {
- rewriteRun(
- //language=java
- java(
- """
- import java.util.Collections;
- import java.util.List;
- import java.util.Map;
- import java.util.stream.Collectors;
- import java.util.stream.Stream;
- public class A {
- @SuppressWarnings("unchecked")
- public static Stream
+ *
+ */
+public class NoRequestMappingAnnotation extends Recipe {
+
+ @Override
+ public String getDisplayName() {
+ return "Remove `@RequestMapping` annotations";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Replace method declaration `@RequestMapping` annotations with `@GetMapping`, `@PostMapping`, etc. when possible.";
+ }
+
+ @Override
+ public Set> BOOT_2_7 = Suppliers.memoize(() -> {
+ try {
+ return getDependencyJarsForClasspath(
+ //language=xml
+ """
+
S save(S entity) {
+ return null;
+ }
+
+ @Override
+ public Iterable saveAll(Iterable entities) {
+ return null;
+ }
+
+ @Override
+ public Optional callable = () -> {
+ return new ArrayList();
+ };
+ return new Stack();
+ }
+ }
+ """,
+ """
+ import org.springframework.context.annotation.Bean;
+ import java.util.List;
+ import java.util.ArrayList;
+ import java.util.Stack;
+ import java.util.concurrent.Callable;
+
+ class A {
+ @Bean
+ Stack bean1() {
+ Callable
callable = () -> {
+ return new ArrayList();
+ };
+ return new Stack();
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void notApplicableCase() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.context.annotation.Bean;
+ import java.util.ArrayList;
+
+ class A {
+ @Bean
+ ArrayList bean1() {
+ return new ArrayList();
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void notApplicablePrimitiveTypeCase() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.springframework.context.annotation.Bean;
+
+ class A {
+ @Bean
+ String bean1() {
+ return "hello";
+ }
+ }
+ """
+ )
+ );
+ }
+}
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
new file mode 100644
index 0000000000..cc5c2e115d
--- /dev/null
+++ b/headless-services/commons/commons-rewrite/src/test/java/org/openrewrite/java/spring/framework/BeanMethodsNotPublicTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *