From d2af2336594f6310026189bd4633598bd60e51d8 Mon Sep 17 00:00:00 2001 From: Ouwesh Seeroo Date: Mon, 3 Aug 2026 19:26:21 +0400 Subject: [PATCH 1/9] Migrate MockMvc Hamcrest assertions to AssertJ --- ...ateMockMvcHamcrestAssertionsToAssertJ.java | 101 ++++++++++ .../resources/META-INF/rewrite/recipes.csv | 9 +- .../META-INF/rewrite/spring-framework-62.yml | 1 + ...ockMvcHamcrestAssertionsToAssertJTest.java | 182 ++++++++++++++++++ 4 files changed, 289 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java create mode 100644 src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java diff --git a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java new file mode 100644 index 000000000..ce76677c6 --- /dev/null +++ b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java @@ -0,0 +1,101 @@ +/* + * Copyright 2026 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * 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 lombok.Getter; +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.MethodMatcher; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; + +import java.util.ArrayList; +import java.util.List; + +public class MigrateMockMvcHamcrestAssertionsToAssertJ extends Recipe { + private static final String MOCK_MVC_TESTER = "org.springframework.test.web.servlet.assertj.MockMvcTester"; + private static final String ASSERT_THAT = "org.assertj.core.api.Assertions.assertThat"; + + private static final MethodMatcher AND_EXPECT = new MethodMatcher( + "org.springframework.test.web.servlet.ResultActions andExpect(org.springframework.test.web.servlet.ResultMatcher)" + ); + private static final MethodMatcher PERFORM = new MethodMatcher( + "org.springframework.test.web.servlet.MockMvc perform(org.springframework.test.web.servlet.RequestBuilder)" + ); + + @Getter + final String displayName = "Migrate MockMvc Hamcrest assertions to AssertJ"; + + @Getter + final String description = "Wraps chained MockMvc `andExpect(..)` assertions in Spring Framework 6.2's AssertJ support while preserving the existing request builders and result matchers."; + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new UsesMethod<>(AND_EXPECT), new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (!AND_EXPECT.matches(mi) || isChainedAndExpect()) { + return mi; + } + + List matchers = new ArrayList<>(); + J.MethodInvocation current = mi; + while (AND_EXPECT.matches(current)) { + matchers.add(0, current.getArguments().get(0)); + if (!(current.getSelect() instanceof J.MethodInvocation)) { + return mi; + } + current = (J.MethodInvocation) current.getSelect(); + } + + if (!PERFORM.matches(current) || current.getSelect() == null || current.getArguments().size() != 1) { + return mi; + } + + StringBuilder template = new StringBuilder("assertThat(MockMvcTester.create(#{any()}).perform(#{any()}))"); + for (int i = 0; i < matchers.size(); i++) { + template.append(".matches(#{any()})"); + } + + List parameters = new ArrayList<>(); + parameters.add(current.getSelect()); + parameters.add(current.getArguments().get(0)); + parameters.addAll(matchers); + + return JavaTemplate.builder(template.toString()) + .imports(MOCK_MVC_TESTER) + .staticImports(ASSERT_THAT) + .build() + .apply(getCursor(), mi.getCoordinates().replace(), parameters.toArray()); + } + + private boolean isChainedAndExpect() { + Object parent = getCursor().getParentOrThrow().getValue(); + if (!(parent instanceof J.MethodInvocation)) { + return false; + } + J.MethodInvocation parentInvocation = (J.MethodInvocation) parent; + return AND_EXPECT.matches(parentInvocation) && parentInvocation.getSelect() instanceof J.MethodInvocation; + } + }); + } +} diff --git a/src/main/resources/META-INF/rewrite/recipes.csv b/src/main/resources/META-INF/rewrite/recipes.csv index fe67042e8..598142f0c 100644 --- a/src/main/resources/META-INF/rewrite/recipes.csv +++ b/src/main/resources/META-INF/rewrite/recipes.csv @@ -116,7 +116,7 @@ maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.boot2.Up maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.boot2.search.CustomizingJooqDefaultConfiguration,In Spring Boot 2.5 a `DefaultConfigurationCustomizer` can now be used in favour of defining one or more `*Provider` beans,"To streamline the customization of jOOQ’s `DefaultConfiguration`, a bean that implements `DefaultConfigurationCustomizer` can now be defined. This customizer callback should be used in favour of defining one or more `*Provider` beans, the support for which has now been deprecated. See [Spring Boot 2.5 jOOQ customization](https://docs.spring.io/spring-boot/docs/2.5.x/reference/htmlsingle/#features.sql.jooq.customizing).",1,,,Search,Spring Boot 2.x,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.boot2.search.FindUpgradeRequirementsSpringBoot_2_5,Find patterns that require updating for Spring Boot 2.5,Looks for a series of patterns that have not yet had auto-remediation recipes developed for.,6,,,Search,Spring Boot 2.x,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,,"[{""name"":""org.openrewrite.maven.table.DependenciesDeclared"",""displayName"":""Dependencies declared"",""instanceName"":""Dependencies declared"",""description"":""Direct (first-order) dependencies declared by the project."",""columns"":[{""name"":""projectName"",""type"":""String"",""displayName"":""Project name"",""description"":""The name of the project that contains the dependency.""},{""name"":""sourceSet"",""type"":""String"",""displayName"":""Source set"",""description"":""The source set that contains the dependency.""},{""name"":""groupId"",""type"":""String"",""displayName"":""Group"",""description"":""The first part of a dependency coordinate `com.google.guava:guava:VERSION`.""},{""name"":""artifactId"",""type"":""String"",""displayName"":""Artifact"",""description"":""The second part of a dependency coordinate `com.google.guava:guava:VERSION`.""},{""name"":""version"",""type"":""String"",""displayName"":""Version"",""description"":""The resolved version.""},{""name"":""datedSnapshotVersion"",""type"":""String"",""displayName"":""Dated snapshot version"",""description"":""The resolved dated snapshot version or `null` if this dependency is not a snapshot.""},{""name"":""scope"",""type"":""String"",""displayName"":""Scope"",""description"":""Maven scope (e.g. `compile`, `test`) or Gradle configuration name (e.g. `implementation`, `testImplementation`). For Maven, defaults to `compile` when no scope is declared.""}]}]" maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.boot2.search.IntegrationSchedulerPoolRecipe,Integration scheduler pool size,"Spring Integration now reuses an available `TaskScheduler` rather than configuring its own. In a typical application setup relying on the auto-configuration, this means that Spring Integration uses the auto-configured task scheduler that has a pool size of 1. To restore Spring Integration’s default of 10 threads, use the `spring.task.scheduling.pool.size` property.",1,,,Search,Spring Boot 2.x,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, -maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.boot2.search.LoggingShutdownHooks,Applications using logging shutdown hooks,"Spring Boot registers a logging shutdown hook by default for JAR-based applications to ensure that logging resources are released when the JVM exits. If your application is deployed as a WAR then the shutdown hook is not registered since the servlet container usually handles logging concerns. +maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.boot2.search.LoggingShutdownHooks,Applications using logging shutdown hooks,"Spring Boot registers a logging shutdown hook by default for JAR-based applications to ensure that logging resources are released when the JVM exits. If your application is deployed as a WAR then the shutdown hook is not registered since the servlet container usually handles logging concerns. Most applications will want the shutdown hook. However, if your application has complex context hierarchies, then you may need to disable it. You can use the `logging.register-shutdown-hook` property to do that.",1,,,Search,Spring Boot 2.x,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.boot2.search.MessagesInTheDefaultErrorView,Find projects affected by changes to the default error view message attribute,"As of Spring Boot 2.5 the `message` attribute in the default error view was removed rather than blanked when it is not shown. @@ -245,6 +245,7 @@ maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framewor maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.MigrateHandlerResultSetExceptionHandlerMethod,Migrate `org.springframework.web.reactive.HandlerResult.setExceptionHandler` method,"`org.springframework.web.reactive.HandlerResult.setExceptionHandler(Function>)` was deprecated, in favor of `setExceptionHandler(DispatchExceptionHandler)`.",1,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.MigrateInstantiationAwareBeanPostProcessorAdapter,Convert `InstantiationAwareBeanPostProcessorAdapter` to `SmartInstantiationAwareBeanPostProcessor`,As of Spring-Framework 5.3 `InstantiationAwareBeanPostProcessorAdapter` is deprecated in favor of the existing default methods in `SmartInstantiationAwareBeanPostProcessor`.,1,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.MigrateMethodArgumentNotValidExceptionErrorMethod,Migrate `MethodArgumentNotValidException.errorsToStringList` and `resolveErrorMessages`,"`org.springframework.web.bind.MethodArgumentNotValidException.errorsToStringList` and `resolveErrorMessages` method was deprecated, in favor of `BindErrorUtils`.",1,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, +maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.MigrateMockMvcHamcrestAssertionsToAssertJ,Migrate MockMvc Hamcrest assertions to AssertJ,Wraps chained MockMvc `andExpect(..)` assertions in Spring Framework 6.2's AssertJ support while preserving the existing request builders and result matchers.,1,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.MigrateResourceHttpMessageWriterAddHeadersMethod,Migrate `ResourceHttpMessageWriter.addHeaders`,"`org.springframework.http.codec.ResourceHttpMessageWriter.addHeaders` was deprecated, in favor of `addDefaultHeaders` method.",1,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.MigrateResponseEntityExceptionHandlerHttpStatusToHttpStatusCode,Migrate `ResponseEntityExceptionHandler` from HttpStatus to HttpStatusCode,With Spring 6 `HttpStatus` was replaced by `HttpStatusCode` in most method signatures in the `ResponseEntityExceptionHandler`.,1,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.MigrateResponseStatusException,Migrate breaking changes in `ResponseStatusException`,Migrate Spring Framework 5.3's `ResponseStatusException` method `getRawStatusCode()` to Spring Framework 6's `getStatusCode().value()` and `ResponseStatusException` method `getStatus()` to Spring Framework 6's `getStatusCode()` .,3,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, @@ -260,9 +261,9 @@ maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framewor maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.UpgradeSpringFramework_5_2,Migrate to Spring Framework 5.2,Migrate applications to the latest Spring Framework 5.2 release.,19,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.UpgradeSpringFramework_5_3,Migrate to Spring Framework 5.3,Migrate applications to the latest Spring Framework 5.3 release.,30,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_0,Migrate to Spring Framework 6.0,Migrate applications to the latest Spring Framework 6.0 release.,948,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,,"[{""name"":""org.openrewrite.maven.table.MavenMetadataFailures"",""displayName"":""Maven metadata failures"",""instanceName"":""Maven metadata failures"",""description"":""Attempts to resolve maven metadata that failed."",""columns"":[{""name"":""group"",""type"":""String"",""displayName"":""Group id"",""description"":""The groupId of the artifact for which the metadata download failed.""},{""name"":""artifactId"",""type"":""String"",""displayName"":""Artifact id"",""description"":""The artifactId of the artifact for which the metadata download failed.""},{""name"":""version"",""type"":""String"",""displayName"":""Version"",""description"":""The version of the artifact for which the metadata download failed.""},{""name"":""mavenRepositoryUri"",""type"":""String"",""displayName"":""Maven repository"",""description"":""The URL of the Maven repository that the metadata download failed on.""},{""name"":""snapshots"",""type"":""String"",""displayName"":""Snapshots"",""description"":""Does the repository support snapshots.""},{""name"":""releases"",""type"":""String"",""displayName"":""Releases"",""description"":""Does the repository support releases.""},{""name"":""failure"",""type"":""String"",""displayName"":""Failure"",""description"":""The reason the metadata download failed.""}]}]" -maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_1,Migrate to Spring Framework 6.1,Migrate applications to the latest Spring Framework 6.1 release.,953,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,,"[{""name"":""org.openrewrite.maven.table.MavenMetadataFailures"",""displayName"":""Maven metadata failures"",""instanceName"":""Maven metadata failures"",""description"":""Attempts to resolve maven metadata that failed."",""columns"":[{""name"":""group"",""type"":""String"",""displayName"":""Group id"",""description"":""The groupId of the artifact for which the metadata download failed.""},{""name"":""artifactId"",""type"":""String"",""displayName"":""Artifact id"",""description"":""The artifactId of the artifact for which the metadata download failed.""},{""name"":""version"",""type"":""String"",""displayName"":""Version"",""description"":""The version of the artifact for which the metadata download failed.""},{""name"":""mavenRepositoryUri"",""type"":""String"",""displayName"":""Maven repository"",""description"":""The URL of the Maven repository that the metadata download failed on.""},{""name"":""snapshots"",""type"":""String"",""displayName"":""Snapshots"",""description"":""Does the repository support snapshots.""},{""name"":""releases"",""type"":""String"",""displayName"":""Releases"",""description"":""Does the repository support releases.""},{""name"":""failure"",""type"":""String"",""displayName"":""Failure"",""description"":""The reason the metadata download failed.""}]}]" -maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_2,Migrate to Spring Framework 6.2,Migrate applications to the latest Spring Framework 6.2 release.,970,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,,"[{""name"":""org.openrewrite.maven.table.MavenMetadataFailures"",""displayName"":""Maven metadata failures"",""instanceName"":""Maven metadata failures"",""description"":""Attempts to resolve maven metadata that failed."",""columns"":[{""name"":""group"",""type"":""String"",""displayName"":""Group id"",""description"":""The groupId of the artifact for which the metadata download failed.""},{""name"":""artifactId"",""type"":""String"",""displayName"":""Artifact id"",""description"":""The artifactId of the artifact for which the metadata download failed.""},{""name"":""version"",""type"":""String"",""displayName"":""Version"",""description"":""The version of the artifact for which the metadata download failed.""},{""name"":""mavenRepositoryUri"",""type"":""String"",""displayName"":""Maven repository"",""description"":""The URL of the Maven repository that the metadata download failed on.""},{""name"":""snapshots"",""type"":""String"",""displayName"":""Snapshots"",""description"":""Does the repository support snapshots.""},{""name"":""releases"",""type"":""String"",""displayName"":""Releases"",""description"":""Does the repository support releases.""},{""name"":""failure"",""type"":""String"",""displayName"":""Failure"",""description"":""The reason the metadata download failed.""}]}]" -maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.UpgradeSpringFramework_7_0,Migrate to Spring Framework 7.0,Migrate applications to the latest Spring Framework 7.0 release.,1325,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,,"[{""name"":""org.openrewrite.maven.table.MavenMetadataFailures"",""displayName"":""Maven metadata failures"",""instanceName"":""Maven metadata failures"",""description"":""Attempts to resolve maven metadata that failed."",""columns"":[{""name"":""group"",""type"":""String"",""displayName"":""Group id"",""description"":""The groupId of the artifact for which the metadata download failed.""},{""name"":""artifactId"",""type"":""String"",""displayName"":""Artifact id"",""description"":""The artifactId of the artifact for which the metadata download failed.""},{""name"":""version"",""type"":""String"",""displayName"":""Version"",""description"":""The version of the artifact for which the metadata download failed.""},{""name"":""mavenRepositoryUri"",""type"":""String"",""displayName"":""Maven repository"",""description"":""The URL of the Maven repository that the metadata download failed on.""},{""name"":""snapshots"",""type"":""String"",""displayName"":""Snapshots"",""description"":""Does the repository support snapshots.""},{""name"":""releases"",""type"":""String"",""displayName"":""Releases"",""description"":""Does the repository support releases.""},{""name"":""failure"",""type"":""String"",""displayName"":""Failure"",""description"":""The reason the metadata download failed.""}]}]" +maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_1,Migrate to Spring Framework 6.1,Migrate applications to the latest Spring Framework 6.1 release.,951,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,,"[{""name"":""org.openrewrite.maven.table.MavenMetadataFailures"",""displayName"":""Maven metadata failures"",""instanceName"":""Maven metadata failures"",""description"":""Attempts to resolve maven metadata that failed."",""columns"":[{""name"":""group"",""type"":""String"",""displayName"":""Group id"",""description"":""The groupId of the artifact for which the metadata download failed.""},{""name"":""artifactId"",""type"":""String"",""displayName"":""Artifact id"",""description"":""The artifactId of the artifact for which the metadata download failed.""},{""name"":""version"",""type"":""String"",""displayName"":""Version"",""description"":""The version of the artifact for which the metadata download failed.""},{""name"":""mavenRepositoryUri"",""type"":""String"",""displayName"":""Maven repository"",""description"":""The URL of the Maven repository that the metadata download failed on.""},{""name"":""snapshots"",""type"":""String"",""displayName"":""Snapshots"",""description"":""Does the repository support snapshots.""},{""name"":""releases"",""type"":""String"",""displayName"":""Releases"",""description"":""Does the repository support releases.""},{""name"":""failure"",""type"":""String"",""displayName"":""Failure"",""description"":""The reason the metadata download failed.""}]}]" +maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_2,Migrate to Spring Framework 6.2,Migrate applications to the latest Spring Framework 6.2 release.,969,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,,"[{""name"":""org.openrewrite.maven.table.MavenMetadataFailures"",""displayName"":""Maven metadata failures"",""instanceName"":""Maven metadata failures"",""description"":""Attempts to resolve maven metadata that failed."",""columns"":[{""name"":""group"",""type"":""String"",""displayName"":""Group id"",""description"":""The groupId of the artifact for which the metadata download failed.""},{""name"":""artifactId"",""type"":""String"",""displayName"":""Artifact id"",""description"":""The artifactId of the artifact for which the metadata download failed.""},{""name"":""version"",""type"":""String"",""displayName"":""Version"",""description"":""The version of the artifact for which the metadata download failed.""},{""name"":""mavenRepositoryUri"",""type"":""String"",""displayName"":""Maven repository"",""description"":""The URL of the Maven repository that the metadata download failed on.""},{""name"":""snapshots"",""type"":""String"",""displayName"":""Snapshots"",""description"":""Does the repository support snapshots.""},{""name"":""releases"",""type"":""String"",""displayName"":""Releases"",""description"":""Does the repository support releases.""},{""name"":""failure"",""type"":""String"",""displayName"":""Failure"",""description"":""The reason the metadata download failed.""}]}]" +maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.UpgradeSpringFramework_7_0,Migrate to Spring Framework 7.0,Migrate applications to the latest Spring Framework 7.0 release.,1323,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,,"[{""name"":""org.openrewrite.maven.table.MavenMetadataFailures"",""displayName"":""Maven metadata failures"",""instanceName"":""Maven metadata failures"",""description"":""Attempts to resolve maven metadata that failed."",""columns"":[{""name"":""group"",""type"":""String"",""displayName"":""Group id"",""description"":""The groupId of the artifact for which the metadata download failed.""},{""name"":""artifactId"",""type"":""String"",""displayName"":""Artifact id"",""description"":""The artifactId of the artifact for which the metadata download failed.""},{""name"":""version"",""type"":""String"",""displayName"":""Version"",""description"":""The version of the artifact for which the metadata download failed.""},{""name"":""mavenRepositoryUri"",""type"":""String"",""displayName"":""Maven repository"",""description"":""The URL of the Maven repository that the metadata download failed on.""},{""name"":""snapshots"",""type"":""String"",""displayName"":""Snapshots"",""description"":""Does the repository support snapshots.""},{""name"":""releases"",""type"":""String"",""displayName"":""Releases"",""description"":""Does the repository support releases.""},{""name"":""failure"",""type"":""String"",""displayName"":""Failure"",""description"":""The reason the metadata download failed.""}]}]" maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.framework.UseObjectUtilsIsEmpty,Use `ObjectUtils#isEmpty(Object)`,`StringUtils#isEmpty(Object)` was deprecated in 5.3.,1,,,,Spring Framework,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.http.ReplaceStringLiteralsWithHttpHeadersConstants,Replace String literals with `HttpHeaders` constants,Replace String literals with `org.springframework.http.HttpHeaders` constants.,62,,,,Http,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, maven,org.openrewrite.recipe:rewrite-spring,org.openrewrite.java.spring.http.ReplaceStringLiteralsWithMediaTypeConstants,Replace String literals with `MediaType` constants,Replace String literals with `org.springframework.http.MediaType` constants.,32,,,,Http,Spring,Java,,,,,Recipes for upgrading and patching [Spring](https://spring.io/) applications.,Basic building blocks for transforming Java code.,, diff --git a/src/main/resources/META-INF/rewrite/spring-framework-62.yml b/src/main/resources/META-INF/rewrite/spring-framework-62.yml index 19af951fb..8f9563a7a 100644 --- a/src/main/resources/META-INF/rewrite/spring-framework-62.yml +++ b/src/main/resources/META-INF/rewrite/spring-framework-62.yml @@ -37,6 +37,7 @@ recipeList: - org.openrewrite.java.spring.framework.MigrateUriComponentsBuilderMethods - org.openrewrite.java.spring.framework.MigrateWebExchangeBindExceptionResolveErrorMethod - org.openrewrite.java.spring.framework.HttpComponentsClientHttpRequestFactoryConnectTimeout + - org.openrewrite.java.spring.framework.MigrateMockMvcHamcrestAssertionsToAssertJ - org.openrewrite.java.ReplaceConstantWithAnotherConstant: existingFullyQualifiedConstantName: org.springframework.http.client.observation.ClientHttpObservationDocumentation.HighCardinalityKeyNames.CLIENT_NAME diff --git a/src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java b/src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java new file mode 100644 index 000000000..8d8733de8 --- /dev/null +++ b/src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java @@ -0,0 +1,182 @@ +/* + * Copyright 2026 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * 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.DocumentExample; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class MigrateMockMvcHamcrestAssertionsToAssertJTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new MigrateMockMvcHamcrestAssertionsToAssertJ()) + .parser(JavaParser.fromJavaVersion().dependsOn( + """ + package org.springframework.test.web.servlet; + public class MockMvc { + public ResultActions perform(RequestBuilder requestBuilder) { + return null; + } + } + """, + """ + package org.springframework.test.web.servlet; + public interface RequestBuilder { + } + """, + """ + package org.springframework.test.web.servlet; + public interface ResultMatcher { + } + """, + """ + package org.springframework.test.web.servlet; + public interface ResultActions { + ResultActions andExpect(ResultMatcher matcher); + ResultActions andExpectAll(ResultMatcher... matchers); + } + """, + """ + package org.springframework.test.web.servlet.request; + import org.springframework.test.web.servlet.RequestBuilder; + public final class MockMvcRequestBuilders { + public static RequestBuilder get(String uri, Object... uriVariables) { + return null; + } + } + """, + """ + package org.springframework.test.web.servlet.result; + import org.springframework.test.web.servlet.ResultMatcher; + public final class MockMvcResultMatchers { + public static StatusResultMatchers status() { + return null; + } + public static final class StatusResultMatchers { + public ResultMatcher isOk() { + return null; + } + } + } + """, + """ + package org.springframework.test.web.servlet.assertj; + import org.springframework.test.web.servlet.MockMvc; + import org.springframework.test.web.servlet.RequestBuilder; + public final class MockMvcTester { + public static MockMvcTester create(MockMvc mockMvc) { + return null; + } + public MvcTestResult perform(RequestBuilder requestBuilder) { + return null; + } + } + """, + """ + package org.springframework.test.web.servlet.assertj; + import org.springframework.test.web.servlet.ResultMatcher; + public class MvcTestResult { + } + """, + """ + package org.springframework.test.web.servlet.assertj; + import org.springframework.test.web.servlet.ResultMatcher; + public class MvcTestResultAssert { + public MvcTestResultAssert matches(ResultMatcher matcher) { + return this; + } + } + """, + """ + package org.assertj.core.api; + import org.springframework.test.web.servlet.assertj.MvcTestResult; + import org.springframework.test.web.servlet.assertj.MvcTestResultAssert; + public final class Assertions { + public static MvcTestResultAssert assertThat(MvcTestResult result) { + return null; + } + } + """ + )); + } + + @DocumentExample + @Test + void migratesChainedAssertions() { + rewriteRun( + //language=java + java( + """ + import org.springframework.test.web.servlet.MockMvc; + + import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; + import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + class Example { + void test(MockMvc mockMvc) { + mockMvc.perform(get("/accounts/{id}", 1)) + .andExpect(status().isOk()) + .andExpect(status().isOk()); + } + } + """, + """ + import org.springframework.test.web.servlet.MockMvc; + import org.springframework.test.web.servlet.assertj.MockMvcTester; + + import static org.assertj.core.api.Assertions.assertThat; + import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; + import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + class Example { + void test(MockMvc mockMvc) { + assertThat(MockMvcTester.create(mockMvc).perform(get("/accounts/{id}", 1))) + .matches(status().isOk()) + .matches(status().isOk()); + } + } + """ + ) + ); + } + + @Test + void doesNotMigrateAndExpectAll() { + rewriteRun( + //language=java + java( + """ + import org.springframework.test.web.servlet.MockMvc; + + import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; + import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + class Example { + void test(MockMvc mockMvc) { + mockMvc.perform(get("/accounts/{id}", 1)) + .andExpectAll(status().isOk(), status().isOk()); + } + } + """ + ) + ); + } +} From 2ea51a73fc07b635ad222c77772f6b9ef1d94f61 Mon Sep 17 00:00:00 2001 From: Ouwesh Seeroo Date: Fri, 7 Aug 2026 14:05:12 +0400 Subject: [PATCH 2/9] Fix MockMvc AssertJ assertion migration --- ...ateMockMvcHamcrestAssertionsToAssertJ.java | 10 +++++--- ...ockMvcHamcrestAssertionsToAssertJTest.java | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java index ce76677c6..8036fa366 100644 --- a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java +++ b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java @@ -53,13 +53,13 @@ public TreeVisitor getVisitor() { @Override public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); - if (!AND_EXPECT.matches(mi) || isChainedAndExpect()) { + if (!isAndExpect(mi) || isChainedAndExpect()) { return mi; } List matchers = new ArrayList<>(); J.MethodInvocation current = mi; - while (AND_EXPECT.matches(current)) { + while (isAndExpect(current)) { matchers.add(0, current.getArguments().get(0)); if (!(current.getSelect() instanceof J.MethodInvocation)) { return mi; @@ -94,7 +94,11 @@ private boolean isChainedAndExpect() { return false; } J.MethodInvocation parentInvocation = (J.MethodInvocation) parent; - return AND_EXPECT.matches(parentInvocation) && parentInvocation.getSelect() instanceof J.MethodInvocation; + return isAndExpect(parentInvocation) && parentInvocation.getSelect() instanceof J.MethodInvocation; + } + + private boolean isAndExpect(J.MethodInvocation methodInvocation) { + return "andExpect".equals(methodInvocation.getSimpleName()) && AND_EXPECT.matches(methodInvocation); } }); } diff --git a/src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java b/src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java index 8d8733de8..64cfddf56 100644 --- a/src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java +++ b/src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java @@ -158,6 +158,31 @@ void test(MockMvc mockMvc) { ); } + @Test + void doesNotMigrateAssertJMatches() { + rewriteRun( + //language=java + java( + """ + import org.springframework.test.web.servlet.MockMvc; + import org.springframework.test.web.servlet.assertj.MockMvcTester; + + import static org.assertj.core.api.Assertions.assertThat; + import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; + import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + class Example { + void test(MockMvc mockMvc) { + assertThat(MockMvcTester.create(mockMvc).perform(get("/accounts/{id}", 1))) + .matches(status().isOk()) + .matches(status().isOk()); + } + } + """ + ) + ); + } + @Test void doesNotMigrateAndExpectAll() { rewriteRun( From b601a457d4e6e6d2adb682dfeb9a2d2e9a3db127 Mon Sep 17 00:00:00 2001 From: Ouwesh Seeroo Date: Fri, 7 Aug 2026 14:41:28 +0400 Subject: [PATCH 3/9] Fix chained MockMvc assertion traversal --- .../framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java index 8036fa366..dc936d7e6 100644 --- a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java +++ b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java @@ -52,8 +52,9 @@ public TreeVisitor getVisitor() { return Preconditions.check(new UsesMethod<>(AND_EXPECT), new JavaIsoVisitor() { @Override public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + boolean isChainedAndExpect = isChainedAndExpect(); J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); - if (!isAndExpect(mi) || isChainedAndExpect()) { + if (!isAndExpect(mi) || isChainedAndExpect) { return mi; } From e71033cf817a9ab97b08df8867f0b745dfa5b509 Mon Sep 17 00:00:00 2001 From: Ouwesh Seeroo Date: Fri, 7 Aug 2026 15:31:48 +0400 Subject: [PATCH 4/9] Fix MockMvc assertion chain detection --- ...igrateMockMvcHamcrestAssertionsToAssertJ.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java index dc936d7e6..ca741c4ca 100644 --- a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java +++ b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java @@ -16,6 +16,7 @@ package org.openrewrite.java.spring.framework; import lombok.Getter; +import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; import org.openrewrite.Preconditions; import org.openrewrite.Recipe; @@ -52,7 +53,7 @@ public TreeVisitor getVisitor() { return Preconditions.check(new UsesMethod<>(AND_EXPECT), new JavaIsoVisitor() { @Override public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - boolean isChainedAndExpect = isChainedAndExpect(); + boolean isChainedAndExpect = isChainedAndExpect(method); J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); if (!isAndExpect(mi) || isChainedAndExpect) { return mi; @@ -89,13 +90,14 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu .apply(getCursor(), mi.getCoordinates().replace(), parameters.toArray()); } - private boolean isChainedAndExpect() { - Object parent = getCursor().getParentOrThrow().getValue(); - if (!(parent instanceof J.MethodInvocation)) { - return false; + private boolean isChainedAndExpect(J.MethodInvocation methodInvocation) { + for (Cursor cursor = getCursor().getParent(); cursor != null; cursor = cursor.getParent()) { + if (cursor.getValue() instanceof J.MethodInvocation) { + J.MethodInvocation parentInvocation = (J.MethodInvocation) cursor.getValue(); + return parentInvocation.getSelect() == methodInvocation && isAndExpect(parentInvocation); + } } - J.MethodInvocation parentInvocation = (J.MethodInvocation) parent; - return isAndExpect(parentInvocation) && parentInvocation.getSelect() instanceof J.MethodInvocation; + return false; } private boolean isAndExpect(J.MethodInvocation methodInvocation) { From 842169a0249cc9d4cad7eba4c8e4c48857ba6554 Mon Sep 17 00:00:00 2001 From: Ouwesh Seeroo Date: Fri, 7 Aug 2026 15:44:42 +0400 Subject: [PATCH 5/9] Format migrated MockMvc assertions --- .../framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java index ca741c4ca..3878e0be3 100644 --- a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java +++ b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java @@ -83,11 +83,14 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu parameters.add(current.getArguments().get(0)); parameters.addAll(matchers); - return JavaTemplate.builder(template.toString()) + maybeAddImport(MOCK_MVC_TESTER, false); + maybeAddImport(ASSERT_THAT, "assertThat", false); + J.MethodInvocation replacement = JavaTemplate.builder(template.toString()) .imports(MOCK_MVC_TESTER) .staticImports(ASSERT_THAT) .build() .apply(getCursor(), mi.getCoordinates().replace(), parameters.toArray()); + return autoFormat(replacement, ctx); } private boolean isChainedAndExpect(J.MethodInvocation methodInvocation) { From aecb5d70060666c64939efaf01c8418c50484582 Mon Sep 17 00:00:00 2001 From: Ouwesh Seeroo Date: Fri, 7 Aug 2026 16:01:17 +0400 Subject: [PATCH 6/9] Fix MockMvc assertion static import --- .../MigrateMockMvcHamcrestAssertionsToAssertJ.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java index 3878e0be3..3ecbd6e28 100644 --- a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java +++ b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java @@ -33,7 +33,8 @@ public class MigrateMockMvcHamcrestAssertionsToAssertJ extends Recipe { private static final String MOCK_MVC_TESTER = "org.springframework.test.web.servlet.assertj.MockMvcTester"; - private static final String ASSERT_THAT = "org.assertj.core.api.Assertions.assertThat"; + private static final String ASSERTIONS = "org.assertj.core.api.Assertions"; + private static final String ASSERT_THAT = ASSERTIONS + ".assertThat"; private static final MethodMatcher AND_EXPECT = new MethodMatcher( "org.springframework.test.web.servlet.ResultActions andExpect(org.springframework.test.web.servlet.ResultMatcher)" @@ -75,7 +76,7 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu StringBuilder template = new StringBuilder("assertThat(MockMvcTester.create(#{any()}).perform(#{any()}))"); for (int i = 0; i < matchers.size(); i++) { - template.append(".matches(#{any()})"); + template.append("\n .matches(#{any()})"); } List parameters = new ArrayList<>(); @@ -84,13 +85,13 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu parameters.addAll(matchers); maybeAddImport(MOCK_MVC_TESTER, false); - maybeAddImport(ASSERT_THAT, "assertThat", false); + maybeAddImport(ASSERTIONS, "assertThat", false); J.MethodInvocation replacement = JavaTemplate.builder(template.toString()) .imports(MOCK_MVC_TESTER) .staticImports(ASSERT_THAT) .build() .apply(getCursor(), mi.getCoordinates().replace(), parameters.toArray()); - return autoFormat(replacement, ctx); + return replacement; } private boolean isChainedAndExpect(J.MethodInvocation methodInvocation) { From 1d87ff1f4f4f1535e0898d9969dc1b6a7669664d Mon Sep 17 00:00:00 2001 From: Ouwesh Seeroo Date: Fri, 7 Aug 2026 16:22:06 +0400 Subject: [PATCH 7/9] Fix MockMvc assertion indentation --- .../framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java index 3ecbd6e28..5b7ebf892 100644 --- a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java +++ b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java @@ -76,7 +76,7 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu StringBuilder template = new StringBuilder("assertThat(MockMvcTester.create(#{any()}).perform(#{any()}))"); for (int i = 0; i < matchers.size(); i++) { - template.append("\n .matches(#{any()})"); + template.append("\n.matches(#{any()})"); } List parameters = new ArrayList<>(); From 988d9d86679e0c12427942a615c2bb9ebb539522 Mon Sep 17 00:00:00 2001 From: Ouwesh Seeroo Date: Fri, 7 Aug 2026 16:33:52 +0400 Subject: [PATCH 8/9] Align MockMvc assertion test formatting --- .../MigrateMockMvcHamcrestAssertionsToAssertJTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java b/src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java index 64cfddf56..200e84f4c 100644 --- a/src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java +++ b/src/test/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJTest.java @@ -149,8 +149,8 @@ void test(MockMvc mockMvc) { class Example { void test(MockMvc mockMvc) { assertThat(MockMvcTester.create(mockMvc).perform(get("/accounts/{id}", 1))) - .matches(status().isOk()) - .matches(status().isOk()); + .matches(status().isOk()) + .matches(status().isOk()); } } """ From e8ce84a445395b247afdfc11327afd12d309b025 Mon Sep 17 00:00:00 2001 From: Ouwesh Seeroo Date: Fri, 7 Aug 2026 16:58:16 +0400 Subject: [PATCH 9/9] Add type attribution to MockMvc assertion template --- .../framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java index 5b7ebf892..6d0ed1c63 100644 --- a/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java +++ b/src/main/java/org/openrewrite/java/spring/framework/MigrateMockMvcHamcrestAssertionsToAssertJ.java @@ -22,6 +22,7 @@ import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; 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.UsesMethod; @@ -87,6 +88,8 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu maybeAddImport(MOCK_MVC_TESTER, false); maybeAddImport(ASSERTIONS, "assertThat", false); J.MethodInvocation replacement = JavaTemplate.builder(template.toString()) + .javaParser(JavaParser.fromJavaVersion() + .classpathFromResources(ctx, "spring-test-6.+", "assertj-core")) .imports(MOCK_MVC_TESTER) .staticImports(ASSERT_THAT) .build()