diff --git a/src/test/java/org/openrewrite/java/spring/internal/GeneratePropertiesMigratorConfiguration.java b/src/test/java/org/openrewrite/java/spring/internal/GeneratePropertiesMigratorConfiguration.java index c55089caf..f22288978 100644 --- a/src/test/java/org/openrewrite/java/spring/internal/GeneratePropertiesMigratorConfiguration.java +++ b/src/test/java/org/openrewrite/java/spring/internal/GeneratePropertiesMigratorConfiguration.java @@ -18,7 +18,9 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import io.github.classgraph.ClassGraph; +import io.github.classgraph.ResourceList; import io.github.classgraph.ScanResult; +import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable; import org.openrewrite.maven.tree.Version; @@ -27,6 +29,7 @@ import java.io.InputStream; import java.io.UncheckedIOException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.time.LocalDate; @@ -35,16 +38,13 @@ import static java.util.Collections.emptySet; import static java.util.Objects.requireNonNull; -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toSet; +import static java.util.stream.Collectors.*; class GeneratePropertiesMigratorConfiguration { + private static final ObjectMapper objectMapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + public static void main(String[] args) throws IOException { var springBootReleases = new SpringBootReleases(true); // `true` for release candidates - - var objectMapper = new ObjectMapper() - .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - var releasesDir = new File(".boot-releases"); //noinspection ResultOfMethodCallIgnored releasesDir.mkdirs(); @@ -78,69 +78,116 @@ public static void main(String[] args) throws IOException { } System.out.println("Scanning version " + version); - try (ScanResult scanResult = new ClassGraph() .overrideClasspath(Arrays.stream(requireNonNull(versionDir.listFiles())).map(File::toURI).collect(Collectors.toList())) .acceptPaths("META-INF") .enableMemoryMapping() .scan()) { - var replacements = scanResult.getResourcesMatchingWildcard("**/*spring-configuration-metadata.json").stream() - .flatMap(res -> { - try (InputStream inputStream = res.open()) { - var metadata = objectMapper.readValue(inputStream, SpringConfigurationMetadata.class); - return metadata.properties().stream() - .filter(p -> p.deprecation() != null && p.deprecation().replacement() != null); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }) - .filter(p -> alreadyDefined.add(p.name())) - .sorted(Comparator.comparing(SpringConfigurationMetadata.ConfigurationProperty::name)) - .toList(); - - if (!replacements.isEmpty()) { - var majorMinor = version.split("\\."); - if (semanticVersion.compareTo(new Version("3.1")) < 0) { - // Don't override manual fixes to the unsupported 2.x and 3.0 versions anymore - continue; - } - - var config = Paths.get("src/main/resources/META-INF/rewrite/spring-boot-%s%s-properties.yml".formatted(majorMinor[0], majorMinor[1])); - Files.writeString(config, "#\n" + - Files.readAllLines(Paths.get("gradle/licenseHeader.txt")) - .stream() - .map(str -> str.replaceAll("^", "# ")) - .map(str -> str.replace("${year}", LocalDate.now().getYear() + "")) - .collect(Collectors.joining("\n")) + "\n#\n"); - - Files.writeString(config, """ - # 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.boot%1$s.SpringBootProperties_%1$s_%2$s - displayName: Migrate Spring Boot properties to %1$s.%2$s - description: Migrate properties found in `application.properties` and `application.yml`. - tags: - - spring - - boot - recipeList:""".formatted(majorMinor[0], majorMinor[1]), - StandardOpenOption.APPEND); - - Files.writeString(config, replacements.stream() - .map(r -> """ - - org.openrewrite.java.spring.ChangeSpringPropertyKey: - oldPropertyKey: %s - newPropertyKey: %s - """.formatted( - r.name(), requireNonNull(r.deprecation()).replacement()) - ) - .collect(joining("", "\n", "\n")), - StandardOpenOption.APPEND); + List deprecations = getDeprecations(scanResult, alreadyDefined); + if (deprecations.isEmpty()) { + continue; } + var majorMinor = version.split("\\."); + if (semanticVersion.compareTo(new Version("3.1")) < 0) { + // Don't override manual fixes to the unsupported 2.x and 3.0 versions anymore + continue; + } + var recipePath = Paths.get("src/main/resources/META-INF/rewrite/spring-boot-%s%s-properties.yml".formatted(majorMinor[0], majorMinor[1])); + writeFileHeader(majorMinor, recipePath); + generateReplacementRecipes(deprecations, recipePath); + generateCommentRecipesForDeprecations(deprecations, recipePath); } } } + + private static @NotNull List getDeprecations(ScanResult scanResult, HashSet alreadyDefined) { + ResourceList resources = scanResult.getResourcesMatchingWildcard("**/*spring-configuration-metadata.json"); + return resources.stream() + .flatMap(res -> { + try (InputStream inputStream = res.open()) { + var metadata = objectMapper.readValue(inputStream, SpringConfigurationMetadata.class); + return metadata.properties().stream() + .filter(p -> p.deprecation() != null) + .filter(p -> alreadyDefined.add(getPropertyKey(p))); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }) + .toList(); + } + + private static void generateReplacementRecipes(List properties, Path recipePath) throws IOException { + var replacements = properties.stream() + .filter(d -> (d.deprecation() != null) && d.deprecation().replacement() != null) + .sorted(Comparator.comparing(SpringConfigurationMetadata.ConfigurationProperty::name)) + .toList(); + + if (!replacements.isEmpty()) { + Files.writeString(recipePath, replacements.stream() + .map(r -> """ + - org.openrewrite.java.spring.ChangeSpringPropertyKey: + oldPropertyKey: %s + newPropertyKey: %s + """.formatted( + r.name(), requireNonNull(r.deprecation()).replacement()) + ) + .collect(joining("", "\n", "\n")), + StandardOpenOption.APPEND); + } + } + + private static void generateCommentRecipesForDeprecations(List properties, Path recipePath) throws IOException { + var deprecationsWithoutReplacement = properties.stream() + .filter(d -> (d.deprecation() != null) && d.deprecation().replacement() == null) + .sorted(Comparator.comparing(SpringConfigurationMetadata.ConfigurationProperty::name)) + .toList(); + + if (!deprecationsWithoutReplacement.isEmpty()) { + Files.writeString(recipePath, """ + - org.openrewrite.java.spring.InlineCommentSpringProperties: + comment: "This property is deprecated and will be removed in future Spring Boot versions" + propertyKeys: + """, + StandardOpenOption.APPEND); + + Files.writeString(recipePath, deprecationsWithoutReplacement.stream() + .map(r -> """ + - %s + """.formatted( + r.name()) + ) + .collect(joining("", "", "\n")), + StandardOpenOption.APPEND); + } + } + + private static String getPropertyKey(SpringConfigurationMetadata.ConfigurationProperty property) { + String replacementSuffix = (property.deprecation() != null) && (property.deprecation().replacement() != null)? "->" + property.deprecation().replacement() : ""; + return property.name() + replacementSuffix; + } + + private static void writeFileHeader(String[] majorMinor, Path recipePath) throws IOException { + Files.writeString(recipePath, "#\n" + + Files.readAllLines(Paths.get("gradle/licenseHeader.txt")) + .stream() + .map(str -> str.replaceAll("^", "# ")) + .map(str -> str.replace("${year}", LocalDate.now().getYear() + "")) + .collect(Collectors.joining("\n")) + "\n#\n"); + + Files.writeString(recipePath, """ + # 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.boot%1$s.SpringBootProperties_%1$s_%2$s + displayName: Migrate Spring Boot properties to %1$s.%2$s + description: Migrate properties found in `application.properties` and `application.yml`. + tags: + - spring + - boot + recipeList:""".formatted(majorMinor[0], majorMinor[1]), + StandardOpenOption.APPEND); + } } record SpringConfigurationMetadata(List properties) {