diff --git a/build.gradle.kts b/build.gradle.kts
index cd2eaeaaa..17ed75da5 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -48,6 +48,7 @@ configurations {
}
recipeDependencies {
+
parserClasspath("javax.persistence:javax.persistence-api:2.+")
parserClasspath("javax.validation:validation-api:2.0.1.Final")
parserClasspath("org.junit.jupiter:junit-jupiter-api:latest.release")
@@ -83,6 +84,7 @@ recipeDependencies {
parserClasspath("org.springframework:spring-webmvc:5.+")
parserClasspath("org.springframework.data:spring-data-commons:2.+")
+ parserClasspath("org.springframework.data:spring-data-commons:1.+")
parserClasspath("org.springframework.data:spring-data-jpa:2.+")
parserClasspath("org.springframework.data:spring-data-jpa:2.3.+")
diff --git a/src/main/java/org/openrewrite/java/spring/data/MigrateAuditorAwareToOptional.java b/src/main/java/org/openrewrite/java/spring/data/MigrateAuditorAwareToOptional.java
new file mode 100644
index 000000000..fad42dee7
--- /dev/null
+++ b/src/main/java/org/openrewrite/java/spring/data/MigrateAuditorAwareToOptional.java
@@ -0,0 +1,159 @@
+/*
+ * 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.data;
+
+import lombok.RequiredArgsConstructor;
+import org.jspecify.annotations.Nullable;
+import org.openrewrite.*;
+import org.openrewrite.java.*;
+import org.openrewrite.java.search.UsesType;
+import org.openrewrite.java.spring.util.MemberReferenceToMethodInvocation;
+import org.openrewrite.java.tree.*;
+
+public class MigrateAuditorAwareToOptional extends Recipe {
+
+ private static final TypeMatcher isAuditorAware = new TypeMatcher("org.springframework.data.domain.AuditorAware", true);
+ private static final MethodMatcher isCurrentAuditor = new MethodMatcher("org.springframework.data.domain.AuditorAware getCurrentAuditor()", true);
+ private static final TypeMatcher isOptional = new TypeMatcher("java.util.Optional");
+
+ @Override
+ public String getDisplayName() {
+ return "Make AuditorAware.getCurrentAuditor return `Optional`";
+ }
+
+ @Override
+ public String getDescription() {
+ return "As of Spring boot 2.0, the `AuditorAware.getCurrentAuditor` method should return an `Optional`. " +
+ "This recipe will update the implementations of this method to return an `Optional` using the `ofNullable`.";
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ ImplementationVisitor implementationVisitor = new ImplementationVisitor();
+ FunctionalVisitor functionalVisitor = new FunctionalVisitor(implementationVisitor);
+ return Preconditions.check(new UsesType<>("org.springframework.data.domain.AuditorAware", true), new JavaIsoVisitor() {
+ @Override
+ public @Nullable J visit(@Nullable Tree tree, ExecutionContext ctx) {
+ tree = implementationVisitor.visit(tree, ctx);
+ tree = functionalVisitor.visit(tree, ctx);
+ return (J) tree;
+ }
+ });
+ }
+
+ private static class ImplementationVisitor extends JavaIsoVisitor {
+ @Override
+ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
+ TypeTree returnType = method.getReturnTypeExpression();
+ if (method.getMethodType() == null || !isCurrentAuditor.matches(method.getMethodType()) ||
+ returnType == null || returnType.getType().toString().matches("java.util.Optional<.*>")) {
+ return method;
+ }
+ Space space = returnType.getPrefix();
+ returnType = TypeTree.build("java.util.Optional<" + returnType.getType() + ">");
+ J.MethodDeclaration md = super.visitMethodDeclaration(method, ctx).withReturnTypeExpression(returnType.withPrefix(space));
+ doAfterVisit(ShortenFullyQualifiedTypeReferences.modifyOnly(md));
+ maybeAddImport("java.util.Optional");
+ return md;
+ }
+
+ @Override
+ public J.Return visitReturn(J.Return return_, ExecutionContext ctx) {
+ Expression expression = return_.getExpression();
+ if (expression == null) {
+ return return_;
+ }
+ J.Return altered = JavaTemplate.builder("Optional.ofNullable(#{any()})")
+ .imports("java.util.Optional")
+ .build()
+ .apply(getCursor(), expression.getCoordinates().replace(), expression);
+ if (altered == null) {
+ return return_;
+ }
+ maybeAddImport("java.util.Optional");
+
+ return altered;
+ }
+ }
+
+ @RequiredArgsConstructor
+ private static class FunctionalVisitor extends JavaIsoVisitor {
+ private final JavaIsoVisitor implementationVisitor;
+
+ @Override
+ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
+ if (!isAuditorAware.matches(method.getReturnTypeExpression()) || method.getBody() == null || method.getBody().getStatements().size() != 1) {
+ return method;
+ }
+ Statement statement = method.getBody().getStatements().get(0);
+ if (!(statement instanceof J.Return)) {
+ return method;
+ }
+ return super.visitMethodDeclaration(method, ctx);
+ }
+
+ @Override
+ public J.Return visitReturn(J.Return return_, ExecutionContext ctx) {
+ Expression expression = return_.getExpression();
+ if (expression instanceof J.MemberReference) {
+ J.MemberReference memberReference = (J.MemberReference) expression;
+ JavaType.Method methodType = memberReference.getMethodType();
+ if (methodType == null || isOptional.matches(methodType.getReturnType())) {
+ return return_;
+ }
+ expression = (Expression) new MemberReferenceToMethodInvocation().visitNonNull(memberReference, ctx, new Cursor(getCursor(), expression).getParent());
+ }
+ if (expression instanceof J.Lambda) {
+ J.Lambda lambda = ((J.Lambda) expression);
+ J body = lambda.getBody();
+ if (body instanceof J.MethodInvocation &&
+ (((J.MethodInvocation) body).getMethodType() != null && isOptional.matches(((J.MethodInvocation) body).getMethodType().getReturnType()))) {
+ return return_;
+ }
+ if (body instanceof J.Literal || body instanceof J.MethodInvocation) {
+ body = JavaTemplate.builder("Optional.ofNullable(#{any()})")
+ .contextSensitive()
+ .imports("java.util.Optional")
+ .build()
+ .apply(new Cursor(getCursor(), lambda), lambda.getCoordinates().replace(), body);
+ JavaType.Method methodType = ((J.MethodInvocation) body).getMethodType();
+ if (methodType != null) {
+ methodType = methodType.withReturnType(JavaType.buildType("java.util.Optional"));
+ }
+ body = ((J.MethodInvocation) body).withMethodType(methodType);
+ maybeAddImport("java.util.Optional");
+ return return_.withExpression(lambda.withBody(body));
+ }
+ return super.visitReturn(return_, ctx);
+ }
+ if (expression instanceof J.MethodInvocation) {
+ if (((J.MethodInvocation) expression).getMethodType() != null && isOptional.matches(((J.MethodInvocation) expression).getMethodType().getReturnType())) {
+ return return_;
+ }
+ maybeAddImport("java.util.Optional");
+ return return_.withExpression(JavaTemplate.builder("Optional.ofNullable(#{any()})")
+ .imports("java.util.Optional")
+ .build()
+ .apply(new Cursor(getCursor(), expression), expression.getCoordinates().replace(), expression));
+ } else if (expression instanceof J.NewClass && isAuditorAware.matches(((J.NewClass) expression).getClazz().getType())) {
+ implementationVisitor.setCursor(new Cursor(getCursor(), expression));
+ maybeAddImport("java.util.Optional");
+ return return_.withExpression(implementationVisitor.visitNewClass((J.NewClass) expression, ctx));
+ }
+ return return_;
+ }
+ }
+}
diff --git a/src/main/java/org/openrewrite/java/spring/util/concurrent/MemberReferenceToMethodInvocation.java b/src/main/java/org/openrewrite/java/spring/util/MemberReferenceToMethodInvocation.java
similarity index 95%
rename from src/main/java/org/openrewrite/java/spring/util/concurrent/MemberReferenceToMethodInvocation.java
rename to src/main/java/org/openrewrite/java/spring/util/MemberReferenceToMethodInvocation.java
index cfa8c4e03..abad6c7ab 100644
--- a/src/main/java/org/openrewrite/java/spring/util/concurrent/MemberReferenceToMethodInvocation.java
+++ b/src/main/java/org/openrewrite/java/spring/util/MemberReferenceToMethodInvocation.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.openrewrite.java.spring.util.concurrent;
+package org.openrewrite.java.spring.util;
import lombok.Value;
import org.openrewrite.ExecutionContext;
@@ -28,7 +28,7 @@
import static java.util.stream.Collectors.joining;
-class MemberReferenceToMethodInvocation extends JavaVisitor {
+public class MemberReferenceToMethodInvocation extends JavaVisitor {
@Override
public J visitMemberReference(J.MemberReference memberRef, ExecutionContext ctx) {
J.MemberReference mr = (J.MemberReference) super.visitMemberReference(memberRef, ctx);
diff --git a/src/main/java/org/openrewrite/java/spring/util/concurrent/SuccessFailureCallbackToBiConsumerVisitor.java b/src/main/java/org/openrewrite/java/spring/util/concurrent/SuccessFailureCallbackToBiConsumerVisitor.java
index 057af2dd9..28177e7f9 100644
--- a/src/main/java/org/openrewrite/java/spring/util/concurrent/SuccessFailureCallbackToBiConsumerVisitor.java
+++ b/src/main/java/org/openrewrite/java/spring/util/concurrent/SuccessFailureCallbackToBiConsumerVisitor.java
@@ -19,6 +19,7 @@
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.MethodMatcher;
+import org.openrewrite.java.spring.util.MemberReferenceToMethodInvocation;
import org.openrewrite.java.tree.J;
import org.openrewrite.staticanalysis.RemoveUnneededBlock;
diff --git a/src/main/java/org/openrewrite/java/spring/util/package-info.java b/src/main/java/org/openrewrite/java/spring/util/package-info.java
new file mode 100644
index 000000000..4abd01b3a
--- /dev/null
+++ b/src/main/java/org/openrewrite/java/spring/util/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+@NullMarked @NonNullFields
+package org.openrewrite.java.spring.util;
+
+import org.jspecify.annotations.NullMarked;
+import org.openrewrite.internal.lang.NonNullFields;
diff --git a/src/main/resources/META-INF/rewrite/classpath/spring-data-commons-1.13.23.RELEASE.jar b/src/main/resources/META-INF/rewrite/classpath/spring-data-commons-1.13.23.RELEASE.jar
new file mode 100644
index 000000000..103e01325
Binary files /dev/null and b/src/main/resources/META-INF/rewrite/classpath/spring-data-commons-1.13.23.RELEASE.jar differ
diff --git a/src/main/resources/META-INF/rewrite/spring-boot-20.yml b/src/main/resources/META-INF/rewrite/spring-boot-20.yml
index 62562cec2..9d86dd617 100644
--- a/src/main/resources/META-INF/rewrite/spring-boot-20.yml
+++ b/src/main/resources/META-INF/rewrite/spring-boot-20.yml
@@ -82,6 +82,7 @@ recipeList:
newValue: "off"
- org.openrewrite.java.spring.boot2.SpringBoot2BestPractices
- org.openrewrite.apache.commons.lang.UpgradeApacheCommonsLang_2_3
+ - org.openrewrite.java.spring.data.MigrateAuditorAwareToOptional
---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.spring.boot2.MigrateToWebServerFactoryCustomizer
diff --git a/src/test/java/org/openrewrite/java/spring/data/MigrateAuditorAwareToOptionalTest.java b/src/test/java/org/openrewrite/java/spring/data/MigrateAuditorAwareToOptionalTest.java
new file mode 100644
index 000000000..d81161802
--- /dev/null
+++ b/src/test/java/org/openrewrite/java/spring/data/MigrateAuditorAwareToOptionalTest.java
@@ -0,0 +1,515 @@
+/*
+ * 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.java.spring.data;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.InMemoryExecutionContext;
+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;
+
+@Issue("https://github.com/openrewrite/rewrite-spring/issues/613")
+class MigrateAuditorAwareToOptionalTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec
+ .parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "spring-data-commons-1.13"))
+ .recipe(new MigrateAuditorAwareToOptional());
+ }
+
+ @DocumentExample
+ @Test
+ void rewriteImplementation() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ public class MyAuditorAware implements AuditorAware {
+ @Override
+ public String getCurrentAuditor() {
+ return "admin";
+ }
+ }
+ """, """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class MyAuditorAware implements AuditorAware {
+ @Override
+ public Optional getCurrentAuditor() {
+ return Optional.ofNullable("admin");
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void rewriteLambdaLiteral() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return () -> "admin";
+ }
+ }
+ """, """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return () -> Optional.ofNullable("admin");
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void rewriteLambdaBlock() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Objects;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return () -> {
+ return Objects.toString("admin");
+ };
+ }
+ }
+ """, """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Objects;
+ import java.util.Optional;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return () -> {
+ return Optional.ofNullable(Objects.toString("admin"));
+ };
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void rewriteInterfaceInstantiation() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return new AuditorAware() {
+ @Override
+ public String getCurrentAuditor() {
+ return "admin";
+ }
+ };
+ }
+ }
+ """, """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return new AuditorAware() {
+ @Override
+ public Optional getCurrentAuditor() {
+ return Optional.ofNullable("admin");
+ }
+ };
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void rewriteMethodReference() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return this::getCurrentAuditor;
+ }
+
+ public String getCurrentAuditor() {
+ return "admin";
+ }
+ }
+ """, """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return () -> Optional.ofNullable(this.getCurrentAuditor());
+ }
+
+ public String getCurrentAuditor() {
+ return "admin";
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void dontRewriteImplementation() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class MyAuditorAware implements AuditorAware {
+ @Override
+ public Optional getCurrentAuditor() {
+ return Optional.ofNullable("admin");
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void dontRewriteLambdaLiteral() {
+ rewriteRun(
+ spec -> spec.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "spring-data-commons-2")),
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return () -> Optional.ofNullable("admin");
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void dontRewriteLambdaBlock() {
+ rewriteRun(
+ spec -> spec.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "spring-data-commons-2")),
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Objects;
+ import java.util.Optional;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return () -> {
+ return Optional.ofNullable(Objects.toString("admin"));
+ };
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void dontRewriteInterfaceInstantiation() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return new AuditorAware() {
+ @Override
+ public Optional getCurrentAuditor() {
+ return Optional.ofNullable("admin");
+ }
+ };
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void complexerObjects() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ public class Configuration {
+
+ public AuditorAware auditorAware() {
+ return this::determineUser;
+ }
+
+ public User determineUser() {
+ return new User("admin");
+ }
+
+ public static class User {
+ private final String name;
+
+ public User(String name) {
+ this.name = name;
+ }
+ }
+ }
+ """, """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class Configuration {
+
+ public AuditorAware auditorAware() {
+ return () -> Optional.ofNullable(this.determineUser());
+ }
+
+ public User determineUser() {
+ return new User("admin");
+ }
+
+ public static class User {
+ private final String name;
+
+ public User(String name) {
+ this.name = name;
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void dontRewriteOptionalObjectMethodReference() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class Configuration {
+
+ public AuditorAware auditorAware() {
+ return this::determineUser;
+ }
+
+ public Optional determineUser() {
+ return Optional.of(new User("admin"));
+ }
+
+ public static class User {
+ private final String name;
+
+ public User(String name) {
+ this.name = name;
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void dontRewriteOptionalMethodReference() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class Configuration {
+ public AuditorAware auditorAware() {
+ return this::getCurrentAuditor;
+ }
+
+ public Optional getCurrentAuditor() {
+ return Optional.ofNullable("admin");
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void complexerObjectsCalls() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ public class Configuration {
+
+ public AuditorAware auditorAware() {
+ return () -> {
+ User u = this.determineUser();
+ return u.getName();
+ };
+ }
+
+ public User determineUser() {
+ return new User("admin");
+ }
+
+ public static class User {
+ private final String name;
+
+ public User(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+ }
+ """, """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class Configuration {
+
+ public AuditorAware auditorAware() {
+ return () -> {
+ User u = this.determineUser();
+ return Optional.ofNullable(u.getName());
+ };
+ }
+
+ public User determineUser() {
+ return new User("admin");
+ }
+
+ public static class User {
+ private final String name;
+
+ public User(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void dontRewriteOptionalObjectMethodInvocations() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.springframework.data.domain.AuditorAware;
+
+ import java.util.Optional;
+
+ public class Configuration {
+
+ public AuditorAware auditorAware() {
+ return () -> {
+ User u = this.determineUser();
+ return u.getName();
+ };
+ }
+
+ public User determineUser() {
+ return new User("admin");
+ }
+
+ public static class User {
+ private final String name;
+
+ public User(String name) {
+ this.name = name;
+ }
+
+ public Optional getName() {
+ return Optional.ofNullable(name);
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+}
diff --git a/src/test/java/org/openrewrite/java/spring/util/concurrent/MemberReferenceToMethodInvocationTest.java b/src/test/java/org/openrewrite/java/spring/util/MemberReferenceToMethodInvocationTest.java
similarity index 97%
rename from src/test/java/org/openrewrite/java/spring/util/concurrent/MemberReferenceToMethodInvocationTest.java
rename to src/test/java/org/openrewrite/java/spring/util/MemberReferenceToMethodInvocationTest.java
index 1d3c389bb..4da42dea6 100644
--- a/src/test/java/org/openrewrite/java/spring/util/concurrent/MemberReferenceToMethodInvocationTest.java
+++ b/src/test/java/org/openrewrite/java/spring/util/MemberReferenceToMethodInvocationTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.openrewrite.java.spring.util.concurrent;
+package org.openrewrite.java.spring.util;
import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;