diff --git a/.github/workflows/mvn-build.yml b/.github/workflows/mvn-build.yml index 9611c4071..d3e51cf4f 100644 --- a/.github/workflows/mvn-build.yml +++ b/.github/workflows/mvn-build.yml @@ -2,9 +2,9 @@ name: Java CI on: push: branches: '**' -# pull_request: -# branches: -# - main + pull_request: + branches: + - main jobs: build: runs-on: ubuntu-latest @@ -18,4 +18,4 @@ jobs: distribution: 'adopt' cache: 'maven' - name: Build with Maven - run: mvn --update-snapshots -DtrimStackTrace=false -Dsurefire.useFile=false -DskipITs verify \ No newline at end of file + run: mvn --update-snapshots -DtrimStackTrace=false -Dsurefire.useFile=false -DskipITs verify diff --git a/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/pom.xml b/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/pom.xml index 65b7c2172..ae435e540 100644 --- a/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/pom.xml +++ b/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/pom.xml @@ -35,6 +35,15 @@ h2 runtime + + io.projectreactor + reactor-core + + + io.reactivex.rxjava3 + rxjava + 3.1.5 + org.springframework.boot spring-boot-starter-test diff --git a/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/BootUpgrade2730Application.java b/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/BootUpgrade2730Application.java index 52790113a..da6950db3 100644 --- a/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/BootUpgrade2730Application.java +++ b/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/BootUpgrade2730Application.java @@ -2,7 +2,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; @SpringBootApplication public class BootUpgrade2730Application { diff --git a/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/RepositoryController.java b/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/RepositoryController.java new file mode 100644 index 000000000..bb4767761 --- /dev/null +++ b/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/RepositoryController.java @@ -0,0 +1,25 @@ +package org.springboot.example.upgrade; + +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class RepositoryController { + private final StudentRepoPagingAndSorting studentRepoPagingAndSorting; + private final StudentRepoReactiveSorting studentRepoReactiveSorting; + private final StudentRepoRxJava3Sorting studentRepoRxJava3Sorting; + + public RepositoryController(StudentRepoPagingAndSorting studentRepoPagingAndSorting, StudentRepoReactiveSorting studentRepoReactiveSorting, StudentRepoRxJava3Sorting studentRepoRxJava3Sorting) { + this.studentRepoPagingAndSorting = studentRepoPagingAndSorting; + this.studentRepoReactiveSorting = studentRepoReactiveSorting; + this.studentRepoRxJava3Sorting = studentRepoRxJava3Sorting; + } + + public void actWithRepositories() { + studentRepoPagingAndSorting.save(new Student()); + List.of(new Student()) + .forEach(studentRepoReactiveSorting::save); + studentRepoRxJava3Sorting.save(new Student()); + } +} diff --git a/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/StudentRepo.java b/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/StudentRepoPagingAndSorting.java similarity index 100% rename from applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/StudentRepo.java rename to applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/StudentRepoPagingAndSorting.java diff --git a/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/StudentRepoReactiveSorting.java b/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/StudentRepoReactiveSorting.java new file mode 100644 index 000000000..d0b85d111 --- /dev/null +++ b/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/StudentRepoReactiveSorting.java @@ -0,0 +1,7 @@ +package org.springboot.example.upgrade; + +import org.springframework.data.repository.reactive.ReactiveCrudRepository; +import org.springframework.data.repository.reactive.ReactiveSortingRepository; + +public interface StudentRepoReactiveSorting extends ReactiveSortingRepository, Long> { +} diff --git a/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/StudentRepoRxJava3Sorting.java b/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/StudentRepoRxJava3Sorting.java new file mode 100644 index 000000000..0683d6cfd --- /dev/null +++ b/applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/StudentRepoRxJava3Sorting.java @@ -0,0 +1,6 @@ +package org.springboot.example.upgrade; + +import org.springframework.data.repository.reactive.RxJava3SortingRepository; + +public interface StudentRepoRxJava3Sorting extends RxJava3SortingRepository, Long> { +} diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtension.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtension.java index 4ffc13eec..951a84f6f 100644 --- a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtension.java +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtension.java @@ -16,6 +16,8 @@ package org.springframework.sbm.boot.upgrade_27_30; +import lombok.Setter; +import lombok.Value; import org.jetbrains.annotations.NotNull; import org.openrewrite.ExecutionContext; import org.openrewrite.Recipe; @@ -28,9 +30,9 @@ import java.util.List; import java.util.Optional; + +@Setter public class CrudRepositoryExtension extends Recipe { - public static final String PAGING_AND_SORTING_REPOSITORY = "org.springframework.data.repository.PagingAndSortingRepository"; - public static final String CRUD_REPOSITORY = "org.springframework.data.repository.CrudRepository"; @Override @NotNull @@ -38,6 +40,18 @@ public String getDisplayName() { return "Extends CrudRepository for Interfaces that extends PagingAndSortingRepository"; } + public CrudRepositoryExtension() { + + } + + public CrudRepositoryExtension(String pagingAndSortingRepository, String targetCrudRepository) { + this.pagingAndSortingRepository = pagingAndSortingRepository; + this.targetCrudRepository = targetCrudRepository; + } + + private String pagingAndSortingRepository; + private String targetCrudRepository; + @Override protected @Nullable TreeVisitor getApplicableTest() { return new JavaIsoVisitor<>() { @@ -48,11 +62,11 @@ public J.ClassDeclaration visitClassDeclaration(@NotNull J.ClassDeclaration clas } private boolean doesItExtendPagingAndSorting(J.ClassDeclaration classDecl) { - if (classDecl.getType() == null) { + if (classDecl.getImplements() == null) { return false; } return classDecl.getType().getInterfaces().stream() - .anyMatch(impl -> impl.getFullyQualifiedName().equals(PAGING_AND_SORTING_REPOSITORY)); + .anyMatch(impl -> impl.getFullyQualifiedName().equals(pagingAndSortingRepository)); } private J.ClassDeclaration ceaseVisit(J.ClassDeclaration classDecl) { @@ -79,7 +93,7 @@ public J.ClassDeclaration visitClassDeclaration(@NotNull J.ClassDeclaration clas return classDecl; } List typeParameters = pagingInterface.get().getTypeParameters(); - doAfterVisit(new ImplementTypedInterface<>(classDecl, CRUD_REPOSITORY, typeParameters)); + doAfterVisit(new ImplementTypedInterface<>(classDecl, targetCrudRepository, typeParameters)); return classDecl; } @@ -88,7 +102,7 @@ private Optional getExtendPagingAndSorting(J.ClassDecla return Optional.empty(); } return classDecl.getType().getInterfaces().stream() - .filter(impl -> impl.getFullyQualifiedName().equals(PAGING_AND_SORTING_REPOSITORY)) + .filter(impl -> impl.getFullyQualifiedName().equals(pagingAndSortingRepository)) .findAny(); } }; diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtensionWithReferences.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtensionWithReferences.java new file mode 100644 index 000000000..32c2e3461 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtensionWithReferences.java @@ -0,0 +1,201 @@ +/* + * 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; + + +import lombok.Setter; +import org.jetbrains.annotations.NotNull; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.SourceFile; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.MethodCall; +import org.openrewrite.java.tree.TypeUtils; + +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + + +@Setter +public class CrudRepositoryExtensionWithReferences extends Recipe { + + @Override + @NotNull + public String getDisplayName() { + return "Extends CrudRepository for Interfaces that extends PagingAndSortingRepository"; + } + + public CrudRepositoryExtensionWithReferences() { + + } + + public CrudRepositoryExtensionWithReferences(String pagingAndSortingRepository, String targetCrudRepository) { + this.pagingAndSortingRepository = pagingAndSortingRepository; + this.targetCrudRepository = targetCrudRepository; + } + + private String pagingAndSortingRepository; + private String targetCrudRepository; + + @Override + protected List visit(List allSourceFiles, ExecutionContext ctx) { + + Set classesToAddCrudRepository = new HashSet<>(); + for (SourceFile source : allSourceFiles) { + + if (source instanceof J) { + J cu = (J) source; + + new JavaIsoVisitor() { + + @Override + public J.MemberReference visitMemberReference(J.MemberReference memberRef, Integer integer) { + + JavaType callingClassType = memberRef.getContaining().getType(); + JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(callingClassType); + + if ((fullyQualified != null) + && shouldApplyCrudExtension(callingClassType, memberRef)) { + classesToAddCrudRepository.add(fullyQualified.getFullyQualifiedName()); + } + + return super.visitMemberReference(memberRef, integer); + } + + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Integer integer) { + if (method.getSelect() == null) { + return super.visitMethodInvocation(method, integer); + } + + JavaType callingClassType = method.getSelect().getType(); + + if (shouldApplyCrudExtension(callingClassType, method)) { + JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(callingClassType); + if (fullyQualified != null) { + classesToAddCrudRepository.add(fullyQualified.getFullyQualifiedName()); + } + } + + return super.visitMethodInvocation(method, integer); + } + + private boolean shouldApplyCrudExtension(JavaType callingClassType, MethodCall method) { + return TypeUtils.isAssignableTo(pagingAndSortingRepository, callingClassType) + && (method.getMethodType() == null || + TypeUtils.isAssignableTo(targetCrudRepository, method.getMethodType().getDeclaringType())) + ; + } + }.visit(cu, 0); + } + } + + return ListUtils.map(allSourceFiles, sourceFile -> (SourceFile) new JavaIsoVisitor() { + + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Integer p) { + JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(classDecl.getType()); + if ( + TypeUtils.isAssignableTo(pagingAndSortingRepository, classDecl.getType()) + && fullyQualified != null + && classesToAddCrudRepository.contains(fullyQualified.getFullyQualifiedName()) + ) { + Optional pagingInterface = getExtendPagingAndSorting(classDecl); + if (pagingInterface.isEmpty()) { + return classDecl; + } + List typeParameters = pagingInterface.get().getTypeParameters(); + doAfterVisit(new ImplementTypedInterface<>(classDecl, targetCrudRepository, typeParameters)); + + return classDecl; + } + + return super.visitClassDeclaration(classDecl, p); + } + }.visit(sourceFile, 0)); + } + + private Optional getExtendPagingAndSorting(J.ClassDeclaration classDecl) { + if (classDecl.getType() == null) { + return Optional.empty(); + } + return classDecl.getType().getInterfaces().stream() + .filter(impl -> impl.getFullyQualifiedName().equals(pagingAndSortingRepository)) + .findAny(); + } + + // @Override +// protected @Nullable TreeVisitor getApplicableTest() { +// return new JavaIsoVisitor<>() { +// @Override +// @NotNull +// public J.ClassDeclaration visitClassDeclaration(@NotNull J.ClassDeclaration classDecl, @NotNull ExecutionContext executionContext) { +// return doesItExtendPagingAndSorting(classDecl) ? applyThisRecipe(classDecl) : ceaseVisit(classDecl); +// } +// +// private boolean doesItExtendPagingAndSorting(J.ClassDeclaration classDecl) { +// if (classDecl.getImplements() == null) { +// return false; +// } +// return classDecl.getType().getInterfaces().stream() +// .anyMatch(impl -> impl.getFullyQualifiedName().equals(pagingAndSortingRepository)); +// } +// +// private J.ClassDeclaration ceaseVisit(J.ClassDeclaration classDecl) { +// return classDecl; +// } +// +// @NotNull +// private J.ClassDeclaration applyThisRecipe(J.ClassDeclaration classDecl) { +// return classDecl.withMarkers(classDecl.getMarkers().searchResult()); +// } +// }; +// } + +// @Override +// @NotNull +// protected JavaIsoVisitor getVisitor() { +// return new JavaIsoVisitor<>() { +// @Override +// @NotNull +// public J.ClassDeclaration visitClassDeclaration(@NotNull J.ClassDeclaration classDecl, @NotNull ExecutionContext executionContext) { +// +// Optional pagingInterface = getExtendPagingAndSorting(classDecl); +// if (pagingInterface.isEmpty()) { +// return classDecl; +// } +// List typeParameters = pagingInterface.get().getTypeParameters(); +// doAfterVisit(new ImplementTypedInterface<>(classDecl, targetCrudRepository, typeParameters)); +// return classDecl; +// } +// +// private Optional getExtendPagingAndSorting(J.ClassDeclaration classDecl) { +// if (classDecl.getType() == null) { +// return Optional.empty(); +// } +// return classDecl.getType().getInterfaces().stream() +// .filter(impl -> impl.getFullyQualifiedName().equals(pagingAndSortingRepository)) +// .findAny(); +// } +// }; +// +// } +} diff --git a/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-2.7-3.0-dependency-version-update.yaml b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-2.7-3.0-dependency-version-update.yaml index 8cf82e9fd..76ef74370 100644 --- a/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-2.7-3.0-dependency-version-update.yaml +++ b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-2.7-3.0-dependency-version-update.yaml @@ -113,12 +113,26 @@ description: Replace javax with new jakarta packages openRewriteRecipeName: org.openrewrite.java.migrate.JavaxMigrationToJakarta - - type: org.springframework.sbm.engine.recipe.OpenRewriteNamedRecipeAdapter + - type: org.springframework.sbm.engine.recipe.OpenRewriteDeclarativeRecipeAdapter condition: type: org.springframework.sbm.boot.upgrade.common.conditions.HasSpringBootParentOfVersion versionStartingWith: "3.0." description: Add CrudRepository interface extension additionaly to PagingAndSortingRepository - openRewriteRecipeName: org.springframework.sbm.boot.upgrade_27_30.CrudRepositoryExtension + openRewriteRecipe: |- + type: specs.openrewrite.org/v1beta/recipe + name: org.springframework.sbm.boot.upgrade_27_30.SpringBootPropertiesManual_2_7CrudRepo + displayName: Add CrudRepository interface extension additionaly to PagingAndSortingRepository + description: Add CrudRepository interface extension additionaly to PagingAndSortingRepository + recipeList: + - org.springframework.sbm.boot.upgrade_27_30.CrudRepositoryExtension: + pagingAndSortingRepository: org.springframework.data.repository.PagingAndSortingRepository + targetCrudRepository: org.springframework.data.repository.CrudRepository + - org.springframework.sbm.boot.upgrade_27_30.CrudRepositoryExtension: + pagingAndSortingRepository: org.springframework.data.repository.reactive.ReactiveSortingRepository + targetCrudRepository: org.springframework.data.repository.reactive.ReactiveCrudRepository + - org.springframework.sbm.boot.upgrade_27_30.CrudRepositoryExtension: + pagingAndSortingRepository: org.springframework.data.repository.reactive.RxJava3SortingRepository + targetCrudRepository: org.springframework.data.repository.reactive.RxJava3CrudRepository - type: org.springframework.sbm.engine.recipe.OpenRewriteDeclarativeRecipeAdapter condition: diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtensionTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtensionTest.java index 0f5308f71..7a8b25d18 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtensionTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtensionTest.java @@ -15,219 +15,396 @@ */ package org.springframework.sbm.boot.upgrade_27_30; -import org.junit.jupiter.api.Test; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.openrewrite.Recipe; +import org.openrewrite.Result; +import org.openrewrite.test.RewriteTest; import java.util.List; +import java.util.stream.Stream; +import static org.assertj.core.api.Assertions.assertThat; -public class CrudRepositoryExtensionTest { - private JavaTestHelper javaTestHelper = new JavaTestHelper(); - private Recipe recipe = new CrudRepositoryExtension(); +public class CrudRepositoryExtensionTest implements RewriteTest { - @Test - public void shouldAddCrudRepository() { + private final JavaTestHelper javaTestHelper = new JavaTestHelper(); + private static final Recipe crudRepoExtensionRecipe = new CrudRepositoryExtensionWithReferences( + "org.springframework.data.repository.PagingAndSortingRepository", + "org.springframework.data.repository.CrudRepository" + ); - javaTestHelper.runAndVerify( + private static final Recipe reactiveCrudExtensionRecipe = new CrudRepositoryExtensionWithReferences( + "org.springframework.data.repository.reactive.ReactiveSortingRepository", + "org.springframework.data.repository.reactive.ReactiveCrudRepository" + ); + + private static final Recipe rxJavaCrudExtensionRecipe = new CrudRepositoryExtensionWithReferences( + "org.springframework.data.repository.reactive.RxJava3SortingRepository", + "org.springframework.data.repository.reactive.RxJava3CrudRepository" + ); + + + @ParameterizedTest + @MethodSource("repositoryTestArguments") + public void shouldAddCrudRepository(Recipe recipe, String pagingAndSortingRepository, String crudRepository, String repositoryPackage) { + + @NotNull List result = javaTestHelper.runRecipe( recipe, - List.of(""" - package org.springframework.data.repository; - public interface PagingAndSortingRepository { + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + void save(T entity); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + public interface A extends -pagingRepository- { } - """, - """ - package org.springframework.data.repository; - public interface CrudRepository { + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + public class Hello { + public void test(A a) { + a.save("Hello"); + } } - """), - """ - package test; - import org.springframework.data.repository.PagingAndSortingRepository; - public interface A extends PagingAndSortingRepository { - } - """, - """ + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + javaTestHelper.assertResult(result, replacePagingRepoAndCrudRepo(""" package test; - import org.springframework.data.repository.CrudRepository; - import org.springframework.data.repository.PagingAndSortingRepository; - - public interface A extends PagingAndSortingRepository, CrudRepository { + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + + public interface A extends -pagingRepository-, -crudRepository- { } - """ - ); + """, pagingAndSortingRepository, crudRepository, repositoryPackage + )); } - @Test - public void canDoQuestionMark() { + @ParameterizedTest + @MethodSource("repositoryTestArguments") + public void canDoQuestionMark(Recipe recipe, String pagingAndSortingRepository, String crudRepository, String repositoryPackage) { - javaTestHelper.runAndVerify(recipe, - List.of(""" - package org.springframework.data.repository; - public interface PagingAndSortingRepository { + @NotNull List result = javaTestHelper.runRecipe(recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + void save(T); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + public interface Payment { + T hello(); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + public interface A extends -pagingRepository-, Long> { } - """, - """ - package org.springframework.data.repository; - public interface CrudRepository { + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + public class Hello { + public void test(A a) { + a.save("Hello"); + } } - """, - """ + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + javaTestHelper.assertResult(result, replacePagingRepoAndCrudRepo(""" package test; - public interface Payment { - T hello(); + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + + public interface A extends -pagingRepository-, Long>, -crudRepository-, Long> { } - """), - """ - package test; - import org.springframework.data.repository.PagingAndSortingRepository; - public interface A extends PagingAndSortingRepository, Long> { - } - """, - """ - package test; - import org.springframework.data.repository.CrudRepository; - import org.springframework.data.repository.PagingAndSortingRepository; - - public interface A extends PagingAndSortingRepository, Long>, CrudRepository, Long> { - } - """ - ); + """, pagingAndSortingRepository, crudRepository, repositoryPackage)); } - @Test - public void onlyExtendCrudRepoIfInterfaceHasPagingAndSortingRepository() { - javaTestHelper.runAndVerifyNoChanges(recipe, - List.of(""" - package org.springframework.data.repository; - public interface HelloWorld { - } - """, - """ - package org.springframework.data.repository; - public interface CrudRepository { + @MethodSource("repositoryTestArguments") + @ParameterizedTest + public void whenThereAreNoParametersWhilstExtending(Recipe recipe, String pagingAndSortingRepository, String crudRepository, String repositoryPackage) { + + @NotNull List results = javaTestHelper.runRecipe( + recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + public interface A extends -pagingRepository- { } - """, - """ + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" package test; - public interface Payment { - T hello(); + public class Hello { + public void test(A a) { + a.save("Hello"); + } } - """), - """ - package test; - import org.springframework.data.repository.HelloWorld; - public interface A extends HelloWorld, Long> { - } - """ + """, pagingAndSortingRepository, crudRepository, repositoryPackage) ); - } - @Test - public void whenThereAreNoParametersWhilstExtending() { + javaTestHelper.assertResult(results, replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + + public interface A extends -pagingRepository-, -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)); + } - javaTestHelper.runAndVerify( + @MethodSource("repositoryTestArguments") + @ParameterizedTest + public void multipleExtends(Recipe recipe, String pagingAndSortingRepository, String crudRepository, String repositoryPackage) { + @NotNull List results = javaTestHelper.runRecipe( recipe, - List.of(""" - package org.springframework.data.repository; - public interface PagingAndSortingRepository { + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package temp; + public interface Hello { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + import temp.Hello; + public interface A extends Hello, -pagingRepository- { } - """, - """ - package org.springframework.data.repository; - public interface CrudRepository { + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + public class Hello { + public void test(A a) { + a.save("Hello"); + } } - """), - """ - package test; - import org.springframework.data.repository.PagingAndSortingRepository; - public interface A extends PagingAndSortingRepository { - } - """, - """ - package test; - import org.springframework.data.repository.CrudRepository; - import org.springframework.data.repository.PagingAndSortingRepository; - - public interface A extends PagingAndSortingRepository, CrudRepository { - } - """ + """, pagingAndSortingRepository, crudRepository, repositoryPackage) ); + + javaTestHelper.assertResult(results, replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + import temp.Hello; + + public interface A extends Hello, -pagingRepository-, -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)); } - @Test - public void multipleExtends() { - javaTestHelper.runAndVerify( + @MethodSource("repositoryTestArguments") + @ParameterizedTest + public void classImplementsPagingRepository(Recipe recipe, String pagingAndSortingRepository, String crudRepository, String repositoryPackage) { + @NotNull List result = javaTestHelper.runRecipe( recipe, - List.of(""" - package org.springframework.data.repository; - public interface PagingAndSortingRepository { - } - """, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), """ - package org.springframework.data.repository; - public interface Hello { + package temp; + public interface Hello { + } + """, + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + import temp.Hello; + public class A implements Hello, -pagingRepository- { } - """, - """ - package org.springframework.data.repository; - public interface CrudRepository { + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + public class Hello { + public void test(A a) { + a.save("Hello"); + } } - """), - """ - package test; - import org.springframework.data.repository.PagingAndSortingRepository; - import org.springframework.data.repository.Hello; - public interface A extends Hello, PagingAndSortingRepository { - } - """, - """ - package test; - import org.springframework.data.repository.PagingAndSortingRepository; - import org.springframework.data.repository.CrudRepository; - import org.springframework.data.repository.Hello; - - public interface A extends Hello, PagingAndSortingRepository, CrudRepository { - } - """ + """, pagingAndSortingRepository, crudRepository, repositoryPackage) ); + + javaTestHelper.assertResult(result, replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + import temp.Hello; + + public class A implements Hello, -pagingRepository-, -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)); } - @Test - public void classImplementsPagingRepository() { - javaTestHelper.runAndVerify( + @ParameterizedTest + @MethodSource("repositoryTestArguments") + void shouldExtendCrudRepositoryInInnerInterface(Recipe recipe, String pagingAndSortingRepository, + String crudRepository, + String repositoryPackage) { + @NotNull List result = javaTestHelper.runRecipe( recipe, - List.of(""" - package org.springframework.data.repository; - public interface PagingAndSortingRepository { + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + void save(String entity); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + class Hello { + public interface A extends -pagingRepository- { + } + + public void myCall(A a) { + a.save(""); + } } - """, - """ - package org.springframework.data.repository; - public interface Hello { + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + assertThat(result).hasSize(1); + assertThat(result.get(0).getAfter().printAll()) + .isEqualTo( + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + + class Hello { + public interface A extends -pagingRepository-, -crudRepository- { + } + + public void myCall(A a) { + a.save(""); + } } - """, - """ - package org.springframework.data.repository; - public interface CrudRepository { + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + } + + @ParameterizedTest + @MethodSource("repositoryTestArguments") + void shouldExtendCrudRepositoryForCrudMethodReference(Recipe recipe, String pagingAndSortingRepository, + String crudRepository, + String repositoryPackage) { + @NotNull List result = javaTestHelper.runRecipe( + recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + void save(String entity); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ), + replacePagingRepoAndCrudRepo(""" + package test; + import java.util.List; + + import -repositoryPackage-.-pagingRepository-; + + class Hello { + public interface A extends -pagingRepository- { + } + + public void myCall(A a) { + List.of("1", "2", "3").stream() + .forEach(a::save); + } } - """), - """ - package test; - import org.springframework.data.repository.PagingAndSortingRepository; - import org.springframework.data.repository.Hello; - public class A implements Hello, PagingAndSortingRepository { - } - """, - """ - package test; - import org.springframework.data.repository.PagingAndSortingRepository; - import org.springframework.data.repository.CrudRepository; - import org.springframework.data.repository.Hello; - - public class A implements Hello, PagingAndSortingRepository, CrudRepository { - } - """ + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + assertThat(result).hasSize(1); + assertThat(result.get(0).getAfter().printAll()) + .isEqualTo( + replacePagingRepoAndCrudRepo(""" + package test; + import java.util.List; + + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + + class Hello { + public interface A extends -pagingRepository-, -crudRepository- { + } + + public void myCall(A a) { + List.of("1", "2", "3").stream() + .forEach(a::save); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + } + + private String replacePagingRepoAndCrudRepo(String template, String pagingRepo, String crudRepo, String repositoryPackage) { + + return template + .replaceAll("-pagingRepository-", pagingRepo) + .replaceAll("-crudRepository-", crudRepo) + .replaceAll("-repositoryPackage-", repositoryPackage); + } + + private static Stream repositoryTestArguments() { + return Stream.of( + Arguments.of(crudRepoExtensionRecipe, "PagingAndSortingRepository", "CrudRepository", "org.springframework.data.repository"), + Arguments.of(reactiveCrudExtensionRecipe, "ReactiveSortingRepository", "ReactiveCrudRepository", "org.springframework.data.repository.reactive"), + Arguments.of(rxJavaCrudExtensionRecipe, "RxJava3SortingRepository", "RxJava3CrudRepository", "org.springframework.data.repository.reactive") ); } } diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtensionWithReferencesTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtensionWithReferencesTest.java new file mode 100644 index 000000000..e5f2fe755 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtensionWithReferencesTest.java @@ -0,0 +1,587 @@ +/* + * 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; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openrewrite.Recipe; +import org.openrewrite.Result; +import org.openrewrite.test.RewriteTest; + +import java.util.List; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class CrudRepositoryExtensionWithReferencesTest implements RewriteTest { + + private final JavaTestHelper javaTestHelper = new JavaTestHelper(); + private static final Recipe crudRepoExtensionRecipe = new CrudRepositoryExtensionWithReferences( + "org.springframework.data.repository.PagingAndSortingRepository", + "org.springframework.data.repository.CrudRepository" + ); + + private static final Recipe reactiveCrudExtensionRecipe = new CrudRepositoryExtensionWithReferences( + "org.springframework.data.repository.reactive.ReactiveSortingRepository", + "org.springframework.data.repository.reactive.ReactiveCrudRepository" + ); + + private static final Recipe rxJavaCrudExtensionRecipe = new CrudRepositoryExtensionWithReferences( + "org.springframework.data.repository.reactive.RxJava3SortingRepository", + "org.springframework.data.repository.reactive.RxJava3CrudRepository" + ); + + + @ParameterizedTest + @MethodSource("repositoryTestArguments") + public void shouldAddCrudRepository(Recipe recipe, String pagingAndSortingRepository, String crudRepository, String repositoryPackage) { + + @NotNull List result = javaTestHelper.runRecipe( + recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + void save(T entity); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + public interface A extends -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + public class Hello { + public void test(A a) { + a.save("Hello"); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + javaTestHelper.assertResult(result, replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + + public interface A extends -pagingRepository-, -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage + )); + } + + @ParameterizedTest + @MethodSource("repositoryTestArguments") + public void canDoQuestionMark(Recipe recipe, String pagingAndSortingRepository, String crudRepository, String repositoryPackage) { + + @NotNull List result = javaTestHelper.runRecipe(recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + void save(T); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + public interface Payment { + T hello(); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + public interface A extends -pagingRepository-, Long> { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + public class Hello { + public void test(A a) { + a.save("Hello"); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + javaTestHelper.assertResult(result, replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + + public interface A extends -pagingRepository-, Long>, -crudRepository-, Long> { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)); + } + + @MethodSource("repositoryTestArguments") + @ParameterizedTest + public void onlyExtendCrudRepoIfInterfaceHasPagingAndSortingRepository(Recipe recipe, String pagingAndSortingRepository, String crudRepository, String repositoryPackage) { + @NotNull List result = javaTestHelper.runRecipe(recipe, + List.of(""" + package -repositoryPackage-; + public interface HelloWorld { + } + """, + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + """ + package test; + public interface Payment { + T hello(); + } + """, + """ + package test; + import org.springframework.data.repository.HelloWorld; + public interface A extends HelloWorld, Long> { + } + """ + ) + ); + + assertThat(result).hasSize(0); + } + + + @MethodSource("repositoryTestArguments") + @ParameterizedTest + public void whenThereAreNoParametersWhilstExtending(Recipe recipe, String pagingAndSortingRepository, String crudRepository, String repositoryPackage) { + + @NotNull List results = javaTestHelper.runRecipe( + recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + public interface A extends -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + public class Hello { + public void test(A a) { + a.save("Hello"); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + javaTestHelper.assertResult(results, replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + + public interface A extends -pagingRepository-, -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)); + } + + @MethodSource("repositoryTestArguments") + @ParameterizedTest + public void multipleExtends(Recipe recipe, String pagingAndSortingRepository, String crudRepository, String repositoryPackage) { + @NotNull List results = javaTestHelper.runRecipe( + recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package temp; + public interface Hello { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + import temp.Hello; + public interface A extends Hello, -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + public class Hello { + public void test(A a) { + a.save("Hello"); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + javaTestHelper.assertResult(results, replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + import temp.Hello; + + public interface A extends Hello, -pagingRepository-, -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)); + } + + @MethodSource("repositoryTestArguments") + @ParameterizedTest + public void classImplementsPagingRepository(Recipe recipe, String pagingAndSortingRepository, String crudRepository, String repositoryPackage) { + @NotNull List result = javaTestHelper.runRecipe( + recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + """ + package temp; + public interface Hello { + } + """, + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + import temp.Hello; + public class A implements Hello, -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + public class Hello { + public void test(A a) { + a.save("Hello"); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + javaTestHelper.assertResult(result, replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + import temp.Hello; + + public class A implements Hello, -pagingRepository-, -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage)); + } + + @ParameterizedTest + @MethodSource("repositoryTestArguments") + void shouldExtendCrudRepositoryInInnerInterface(Recipe recipe, String pagingAndSortingRepository, + String crudRepository, + String repositoryPackage) { + @NotNull List result = javaTestHelper.runRecipe( + recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + void save(String entity); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + class Hello { + public interface A extends -pagingRepository- { + } + + public void myCall(A a) { + a.save(""); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + assertThat(result).hasSize(1); + assertThat(result.get(0).getAfter().printAll()) + .isEqualTo( + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + + class Hello { + public interface A extends -pagingRepository-, -crudRepository- { + } + + public void myCall(A a) { + a.save(""); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + } + + @ParameterizedTest + @MethodSource("repositoryTestArguments") + void shouldNotExtendCrudRepositoryIfMethodIsNotCrud(Recipe recipe, String pagingAndSortingRepository, + String crudRepository, + String repositoryPackage) { + @NotNull List result = javaTestHelper.runRecipe( + recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + void findAll(String entity); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + + public interface A extends -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + import -repositoryPackage-.-pagingRepository-; + + public interface B extends -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package test; + class Hello { + + public void myCall(A a, B b) { + a.findAll(""); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + assertThat(result).hasSize(0); + } + + @ParameterizedTest + @MethodSource("repositoryTestArguments") + void shouldExtendCrudRepositoryForCrudMethodReference(Recipe recipe, String pagingAndSortingRepository, + String crudRepository, + String repositoryPackage) { + @NotNull List result = javaTestHelper.runRecipe( + recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + void save(String entity); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ), + replacePagingRepoAndCrudRepo(""" + package test; + import java.util.List; + + import -repositoryPackage-.-pagingRepository-; + + class Hello { + public interface A extends -pagingRepository- { + } + + public void myCall(A a) { + List.of("1", "2", "3").stream() + .forEach(a::save); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + assertThat(result).hasSize(1); + assertThat(result.get(0).getAfter().printAll()) + .isEqualTo( + replacePagingRepoAndCrudRepo(""" + package test; + import java.util.List; + + import -repositoryPackage-.-crudRepository-; + import -repositoryPackage-.-pagingRepository-; + + class Hello { + public interface A extends -pagingRepository-, -crudRepository- { + } + + public void myCall(A a) { + List.of("1", "2", "3").stream() + .forEach(a::save); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + } + + @ParameterizedTest + @MethodSource("repositoryTestArguments") + void shouldNotExtendCrudRepositoryForNonPagingMethodReference(Recipe recipe, String pagingAndSortingRepository, + String crudRepository, + String repositoryPackage) { + @NotNull List result = javaTestHelper.runRecipe( + recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + void save(String entity); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ), + replacePagingRepoAndCrudRepo(""" + package test; + import java.util.List; + + import -repositoryPackage-.-pagingRepository-; + + class Hello { + public interface A extends -pagingRepository- { + } + + public void myCall(A a) { + List.of("1", "2", "3").stream() + .forEach(a::save); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + assertThat(result).hasSize(0); + } + + @ParameterizedTest + @MethodSource("repositoryTestArguments") + public void worksWithStaticImports(Recipe recipe, String pagingAndSortingRepository, + String crudRepository, + String repositoryPackage) { + @NotNull List result = javaTestHelper.runRecipe( + recipe, + List.of(replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -crudRepository- { + + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + replacePagingRepoAndCrudRepo(""" + package -repositoryPackage-; + public interface -pagingRepository- { + void save(String entity); + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage), + """ + package test; + + public class StaticClass { + public static int ret() { + return 0; + } + } + """ + ), + + replacePagingRepoAndCrudRepo(""" + package test; + import java.util.List; + import static StaticClass.*; + import -repositoryPackage-.-pagingRepository-; + + class Hello { + public static int temp() { + return 10; + } + public interface A extends -pagingRepository- { + } + + public void myCall(A a) { + int x = ret(); + List.of("1", "2", "3").stream() + .forEach(a::save); + } + } + """, pagingAndSortingRepository, crudRepository, repositoryPackage) + ); + + assertThat(result).hasSize(0); + } + + + private String replacePagingRepoAndCrudRepo(String template, String pagingRepo, String crudRepo, String repositoryPackage) { + + return template + .replaceAll("-pagingRepository-", pagingRepo) + .replaceAll("-crudRepository-", crudRepo) + .replaceAll("-repositoryPackage-", repositoryPackage); + } + + private static Stream repositoryTestArguments() { + return Stream.of( + Arguments.of(crudRepoExtensionRecipe, "PagingAndSortingRepository", "CrudRepository", "org.springframework.data.repository"), + Arguments.of(reactiveCrudExtensionRecipe, "ReactiveSortingRepository", "ReactiveCrudRepository", "org.springframework.data.repository.reactive"), + Arguments.of(rxJavaCrudExtensionRecipe, "RxJava3SortingRepository", "RxJava3CrudRepository", "org.springframework.data.repository.reactive") + ); + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/JavaTestHelper.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/JavaTestHelper.java index ea24371fe..f077d384d 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/JavaTestHelper.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/JavaTestHelper.java @@ -40,20 +40,9 @@ public void runAndVerifyNoChanges( assertThat(result).hasSize(0); } - public void runAndVerify( - Recipe recipe, - List dependsOn, - @Language("java") String before, - @Language("java") String after - ) { - List result = runRecipe(recipe, dependsOn, before); - - assertThat(result).hasSize(1); - assertThat(result.get(0).getAfter().printAll()).isEqualTo(after); - } @NotNull - private List runRecipe(Recipe recipe, List dependsOn, @Language("java") String before) { + public List runRecipe(Recipe recipe, List dependsOn, @Language("java") String... before) { List errors = new ArrayList<>(); InMemoryExecutionContext ctx = new InMemoryExecutionContext((ex) -> { @@ -73,4 +62,10 @@ private List runRecipe(Recipe recipe, List dependsOn, @Language( assertThat(errors).hasSize(0); return result; } + + public void assertResult(List result, String after) { + + assertThat(result).hasSize(1); + assertThat(result.get(0).getAfter().printAll()).isEqualTo(after); + } }