diff --git a/components/sbm-recipes-boot-upgrade/pom.xml b/components/sbm-recipes-boot-upgrade/pom.xml
index 83025a12c..4a5bf03a2 100644
--- a/components/sbm-recipes-boot-upgrade/pom.xml
+++ b/components/sbm-recipes-boot-upgrade/pom.xml
@@ -63,6 +63,10 @@
spring-asciidoctor-backends
${spring-asciidoctor-backends.version}
+
+ org.openrewrite.recipe
+ rewrite-spring
+
org.springframework.boot
spring-boot-starter-test
@@ -91,7 +95,6 @@
test
-
spring-release
@@ -102,4 +105,4 @@
-
\ No newline at end of file
+
diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportHelper.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportHelper.java
index 82db3824a..24bdcc9b4 100644
--- a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportHelper.java
+++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportHelper.java
@@ -21,7 +21,6 @@
import org.springframework.sbm.project.resource.RewriteSourceFileHolder;
import java.nio.file.Path;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ConstructorBindingHelper.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ConstructorBindingHelper.java
new file mode 100644
index 000000000..56763321a
--- /dev/null
+++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ConstructorBindingHelper.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2021 - 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.springframework.sbm.boot.upgrade_27_30.report.helper;
+
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.internal.lang.Nullable;
+import org.openrewrite.java.search.UsesType;
+import org.openrewrite.java.spring.boot3.RemoveConstructorBindingAnnotation;
+import org.openrewrite.java.tree.J;
+import org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportSection;
+import org.springframework.sbm.engine.context.ProjectContext;
+import org.springframework.sbm.engine.recipe.OpenRewriteSourceFilesFinder;
+import org.springframework.sbm.project.resource.RewriteSourceFileHolder;
+import org.springframework.sbm.support.openrewrite.GenericOpenRewriteRecipe;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+
+public class ConstructorBindingHelper implements SpringBootUpgradeReportSection.Helper> {
+
+ private List constructorBindingFiles;
+
+ @Override
+ public String getDescription() {
+ return "";
+ }
+
+ @Override
+ public boolean evaluate(ProjectContext context) {
+
+ GenericOpenRewriteRecipe> recipe =
+ new GenericOpenRewriteRecipe<>(() -> new UsesType("org.springframework.boot.context.properties.ConstructorBinding"));
+
+ List> rewriteSourceFileHolders =
+ context.getProjectJavaSources().find(recipe);
+
+ constructorBindingFiles = rewriteSourceFileHolders
+ .stream()
+ .map(k -> k.getAbsolutePath().toString())
+ .collect(Collectors.toList());
+
+ return !rewriteSourceFileHolders.isEmpty();
+ }
+
+ @Override
+ public Map> getData(ProjectContext context) {
+
+ return Map.of("files", constructorBindingFiles);
+ }
+}
diff --git a/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-new-report.yaml b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-new-report.yaml
index cf6030a66..2edafc9c1 100644
--- a/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-new-report.yaml
+++ b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-new-report.yaml
@@ -130,6 +130,33 @@
recipe: boot-2.7-3.0-upgrade-report
contributors:
- "Sandeep Nagaraj[@sanagaraj-pivotal]"
+
+ - title: Constructor Binding
+ helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.ConstructorBindingHelper
+ change: |-
+ When using constructor bound @ConfigurationProperties the @ConstructorBinding annotation
+ is no longer required if the class has a single parameterized constructor.
+ If you have more than one constructor, you’ll still need to use `@ConstructorBinding`
+ to tell Spring Boot which one to use.
+
+ For most users, this updated logic will allow for simpler `@ConfigurationProperties`
+ classes. If, however, you have a `@ConfigurationProperties` and you want to inject
+ beans into the constructor rather than binding it, you’ll now need to add an
+ `@Autowired` annotation.
+ affected: |-
+ We found usage of `@ConstructorBinding` in following files:
+
+ <#list files as file>
+ * ${file}
+ #list>
+ remediation: |-
+ Remove `@ConstructorBinding` if it matches the criteria, please refer issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/166[#166]
+ for more information
+ gitHubIssue: 166
+ recipe: boot-2.7-3.0-upgrade-report
+ contributors:
+ - "Sandeep Nagaraj[@sanagaraj-pivotal]"
+
footer: |-
We want to say thank you to all Contributors:
diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/UpgradeBomTo30Test.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/UpgradeBomTo30Test.java
index a689424a3..493f69054 100644
--- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/UpgradeBomTo30Test.java
+++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/UpgradeBomTo30Test.java
@@ -20,8 +20,6 @@
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.Result;
-import org.openrewrite.java.JavaParser;
-import org.openrewrite.java.tree.J;
import org.openrewrite.maven.MavenParser;
import org.openrewrite.maven.UpgradeDependencyVersion;
import org.openrewrite.xml.tree.Xml;
diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/ChangesToDataPropertiesReportTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/ChangesToDataPropertiesReportTest.java
index 2afc33992..c5b05ebba 100644
--- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/ChangesToDataPropertiesReportTest.java
+++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/ChangesToDataPropertiesReportTest.java
@@ -15,7 +15,6 @@
*/
package org.springframework.sbm.boot.upgrade_27_30.report;
-import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.sbm.boot.properties.SpringApplicationPropertiesPathMatcher;
@@ -23,8 +22,6 @@
import org.springframework.sbm.engine.context.ProjectContext;
import org.springframework.sbm.project.resource.TestProjectContext;
-import java.nio.file.Path;
-import java.util.Map;
/**
* @author Fabian Krüger
@@ -44,26 +41,25 @@ void changesToDataPropertiesSection_renders() {
.fromProjectContext(context)
.shouldRenderAs(
"""
- === Changes to Data Properties
- Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/441[#441], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"]
-
- ==== What Changed
- The data prefix has been reserved for Spring Data and any properties under the `data` prefix imply that Spring
- Data is required on the classpath.
-
- ==== Why is the application affected
- The scan found properties with `spring.data` prefix but no dependency matching `org.springframework.data:.*`.
-
- * file:///src/main/resources/application.properties[`src/main/resources/application.properties`]
- ** `spring.data.foo`
- * file:///src/main/resources/application-another.properties[`src/main/resources/application-another.properties`]
- ** `spring.data.here`
-
- ==== Remediation
- Either add `spring-data` dependency, rename the property or remove it in case it's not required anymore.
-
- """,
- Map.of("PATH", Path.of(".").toAbsolutePath().resolve(TestProjectContext.getDefaultProjectRoot()).toString()));
+ === Changes to Data Properties
+ Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/441[#441], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"]
+
+ ==== What Changed
+ The data prefix has been reserved for Spring Data and any properties under the `data` prefix imply that Spring
+ Data is required on the classpath.
+
+ ==== Why is the application affected
+ The scan found properties with `spring.data` prefix but no dependency matching `org.springframework.data:.*`.
+
+ * file:///src/main/resources/application.properties[`src/main/resources/application.properties`]
+ ** `spring.data.foo`
+ * file:///src/main/resources/application-another.properties[`src/main/resources/application-another.properties`]
+ ** `spring.data.here`
+
+ ==== Remediation
+ Either add `spring-data` dependency, rename the property or remove it in case it's not required anymore.
+
+ """);
}
@Test
diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportTestSupport.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportTestSupport.java
index 26d1bb5c9..94208df93 100644
--- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportTestSupport.java
+++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportTestSupport.java
@@ -21,6 +21,7 @@
import org.springframework.sbm.engine.recipe.Action;
import org.springframework.sbm.engine.recipe.Recipe;
import org.springframework.sbm.engine.recipe.Recipes;
+import org.springframework.sbm.project.resource.TestProjectContext;
import org.springframework.sbm.test.RecipeTestSupport;
import org.springframework.sbm.testhelper.common.utils.TestDiff;
import org.springframework.test.util.ReflectionTestUtils;
@@ -76,7 +77,7 @@ public Assertion(BuilderData builderData) {
public void shouldRenderAs(String expectedOutput) {
- shouldRenderAs(expectedOutput, Map.of());
+ shouldRenderAs(expectedOutput, defaultMap());
}
public void shouldRenderAs(String expectedOutput, Map templateVariables) {
@@ -90,7 +91,7 @@ public void shouldNotRender() {
}
public void shouldStartWith(String expectedOutput) {
- shouldStartWith(expectedOutput, Map.of());
+ shouldStartWith(expectedOutput, defaultMap());
}
public void shouldStartWith(String expectedOutput, Map templateVariables) {
@@ -99,6 +100,16 @@ public void shouldStartWith(String expectedOutput, Map templateV
verify(assertion);
}
+
+ private Map defaultMap() {
+ String path = Path
+ .of(".")
+ .toAbsolutePath()
+ .resolve(TestProjectContext.getDefaultProjectRoot()).toString();
+
+ return Map.of("PATH", path);
+ }
+
private void verifyDoesNotRender() {
if(SectionBuilderData.class.isInstance(builderData)) {
SectionBuilderData sectionBuilderData = SectionBuilderData.class.cast(builderData);
@@ -148,7 +159,6 @@ public void writeReport(String s, Path outputDir, String filename) {
action.apply(reportBuilderData.getContext());
});
} else if(SectionBuilderData.class.isInstance(builderData)) {
- SectionBuilderData sectionBuilderData = SectionBuilderData.class.cast(builderData);
withRecipes(recipes -> {
Recipe recipe = recipes.getRecipeByName("boot-2.7-3.0-upgrade-report2").get();
SpringBootUpgradeReportAction action = (SpringBootUpgradeReportAction) recipe.getActions().get(0);
diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportHelperTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportHelperTest.java
index cdf14ee4f..ca16ee9c2 100644
--- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportHelperTest.java
+++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportHelperTest.java
@@ -21,8 +21,6 @@
import org.springframework.sbm.engine.context.ProjectContext;
import org.springframework.sbm.project.resource.TestProjectContext;
-import java.nio.file.Path;
-import java.util.Map;
public class BannerSupportHelperTest {
@@ -55,7 +53,6 @@ public void rendersBannerSupportInformation() {
==== Remediation
remove image banners and replace it with text-banner with banner.txt file
- """,
- Map.of("PATH", Path.of(".").toAbsolutePath().resolve(TestProjectContext.getDefaultProjectRoot()).toString()));
+ """);
}
}
diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ConstructorBindingHelperTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ConstructorBindingHelperTest.java
new file mode 100644
index 000000000..a6708db40
--- /dev/null
+++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ConstructorBindingHelperTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2021 - 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.springframework.sbm.boot.upgrade_27_30.report.helper;
+
+import org.intellij.lang.annotations.Language;
+import org.junit.jupiter.api.Test;
+import org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportTestSupport;
+import org.springframework.sbm.engine.context.ProjectContext;
+import org.springframework.sbm.project.resource.TestProjectContext;
+
+public class ConstructorBindingHelperTest {
+
+ @Test
+ public void reportMigrationSuggestionsWhenConstructorBindingUsageIsFound() {
+ @Language("java")
+ String javaClassWithConstructorBinding = """
+ package com.example;
+
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.springframework.boot.context.properties.ConfigurationProperties;
+ import org.springframework.boot.context.properties.ConstructorBinding;
+
+ @ConfigurationProperties(prefix = "mail")
+ @ConstructorBinding
+ public class ConfigProperties {
+ private String hostName;
+ private int port;
+ private String from;
+
+ public ConfigProperties(String hostName, int port, String from) {
+ this.hostName = hostName;
+ this.port = port;
+ this.from = from;
+ }
+
+ public String getHostName() {
+ return hostName;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public String getFrom() {
+ return from;
+ }
+ }
+ """;
+
+ ProjectContext context = TestProjectContext.buildProjectContext()
+ .addJavaSource("src/main/java", javaClassWithConstructorBinding)
+ .withBuildFileHavingDependencies("org.springframework.boot:spring-boot:2.7.1")
+ .build();
+
+ SpringBootUpgradeReportTestSupport
+ .generatedSection("Constructor Binding")
+ .fromProjectContext(context)
+ .shouldRenderAs(
+ """
+ === Constructor Binding
+ Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/166[#166], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"]
+
+ ==== What Changed
+ When using constructor bound @ConfigurationProperties the @ConstructorBinding annotation
+ is no longer required if the class has a single parameterized constructor.
+ If you have more than one constructor, you’ll still need to use `@ConstructorBinding`
+ to tell Spring Boot which one to use.
+
+ For most users, this updated logic will allow for simpler `@ConfigurationProperties`
+ classes. If, however, you have a `@ConfigurationProperties` and you want to inject
+ beans into the constructor rather than binding it, you’ll now need to add an
+ `@Autowired` annotation.
+
+ ==== Why is the application affected
+ We found usage of `@ConstructorBinding` in following files:
+
+ * /src/main/java/com/example/ConfigProperties.java
+
+ ==== Remediation
+ Remove `@ConstructorBinding` if it matches the criteria, please refer issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/166[#166]
+ for more information
+
+ """
+ );
+ }
+
+ @Test
+ public void shouldNotReportConstructorBindingSuggestionWhenNothingIsFound() {
+ @Language("java")
+ String javaClassWithConstructorBinding = """
+ package com.example;
+
+ public class A { }
+ """;
+
+ ProjectContext context = TestProjectContext.buildProjectContext()
+ .addJavaSource("src/main/java/com/example/A.java", javaClassWithConstructorBinding)
+ .withBuildFileHavingDependencies("org.springframework.boot:spring-boot:2.7.1")
+ .build();
+
+ SpringBootUpgradeReportTestSupport
+ .generatedSection("Constructor Binding")
+ .fromProjectContext(context)
+ .shouldNotRender();
+ }
+}