diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteType.java b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteType.java index fc0e972ab..c88ed622f 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteType.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteType.java @@ -17,6 +17,7 @@ import org.openrewrite.java.*; import org.openrewrite.java.format.WrappingAndBraces; +import org.openrewrite.java.tree.*; import org.springframework.sbm.java.api.*; import org.springframework.sbm.java.migration.visitor.RemoveImplementsVisitor; import org.springframework.sbm.java.refactoring.JavaRefactoring; @@ -26,20 +27,20 @@ import org.openrewrite.ExecutionContext; import org.openrewrite.Recipe; import org.openrewrite.java.search.DeclaresMethod; -import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.J.ClassDeclaration; -import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.JavaType.Class; -import org.openrewrite.java.tree.TypeUtils; import org.springframework.sbm.support.openrewrite.GenericOpenRewriteRecipe; import org.springframework.sbm.support.openrewrite.java.AddAnnotationVisitor; import org.springframework.sbm.support.openrewrite.java.FindCompilationUnitContainingType; import org.springframework.sbm.support.openrewrite.java.RemoveAnnotationVisitor; +import org.springframework.util.StringUtils; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.UUID; +import java.util.function.BiFunction; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -351,4 +352,13 @@ public ClassDeclaration visitClassDeclaration(ClassDeclaration classDecl, Execut apply(new GenericOpenRewriteRecipe>(() -> javaIsoVisitor)); } + public boolean isImplementing(String fqClassName){ + return getClassDeclaration() + .getType() + .getInterfaces() + .stream() + .map(JavaType.FullyQualified::getFullyQualifiedName) + .anyMatch(fqClassName::equals); + } + } diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositoryBeanFinder.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositoryBeanFinder.java new file mode 100644 index 000000000..d800c53fb --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositoryBeanFinder.java @@ -0,0 +1,46 @@ +/* + * 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.checks; + +import org.springframework.sbm.java.api.JavaSourceAndType; +import org.springframework.sbm.java.impl.OpenRewriteJavaSource; +import org.springframework.sbm.project.resource.ProjectResourceSet; +import org.springframework.sbm.project.resource.filter.ProjectResourceFinder; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +@Component +public class ApacheSolrRepositoryBeanFinder implements ProjectResourceFinder> { + private static final String SOLR_REPOSITORY_CLASS = "org.springframework.data.solr.repository.SolrCrudRepository"; + + @Override + public List apply(ProjectResourceSet projectResourceSet) { + return projectResourceSet.stream() + .filter(OpenRewriteJavaSource.class::isInstance) + .map(OpenRewriteJavaSource.class::cast) + .filter(js -> js.getTypes().stream().anyMatch(o -> o.isImplementing(SOLR_REPOSITORY_CLASS))) + .map(js -> js.getTypes().stream() + .filter(o -> o.isImplementing(SOLR_REPOSITORY_CLASS)) + .findFirst() + .map(o -> new JavaSourceAndType(js,o)) + .get() + ) + .collect(Collectors.toList()); + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositorySectionBuilder.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositorySectionBuilder.java new file mode 100644 index 000000000..e052f1a93 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositorySectionBuilder.java @@ -0,0 +1,67 @@ +/* + * 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.checks; + +import lombok.RequiredArgsConstructor; +import org.springframework.sbm.boot.asciidoctor.ChangeSection; +import org.springframework.sbm.boot.asciidoctor.Section; +import org.springframework.sbm.boot.asciidoctor.TodoList; +import org.springframework.sbm.boot.upgrade_27_30.Sbu30_UpgradeSectionBuilder; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.java.api.JavaSourceAndType; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class ApacheSolrRepositorySectionBuilder implements Sbu30_UpgradeSectionBuilder { + + private final ApacheSolrRepositoryBeanFinder finder; + + @Override + public boolean isApplicable(ProjectContext projectContext) { + return ! projectContext.search(finder).isEmpty(); + } + + @Override + public Section build(ProjectContext projectContext) { + List solrRepositories = projectContext.search(finder); + + return ChangeSection.RelevantChangeSection.builder() + .title("`Spring Data ApacheSolr` support has been removed") + .paragraph("Support for `Spring Data ApacheSolr` has been removed in Spring Framework 6") + .relevanceSection() + .paragraph("The scan found bean declarations of type `SolrCrudRepository`.") + .todoSection() + .paragraph("Remove repositories of type `SolrCrudRepository`") + .todoList(this.buildTodoList(solrRepositories)) + .build(); + } + + private TodoList buildTodoList(List solrRepositories) { + TodoList.TodoListBuilder todoListBuilder = TodoList.builder(); + solrRepositories.forEach(m -> { + todoListBuilder.todo( + TodoList.Todo.builder() + .text(String.format("Remove from class `%s`", m.getType().getFullyQualifiedName())) + .build() + ); + }); + return todoListBuilder.build(); + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositoryBeanFinderTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositoryBeanFinderTest.java new file mode 100644 index 000000000..ccb90de44 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositoryBeanFinderTest.java @@ -0,0 +1,57 @@ +package org.springframework.sbm.boot.upgrade_27_30.checks; + + +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.Test; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.java.api.JavaSourceAndType; +import org.springframework.sbm.java.api.Type; +import org.springframework.sbm.project.resource.TestProjectContext; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ApacheSolrRepositoryBeanFinderTest { + + @Language("java") + private static String SOLR_REPO = + """ + package foo.bar; + import org.springframework.data.solr.repository.SolrCrudRepository; + public class ProductRepository implements SolrCrudRepository {} + """; + + @Language("java") + private static String NO_SOLR_REPO = + """ + package foo.bar; + public class ProductRepository {} + """; + + @Test + public void givenModuleWithSolrRepository_find_expectNonEmptyList(){ + ProjectContext projectContext = TestProjectContext.buildProjectContext() + .withJavaSources(SOLR_REPO) + .withBuildFileHavingDependencies("org.springframework.data:spring-data-solr:4.3.15") + .build(); + + ApacheSolrRepositoryBeanFinder solrRepositoryBeanFinder = new ApacheSolrRepositoryBeanFinder(); + List solrRepositories = projectContext.search(solrRepositoryBeanFinder); + assertThat(solrRepositories).isNotEmpty(); + Type type = solrRepositories.get(0).getType(); + assertThat(type.getFullyQualifiedName()).isEqualTo("foo.bar.ProductRepository"); + } + + @Test + public void givenModuleWithoutSolrRepository_find_expectNonEmptyList(){ + ProjectContext projectContext = TestProjectContext.buildProjectContext() + .withJavaSources(NO_SOLR_REPO) + .withBuildFileHavingDependencies("org.springframework.data:spring-data-solr:4.3.15") + .build(); + + ApacheSolrRepositoryBeanFinder solrRepositoryBeanFinder = new ApacheSolrRepositoryBeanFinder(); + List solrRepositories = projectContext.search(solrRepositoryBeanFinder); + assertThat(solrRepositories).isEmpty(); + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositorySectionBuilderTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositorySectionBuilderTest.java new file mode 100644 index 000000000..d49207fce --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/checks/ApacheSolrRepositorySectionBuilderTest.java @@ -0,0 +1,79 @@ +/* + * 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.checks; + +import org.junit.jupiter.api.Test; +import org.springframework.sbm.boot.asciidoctor.Section; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.java.api.JavaSource; +import org.springframework.sbm.java.api.JavaSourceAndType; +import org.springframework.sbm.java.api.Type; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ApacheSolrRepositorySectionBuilderTest { + + @Test + void givenAContextWithSolrRepository_applySectionBuilder_validateReport() { + ApacheSolrRepositoryBeanFinder finder = mock(ApacheSolrRepositoryBeanFinder.class); + + Type type = mock(Type.class); + Type type1 = mock(Type.class); + JavaSource javaSource = mock(JavaSource.class); + JavaSource javaSource1 = mock(JavaSource.class); + JavaSourceAndType javaSourceAndType = new JavaSourceAndType(javaSource,type); + JavaSourceAndType javaSourceAndType1 = new JavaSourceAndType(javaSource1,type1); + + ProjectContext context = mock(ProjectContext.class); + ApacheSolrRepositorySectionBuilder sut = new ApacheSolrRepositorySectionBuilder(finder); + List matches = List.of( + javaSourceAndType, + javaSourceAndType1 + ); + + when(context.search(finder)).thenReturn(matches); + when(type.getFullyQualifiedName()).thenReturn("com.foo.bar.SomeClass"); + when(type1.getFullyQualifiedName()).thenReturn("com.foo.baz.AnotherClass"); + + Section section = sut.build(context); + + String rendered = SectionRendererTestUtil.render(section); + assertThat(rendered).isEqualTo( + """ + === `Spring Data ApacheSolr` support has been removed + Support for `Spring Data ApacheSolr` has been removed in Spring Framework 6 + + ==== Relevance + + The scan found bean declarations of type `SolrCrudRepository`. + + ==== Todo + + Remove repositories of type `SolrCrudRepository` + + + * [ ] Remove from class `com.foo.bar.SomeClass` + * [ ] Remove from class `com.foo.baz.AnotherClass` + """ + ); + } + +} \ No newline at end of file