Skip to content

Commit b501d07

Browse files
Extend SortingAndPaging Repository with Crud Repository (#272)
- Extend SortingAndPaging Repository with Crud Repository - The recipe CrudExtensionWithReference provides selective extension only if methods from Crud are really called. Left for the future usage Co-authored-by: sanagaraj-pivotal <[email protected]>
1 parent 31fc5ae commit b501d07

File tree

13 files changed

+1227
-193
lines changed

13 files changed

+1227
-193
lines changed

.github/workflows/mvn-build.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: Java CI
22
on:
33
push:
44
branches: '**'
5-
# pull_request:
6-
# branches:
7-
# - main
5+
pull_request:
6+
branches:
7+
- main
88
jobs:
99
build:
1010
runs-on: ubuntu-latest
@@ -18,4 +18,4 @@ jobs:
1818
distribution: 'adopt'
1919
cache: 'maven'
2020
- name: Build with Maven
21-
run: mvn --update-snapshots -DtrimStackTrace=false -Dsurefire.useFile=false -DskipITs verify
21+
run: mvn --update-snapshots -DtrimStackTrace=false -Dsurefire.useFile=false -DskipITs verify

applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/pom.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@
3535
<artifactId>h2</artifactId>
3636
<scope>runtime</scope>
3737
</dependency>
38+
<dependency>
39+
<groupId>io.projectreactor</groupId>
40+
<artifactId>reactor-core</artifactId>
41+
</dependency>
42+
<dependency>
43+
<groupId>io.reactivex.rxjava3</groupId>
44+
<artifactId>rxjava</artifactId>
45+
<version>3.1.5</version>
46+
</dependency>
3847
<dependency>
3948
<groupId>org.springframework.boot</groupId>
4049
<artifactId>spring-boot-starter-test</artifactId>

applications/spring-shell/src/test/resources/testcode/boot-migration-27-30/src/main/java/org/springboot/example/upgrade/BootUpgrade2730Application.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
5-
import org.springframework.context.annotation.Bean;
65

76
@SpringBootApplication
87
public class BootUpgrade2730Application {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.springboot.example.upgrade;
2+
3+
import org.springframework.stereotype.Component;
4+
5+
import java.util.List;
6+
7+
@Component
8+
public class RepositoryController {
9+
private final StudentRepoPagingAndSorting studentRepoPagingAndSorting;
10+
private final StudentRepoReactiveSorting studentRepoReactiveSorting;
11+
private final StudentRepoRxJava3Sorting studentRepoRxJava3Sorting;
12+
13+
public RepositoryController(StudentRepoPagingAndSorting studentRepoPagingAndSorting, StudentRepoReactiveSorting studentRepoReactiveSorting, StudentRepoRxJava3Sorting studentRepoRxJava3Sorting) {
14+
this.studentRepoPagingAndSorting = studentRepoPagingAndSorting;
15+
this.studentRepoReactiveSorting = studentRepoReactiveSorting;
16+
this.studentRepoRxJava3Sorting = studentRepoRxJava3Sorting;
17+
}
18+
19+
public void actWithRepositories() {
20+
studentRepoPagingAndSorting.save(new Student<String>());
21+
List.of(new Student<String>())
22+
.forEach(studentRepoReactiveSorting::save);
23+
studentRepoRxJava3Sorting.save(new Student<String>());
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.springboot.example.upgrade;
2+
3+
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
4+
import org.springframework.data.repository.reactive.ReactiveSortingRepository;
5+
6+
public interface StudentRepoReactiveSorting extends ReactiveSortingRepository<Student<?>, Long> {
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.springboot.example.upgrade;
2+
3+
import org.springframework.data.repository.reactive.RxJava3SortingRepository;
4+
5+
public interface StudentRepoRxJava3Sorting extends RxJava3SortingRepository<Student<?>, Long> {
6+
}

components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/CrudRepositoryExtension.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package org.springframework.sbm.boot.upgrade_27_30;
1717

1818

19+
import lombok.Setter;
20+
import lombok.Value;
1921
import org.jetbrains.annotations.NotNull;
2022
import org.openrewrite.ExecutionContext;
2123
import org.openrewrite.Recipe;
@@ -28,16 +30,28 @@
2830
import java.util.List;
2931
import java.util.Optional;
3032

33+
34+
@Setter
3135
public class CrudRepositoryExtension extends Recipe {
32-
public static final String PAGING_AND_SORTING_REPOSITORY = "org.springframework.data.repository.PagingAndSortingRepository";
33-
public static final String CRUD_REPOSITORY = "org.springframework.data.repository.CrudRepository";
3436

3537
@Override
3638
@NotNull
3739
public String getDisplayName() {
3840
return "Extends CrudRepository for Interfaces that extends PagingAndSortingRepository";
3941
}
4042

43+
public CrudRepositoryExtension() {
44+
45+
}
46+
47+
public CrudRepositoryExtension(String pagingAndSortingRepository, String targetCrudRepository) {
48+
this.pagingAndSortingRepository = pagingAndSortingRepository;
49+
this.targetCrudRepository = targetCrudRepository;
50+
}
51+
52+
private String pagingAndSortingRepository;
53+
private String targetCrudRepository;
54+
4155
@Override
4256
protected @Nullable TreeVisitor<?, ExecutionContext> getApplicableTest() {
4357
return new JavaIsoVisitor<>() {
@@ -48,11 +62,11 @@ public J.ClassDeclaration visitClassDeclaration(@NotNull J.ClassDeclaration clas
4862
}
4963

5064
private boolean doesItExtendPagingAndSorting(J.ClassDeclaration classDecl) {
51-
if (classDecl.getType() == null) {
65+
if (classDecl.getImplements() == null) {
5266
return false;
5367
}
5468
return classDecl.getType().getInterfaces().stream()
55-
.anyMatch(impl -> impl.getFullyQualifiedName().equals(PAGING_AND_SORTING_REPOSITORY));
69+
.anyMatch(impl -> impl.getFullyQualifiedName().equals(pagingAndSortingRepository));
5670
}
5771

5872
private J.ClassDeclaration ceaseVisit(J.ClassDeclaration classDecl) {
@@ -79,7 +93,7 @@ public J.ClassDeclaration visitClassDeclaration(@NotNull J.ClassDeclaration clas
7993
return classDecl;
8094
}
8195
List<JavaType> typeParameters = pagingInterface.get().getTypeParameters();
82-
doAfterVisit(new ImplementTypedInterface<>(classDecl, CRUD_REPOSITORY, typeParameters));
96+
doAfterVisit(new ImplementTypedInterface<>(classDecl, targetCrudRepository, typeParameters));
8397
return classDecl;
8498
}
8599

@@ -88,7 +102,7 @@ private Optional<JavaType.FullyQualified> getExtendPagingAndSorting(J.ClassDecla
88102
return Optional.empty();
89103
}
90104
return classDecl.getType().getInterfaces().stream()
91-
.filter(impl -> impl.getFullyQualifiedName().equals(PAGING_AND_SORTING_REPOSITORY))
105+
.filter(impl -> impl.getFullyQualifiedName().equals(pagingAndSortingRepository))
92106
.findAny();
93107
}
94108
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
* Copyright 2021 - 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.sbm.boot.upgrade_27_30;
17+
18+
19+
import lombok.Setter;
20+
import org.jetbrains.annotations.NotNull;
21+
import org.openrewrite.ExecutionContext;
22+
import org.openrewrite.Recipe;
23+
import org.openrewrite.SourceFile;
24+
import org.openrewrite.internal.ListUtils;
25+
import org.openrewrite.java.JavaIsoVisitor;
26+
import org.openrewrite.java.tree.J;
27+
import org.openrewrite.java.tree.JavaType;
28+
import org.openrewrite.java.tree.MethodCall;
29+
import org.openrewrite.java.tree.TypeUtils;
30+
31+
import java.util.HashSet;
32+
import java.util.List;
33+
import java.util.Optional;
34+
import java.util.Set;
35+
36+
37+
@Setter
38+
public class CrudRepositoryExtensionWithReferences extends Recipe {
39+
40+
@Override
41+
@NotNull
42+
public String getDisplayName() {
43+
return "Extends CrudRepository for Interfaces that extends PagingAndSortingRepository";
44+
}
45+
46+
public CrudRepositoryExtensionWithReferences() {
47+
48+
}
49+
50+
public CrudRepositoryExtensionWithReferences(String pagingAndSortingRepository, String targetCrudRepository) {
51+
this.pagingAndSortingRepository = pagingAndSortingRepository;
52+
this.targetCrudRepository = targetCrudRepository;
53+
}
54+
55+
private String pagingAndSortingRepository;
56+
private String targetCrudRepository;
57+
58+
@Override
59+
protected List<SourceFile> visit(List<SourceFile> allSourceFiles, ExecutionContext ctx) {
60+
61+
Set<String> classesToAddCrudRepository = new HashSet<>();
62+
for (SourceFile source : allSourceFiles) {
63+
64+
if (source instanceof J) {
65+
J cu = (J) source;
66+
67+
new JavaIsoVisitor<Integer>() {
68+
69+
@Override
70+
public J.MemberReference visitMemberReference(J.MemberReference memberRef, Integer integer) {
71+
72+
JavaType callingClassType = memberRef.getContaining().getType();
73+
JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(callingClassType);
74+
75+
if ((fullyQualified != null)
76+
&& shouldApplyCrudExtension(callingClassType, memberRef)) {
77+
classesToAddCrudRepository.add(fullyQualified.getFullyQualifiedName());
78+
}
79+
80+
return super.visitMemberReference(memberRef, integer);
81+
}
82+
83+
@Override
84+
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Integer integer) {
85+
if (method.getSelect() == null) {
86+
return super.visitMethodInvocation(method, integer);
87+
}
88+
89+
JavaType callingClassType = method.getSelect().getType();
90+
91+
if (shouldApplyCrudExtension(callingClassType, method)) {
92+
JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(callingClassType);
93+
if (fullyQualified != null) {
94+
classesToAddCrudRepository.add(fullyQualified.getFullyQualifiedName());
95+
}
96+
}
97+
98+
return super.visitMethodInvocation(method, integer);
99+
}
100+
101+
private boolean shouldApplyCrudExtension(JavaType callingClassType, MethodCall method) {
102+
return TypeUtils.isAssignableTo(pagingAndSortingRepository, callingClassType)
103+
&& (method.getMethodType() == null ||
104+
TypeUtils.isAssignableTo(targetCrudRepository, method.getMethodType().getDeclaringType()))
105+
;
106+
}
107+
}.visit(cu, 0);
108+
}
109+
}
110+
111+
return ListUtils.map(allSourceFiles, sourceFile -> (SourceFile) new JavaIsoVisitor<Integer>() {
112+
113+
@Override
114+
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Integer p) {
115+
JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(classDecl.getType());
116+
if (
117+
TypeUtils.isAssignableTo(pagingAndSortingRepository, classDecl.getType())
118+
&& fullyQualified != null
119+
&& classesToAddCrudRepository.contains(fullyQualified.getFullyQualifiedName())
120+
) {
121+
Optional<JavaType.FullyQualified> pagingInterface = getExtendPagingAndSorting(classDecl);
122+
if (pagingInterface.isEmpty()) {
123+
return classDecl;
124+
}
125+
List<JavaType> typeParameters = pagingInterface.get().getTypeParameters();
126+
doAfterVisit(new ImplementTypedInterface<>(classDecl, targetCrudRepository, typeParameters));
127+
128+
return classDecl;
129+
}
130+
131+
return super.visitClassDeclaration(classDecl, p);
132+
}
133+
}.visit(sourceFile, 0));
134+
}
135+
136+
private Optional<JavaType.FullyQualified> getExtendPagingAndSorting(J.ClassDeclaration classDecl) {
137+
if (classDecl.getType() == null) {
138+
return Optional.empty();
139+
}
140+
return classDecl.getType().getInterfaces().stream()
141+
.filter(impl -> impl.getFullyQualifiedName().equals(pagingAndSortingRepository))
142+
.findAny();
143+
}
144+
145+
// @Override
146+
// protected @Nullable TreeVisitor<?, ExecutionContext> getApplicableTest() {
147+
// return new JavaIsoVisitor<>() {
148+
// @Override
149+
// @NotNull
150+
// public J.ClassDeclaration visitClassDeclaration(@NotNull J.ClassDeclaration classDecl, @NotNull ExecutionContext executionContext) {
151+
// return doesItExtendPagingAndSorting(classDecl) ? applyThisRecipe(classDecl) : ceaseVisit(classDecl);
152+
// }
153+
//
154+
// private boolean doesItExtendPagingAndSorting(J.ClassDeclaration classDecl) {
155+
// if (classDecl.getImplements() == null) {
156+
// return false;
157+
// }
158+
// return classDecl.getType().getInterfaces().stream()
159+
// .anyMatch(impl -> impl.getFullyQualifiedName().equals(pagingAndSortingRepository));
160+
// }
161+
//
162+
// private J.ClassDeclaration ceaseVisit(J.ClassDeclaration classDecl) {
163+
// return classDecl;
164+
// }
165+
//
166+
// @NotNull
167+
// private J.ClassDeclaration applyThisRecipe(J.ClassDeclaration classDecl) {
168+
// return classDecl.withMarkers(classDecl.getMarkers().searchResult());
169+
// }
170+
// };
171+
// }
172+
173+
// @Override
174+
// @NotNull
175+
// protected JavaIsoVisitor<ExecutionContext> getVisitor() {
176+
// return new JavaIsoVisitor<>() {
177+
// @Override
178+
// @NotNull
179+
// public J.ClassDeclaration visitClassDeclaration(@NotNull J.ClassDeclaration classDecl, @NotNull ExecutionContext executionContext) {
180+
//
181+
// Optional<JavaType.FullyQualified> pagingInterface = getExtendPagingAndSorting(classDecl);
182+
// if (pagingInterface.isEmpty()) {
183+
// return classDecl;
184+
// }
185+
// List<JavaType> typeParameters = pagingInterface.get().getTypeParameters();
186+
// doAfterVisit(new ImplementTypedInterface<>(classDecl, targetCrudRepository, typeParameters));
187+
// return classDecl;
188+
// }
189+
//
190+
// private Optional<JavaType.FullyQualified> getExtendPagingAndSorting(J.ClassDeclaration classDecl) {
191+
// if (classDecl.getType() == null) {
192+
// return Optional.empty();
193+
// }
194+
// return classDecl.getType().getInterfaces().stream()
195+
// .filter(impl -> impl.getFullyQualifiedName().equals(pagingAndSortingRepository))
196+
// .findAny();
197+
// }
198+
// };
199+
//
200+
// }
201+
}

components/sbm-recipes-boot-upgrade/src/main/resources/recipes/boot-2.7-3.0-dependency-version-update.yaml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,26 @@
113113
description: Replace javax with new jakarta packages
114114
openRewriteRecipeName: org.openrewrite.java.migrate.JavaxMigrationToJakarta
115115

116-
- type: org.springframework.sbm.engine.recipe.OpenRewriteNamedRecipeAdapter
116+
- type: org.springframework.sbm.engine.recipe.OpenRewriteDeclarativeRecipeAdapter
117117
condition:
118118
type: org.springframework.sbm.boot.upgrade.common.conditions.HasSpringBootParentOfVersion
119119
versionStartingWith: "3.0."
120120
description: Add CrudRepository interface extension additionaly to PagingAndSortingRepository
121-
openRewriteRecipeName: org.springframework.sbm.boot.upgrade_27_30.CrudRepositoryExtension
121+
openRewriteRecipe: |-
122+
type: specs.openrewrite.org/v1beta/recipe
123+
name: org.springframework.sbm.boot.upgrade_27_30.SpringBootPropertiesManual_2_7CrudRepo
124+
displayName: Add CrudRepository interface extension additionaly to PagingAndSortingRepository
125+
description: Add CrudRepository interface extension additionaly to PagingAndSortingRepository
126+
recipeList:
127+
- org.springframework.sbm.boot.upgrade_27_30.CrudRepositoryExtension:
128+
pagingAndSortingRepository: org.springframework.data.repository.PagingAndSortingRepository
129+
targetCrudRepository: org.springframework.data.repository.CrudRepository
130+
- org.springframework.sbm.boot.upgrade_27_30.CrudRepositoryExtension:
131+
pagingAndSortingRepository: org.springframework.data.repository.reactive.ReactiveSortingRepository
132+
targetCrudRepository: org.springframework.data.repository.reactive.ReactiveCrudRepository
133+
- org.springframework.sbm.boot.upgrade_27_30.CrudRepositoryExtension:
134+
pagingAndSortingRepository: org.springframework.data.repository.reactive.RxJava3SortingRepository
135+
targetCrudRepository: org.springframework.data.repository.reactive.RxJava3CrudRepository
122136
123137
- type: org.springframework.sbm.engine.recipe.OpenRewriteDeclarativeRecipeAdapter
124138
condition:

0 commit comments

Comments
 (0)