diff --git a/applications/spring-shell/src/test/java/org/springframework/sbm/IntegrationTestBaseClass.java b/applications/spring-shell/src/test/java/org/springframework/sbm/IntegrationTestBaseClass.java index 6ec62b7f7..db48fcef7 100644 --- a/applications/spring-shell/src/test/java/org/springframework/sbm/IntegrationTestBaseClass.java +++ b/applications/spring-shell/src/test/java/org/springframework/sbm/IntegrationTestBaseClass.java @@ -319,8 +319,16 @@ protected void replaceFile(Path target, Path source) { } protected String loadJavaFileFromSubmodule(String submodulePath, String packageName, String className) { + return loadJavaFileFromModule(submodulePath, packageName, className, "src/main/java"); + } + + protected String loadTestJavaFileFromSubmodule(String submodulePath, String packageName, String className) { + return loadJavaFileFromModule(submodulePath, packageName, className, "src/test/java"); + } + + private String loadJavaFileFromModule(String submodulePath, String packageName, String className, String sourceDir) { try { - Path classPath = testDir.resolve(submodulePath + "src/main/java").resolve(packageName.replace(".", "/")); + Path classPath = testDir.resolve(submodulePath + sourceDir).resolve(packageName.replace(".", "/")); Path classFile = classPath.resolve(className + ".java"); return Files.readString(classFile); } catch (IOException e) { @@ -328,10 +336,15 @@ protected String loadJavaFileFromSubmodule(String submodulePath, String packageN } } + protected String loadJavaFile(String packageName, String className) { return loadJavaFileFromSubmodule("", packageName, className); } + protected String loadTestJavaFile(String packageName, String className) { + return loadTestJavaFileFromSubmodule("", packageName, className); + } + /** * Starts {@code image} as Docker container exposing {@code ports} and waiting for {@code httpEndpoint} to be available. */ diff --git a/applications/spring-shell/src/test/java/org/springframework/sbm/MigrateJpaApplicationIntegrationTest.java b/applications/spring-shell/src/test/java/org/springframework/sbm/MigrateJpaApplicationIntegrationTest.java index e3ba9d176..03dc23856 100644 --- a/applications/spring-shell/src/test/java/org/springframework/sbm/MigrateJpaApplicationIntegrationTest.java +++ b/applications/spring-shell/src/test/java/org/springframework/sbm/MigrateJpaApplicationIntegrationTest.java @@ -18,6 +18,8 @@ import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + public class MigrateJpaApplicationIntegrationTest extends IntegrationTestBaseClass { @Override @@ -41,7 +43,47 @@ void migrateJpaApplication() { "migrate-stateless-ejb", "migrate-jpa-to-spring-boot" ); - // TODO: add assertions + + assertThat(super.loadJavaFile("org.superbiz.injection.h3jpa", "SpringBootApp")).isNotEmpty(); + assertThat(super.loadTestJavaFile("org.superbiz.injection.h3jpa", "SpringBootAppTest")).isNotEmpty(); + String movies = loadJavaFile("org.superbiz.injection.h3jpa", "Movies"); + assertThat(movies).contains( + """ + package org.superbiz.injection.h3jpa; + + import org.springframework.stereotype.Service; + import org.springframework.transaction.annotation.Transactional; + + import javax.persistence.EntityManager; + import javax.persistence.PersistenceContext; + import javax.persistence.Query; + import java.util.List; + + @Service + @Transactional + public class Movies { + + @PersistenceContext(unitName = "default") + private EntityManager entityManager; + + public void addMovie(Movie movie) throws Exception { + entityManager.persist(movie); + } + + public void deleteMovie(Movie movie) throws Exception { + movie = entityManager.find(Movie.class, movie.getId()); + entityManager.remove(movie); + } + + public List getMovies() throws Exception { + Query query = entityManager.createQuery("SELECT m from Movie as m"); + return query.getResultList(); + } + + } + """ + ); + } } diff --git a/applications/spring-shell/src/test/resources/testcode/jpa-hibernate/src/main/java/org/superbiz/injection/h3jpa/Movies.java b/applications/spring-shell/src/test/resources/testcode/jpa-hibernate/src/main/java/org/superbiz/injection/h3jpa/Movies.java index bef87a4e2..97fb3961e 100644 --- a/applications/spring-shell/src/test/resources/testcode/jpa-hibernate/src/main/java/org/superbiz/injection/h3jpa/Movies.java +++ b/applications/spring-shell/src/test/resources/testcode/jpa-hibernate/src/main/java/org/superbiz/injection/h3jpa/Movies.java @@ -26,7 +26,7 @@ @Stateless public class Movies { - @PersistenceContext(unitName = "movie-unit" /*, type = PersistenceContextType.EXTENDED*/) + @PersistenceContext(unitName = "movie-unit") private EntityManager entityManager; public void addMovie(Movie movie) throws Exception { diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/ClasspathRegistry.java b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/ClasspathRegistry.java index 8590fffe5..f605a89b8 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/ClasspathRegistry.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/ClasspathRegistry.java @@ -149,18 +149,11 @@ private void initDependency(ResolvedDependency d, Map. if(dependencyPath != null) { Stream.of(maps).forEach(m -> m.put(d, dependencyPath)); } else { - System.out.println(d.getGav() + " has no jars. It has type " + d.getType()); initializeDepeendencies(new HashSet<>(d.getDependencies())); } } else { initializeDepeendencies(new HashSet(d.getDependencies())); } - - -// Optional dependencyPath = dependencyHelper.downloadArtifact(d); -// if (dependencyPath.isPresent()) { -// Stream.of(maps).forEach(m -> m.put(d, dependencyPath.get())); -// } } private boolean isExternalDependency(ResolvedDependency d) { diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteAnnotation.java b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteAnnotation.java index f21ec89b0..f6be12445 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteAnnotation.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteAnnotation.java @@ -15,11 +15,11 @@ */ package org.springframework.sbm.java.impl; +import org.openrewrite.java.AddOrUpdateAnnotationAttribute; import org.openrewrite.java.JavaParser; import org.springframework.sbm.java.api.Annotation; import org.springframework.sbm.java.api.Expression; import org.springframework.sbm.java.refactoring.JavaRefactoring; -import org.springframework.sbm.support.openrewrite.java.AddOrReplaceAnnotationAttribute; import lombok.Getter; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.tree.J; @@ -79,8 +79,8 @@ public boolean hasAttribute(String attribute) { @Override public void setAttribute(String attribute, Object value, Class valueType) { - AddOrReplaceAnnotationAttribute visitor = new AddOrReplaceAnnotationAttribute(() -> javaParser, wrapped, attribute, value, valueType); - refactoring.refactor(visitor); + AddOrUpdateAnnotationAttribute recipe = new AddOrUpdateAnnotationAttribute(this.getFullyQualifiedName(), attribute, value.toString(), false); + refactoring.refactor(recipe); } @Override diff --git a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/java/AddOrReplaceAnnotationAttributeTest.java b/components/sbm-openrewrite/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java similarity index 60% rename from components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/java/AddOrReplaceAnnotationAttributeTest.java rename to components/sbm-openrewrite/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java index c67e16fe4..29e57d885 100644 --- a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/java/AddOrReplaceAnnotationAttributeTest.java +++ b/components/sbm-openrewrite/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java @@ -13,18 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.sbm.support.openrewrite.java; +package org.openrewrite.java; +import org.openrewrite.java.AddOrUpdateAnnotationAttribute; +import org.openrewrite.java.tree.JavaType; import org.springframework.sbm.java.OpenRewriteTestSupport; import org.junit.jupiter.api.Test; -import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.tree.J; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; -public class AddOrReplaceAnnotationAttributeTest { +public class AddOrUpdateAnnotationAttributeTest { @Test @@ -33,9 +35,9 @@ void addBooleanAttributeToAnnotationWithoutAttributes() { J.CompilationUnit compilationUnit = OpenRewriteTestSupport.createCompilationUnit(code); J.Annotation annotation = compilationUnit.getClasses().get(0).getLeadingAnnotations().get(0); - JavaIsoVisitor javaIsoVisitor = new AddOrReplaceAnnotationAttribute(annotation, "forRemoval", true, Boolean.class); + AddOrUpdateAnnotationAttribute javaIsoVisitor = new AddOrUpdateAnnotationAttribute(((JavaType.Class)annotation.getType()).getFullyQualifiedName(), "forRemoval", "true", true); - String refactoredCu = javaIsoVisitor.visit(compilationUnit, new InMemoryExecutionContext()).print(); + String refactoredCu = javaIsoVisitor.run(List.of(compilationUnit), new InMemoryExecutionContext()).getResults().get(0).getAfter().printAll(); assertThat(refactoredCu).isEqualTo("@Deprecated(forRemoval = true) public class Foo {}"); } @@ -46,8 +48,8 @@ void addStringAttributeToAnnotationWithoutAttributes() { J.CompilationUnit compilationUnit = OpenRewriteTestSupport.createCompilationUnit(code); J.Annotation annotation = compilationUnit.getClasses().get(0).getLeadingAnnotations().get(0); - JavaIsoVisitor javaIsoVisitor = new AddOrReplaceAnnotationAttribute(annotation, "since", "2020", String.class); - String refactoredCu = javaIsoVisitor.visit(compilationUnit, new InMemoryExecutionContext()).print(); + AddOrUpdateAnnotationAttribute javaIsoVisitor = new AddOrUpdateAnnotationAttribute(((JavaType.Class)annotation.getType()).getFullyQualifiedName(), "since", "2020", true); + String refactoredCu = javaIsoVisitor.run(List.of(compilationUnit), new InMemoryExecutionContext()).getResults().get(0).getAfter().printAll(); assertThat(refactoredCu).isEqualTo("@Deprecated(since = \"2020\") public class Foo {}"); } @@ -57,8 +59,8 @@ void changeAnnotationAttributeValue() { String code = "@Deprecated(forRemoval = false) public class Foo {}"; J.CompilationUnit compilationUnit = OpenRewriteTestSupport.createCompilationUnit(code); J.Annotation annotation = compilationUnit.getClasses().get(0).getLeadingAnnotations().get(0); - JavaIsoVisitor javaIsoVisitor = new AddOrReplaceAnnotationAttribute(annotation, "forRemoval", true, Boolean.class); - String refactoredCu = javaIsoVisitor.visit(compilationUnit, new InMemoryExecutionContext()).print(); + AddOrUpdateAnnotationAttribute javaIsoVisitor = new AddOrUpdateAnnotationAttribute(((JavaType.Class)annotation.getType()).getFullyQualifiedName(), "forRemoval", "true", false); + String refactoredCu = javaIsoVisitor.run(List.of(compilationUnit), new InMemoryExecutionContext()).getResults().get(0).getAfter().printAll(); assertThat(refactoredCu).isEqualTo("@Deprecated(forRemoval = true) public class Foo {}"); } @@ -67,8 +69,8 @@ void changeAnnotationAttributeValueOfAnnotationWithAttributes() { String code = "@Deprecated(forRemoval = false, since = \"2020\") public class Foo {}"; J.CompilationUnit compilationUnit = OpenRewriteTestSupport.createCompilationUnit(code); J.Annotation annotation = compilationUnit.getClasses().get(0).getLeadingAnnotations().get(0); - JavaIsoVisitor javaIsoVisitor = new AddOrReplaceAnnotationAttribute(annotation, "forRemoval", true, Boolean.class); - String refactoredCu = javaIsoVisitor.visit(compilationUnit, new InMemoryExecutionContext()).print(); + AddOrUpdateAnnotationAttribute javaIsoVisitor = new AddOrUpdateAnnotationAttribute(((JavaType.Class)annotation.getType()).getFullyQualifiedName(), "forRemoval", "true", false); + String refactoredCu = javaIsoVisitor.run(List.of(compilationUnit), new InMemoryExecutionContext()).getResults().get(0).getAfter().printAll(); assertThat(refactoredCu).isEqualTo("@Deprecated(forRemoval = true, since = \"2020\") public class Foo {}"); } @@ -77,8 +79,8 @@ void changeAnnotationAttributeValueOfAnnotationWithAttributes2() { String code = "@Deprecated(since = \"2020\", forRemoval = false) public class Foo {}"; J.CompilationUnit compilationUnit = OpenRewriteTestSupport.createCompilationUnit(code); J.Annotation annotation = compilationUnit.getClasses().get(0).getLeadingAnnotations().get(0); - JavaIsoVisitor javaIsoVisitor = new AddOrReplaceAnnotationAttribute(annotation, "forRemoval", true, Boolean.class); - String refactoredCu = javaIsoVisitor.visit(compilationUnit, new InMemoryExecutionContext()).print(); + AddOrUpdateAnnotationAttribute javaIsoVisitor = new AddOrUpdateAnnotationAttribute(((JavaType.Class)annotation.getType()).getFullyQualifiedName(), "forRemoval", "true", false); + String refactoredCu = javaIsoVisitor.run(List.of(compilationUnit), new InMemoryExecutionContext()).getResults().get(0).getAfter().printAll(); assertThat(refactoredCu).isEqualTo("@Deprecated(since = \"2020\", forRemoval = true) public class Foo {}"); } @@ -87,9 +89,9 @@ void addAttributeToAnnotationWithAttributes() { String code = "@Deprecated(forRemoval = true) public class Foo {}"; J.CompilationUnit compilationUnit = OpenRewriteTestSupport.createCompilationUnit(code); J.Annotation annotation = compilationUnit.getClasses().get(0).getLeadingAnnotations().get(0); - JavaIsoVisitor javaIsoVisitor = new AddOrReplaceAnnotationAttribute(annotation, "since", "2020", String.class); - String refactoredCu = javaIsoVisitor.visit(compilationUnit, new InMemoryExecutionContext()).print(); - assertThat(refactoredCu).isEqualTo("@Deprecated(forRemoval = true, since = \"2020\") public class Foo {}"); + AddOrUpdateAnnotationAttribute javaIsoVisitor = new AddOrUpdateAnnotationAttribute(((JavaType.Class)annotation.getType()).getFullyQualifiedName(), "since", "2020", false); + String refactoredCu = javaIsoVisitor.run(List.of(compilationUnit), new InMemoryExecutionContext()).getResults().get(0).getAfter().printAll(); + assertThat(refactoredCu).isEqualTo("@Deprecated(since = \"2020\", forRemoval = true) public class Foo {}"); } diff --git a/components/sbm-recipes-jee-to-boot/src/main/java/org/springframework/sbm/jee/jpa/actions/RenameUnitNameOfPersistenceContextAnnotationsToDefault.java b/components/sbm-recipes-jee-to-boot/src/main/java/org/springframework/sbm/jee/jpa/actions/RenameUnitNameOfPersistenceContextAnnotationsToDefault.java new file mode 100644 index 000000000..cc75a061b --- /dev/null +++ b/components/sbm-recipes-jee-to-boot/src/main/java/org/springframework/sbm/jee/jpa/actions/RenameUnitNameOfPersistenceContextAnnotationsToDefault.java @@ -0,0 +1,55 @@ +/* + * 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.jee.jpa.actions; + +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.engine.recipe.AbstractAction; +import org.springframework.sbm.java.api.JavaSource; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Fabian Krüger + */ +public class RenameUnitNameOfPersistenceContextAnnotationsToDefault extends AbstractAction { + + public static final String PERSISTENCE_CONTEXT = "javax.persistence.PersistenceContext"; + + @Override + public void apply(ProjectContext context) { + List javaSources = context + .getProjectJavaSources() + .asStream() + .filter(s -> s + .getTypes() + .stream() + .flatMap(t -> t.getMembers().stream()) + .anyMatch(m -> m.hasAnnotation(PERSISTENCE_CONTEXT))) + .collect(Collectors.toList()); + + javaSources.forEach(s -> { + s.getTypes() + .stream() + .flatMap(t -> t.getMembers().stream()) + .filter(m -> m.hasAnnotation(PERSISTENCE_CONTEXT)) + .map(m -> m.getAnnotation(PERSISTENCE_CONTEXT)) + .findFirst() + .get() + .setAttribute("unitName", "default", String.class); + }); + } +} diff --git a/components/sbm-recipes-jee-to-boot/src/main/resources/recipes/migrate-jpa-to-spring-boot.yaml b/components/sbm-recipes-jee-to-boot/src/main/resources/recipes/migrate-jpa-to-spring-boot.yaml index 6865d7587..2d1a49e5a 100644 --- a/components/sbm-recipes-jee-to-boot/src/main/resources/recipes/migrate-jpa-to-spring-boot.yaml +++ b/components/sbm-recipes-jee-to-boot/src/main/resources/recipes/migrate-jpa-to-spring-boot.yaml @@ -88,3 +88,9 @@ condition: type: org.springframework.sbm.common.migration.conditions.TrueCondition pattern: '/**/persistence.xml' + + - type: org.springframework.sbm.jee.jpa.actions.RenameUnitNameOfPersistenceContextAnnotationsToDefault + description: Set 'unitName' attribute from @PersistenceContext annotations to 'default' when different + condition: + type: org.springframework.sbm.java.migration.conditions.HasMemberAnnotation + annotation: javax.persistence.PersistenceContext diff --git a/components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jpa/actions/RenameUnitNameOfPersistenceContextAnnotationsToDefaultTest.java b/components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jpa/actions/RenameUnitNameOfPersistenceContextAnnotationsToDefaultTest.java new file mode 100644 index 000000000..0d069257c --- /dev/null +++ b/components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jpa/actions/RenameUnitNameOfPersistenceContextAnnotationsToDefaultTest.java @@ -0,0 +1,61 @@ +/* + * 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.jee.jpa.actions; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.project.resource.TestProjectContext; + +/** + * @author Fabian Krüger + */ +class RenameUnitNameOfPersistenceContextAnnotationsToDefaultTest { + @Test + void shouldRemoveUnitNameAttribute() { + + String javaCode = """ + import javax.persistence.PersistenceContext; + import javax.persistence.EntityManager; + public class Foo { + @PersistenceContext(unitName = "foo") + private EntityManager entityManager; + } + """; + + ProjectContext context = TestProjectContext + .buildProjectContext() + .addJavaSource("src/main/java", javaCode) + .withBuildFileHavingDependencies("javax.persistence:javax.persistence-api:2.2", "javax.ejb:javax.ejb-api:3.2") + .build(); + + RenameUnitNameOfPersistenceContextAnnotationsToDefault sut = new RenameUnitNameOfPersistenceContextAnnotationsToDefault(); + + sut.apply(context); + + String expected = """ + import javax.persistence.PersistenceContext; + import javax.persistence.EntityManager; + public class Foo { + @PersistenceContext(unitName = "default") + private EntityManager entityManager; + } + """; + + + Assertions.assertThat(context.getProjectJavaSources().list().get(0).print()).isEqualTo(expected); + } +} \ No newline at end of file diff --git a/components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jpa/recipes/MigrateJpaToSpringBootRecipeTest.java b/components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jpa/recipes/MigrateJpaToSpringBootRecipeTest.java index b42831ff7..1f4f97ee8 100644 --- a/components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jpa/recipes/MigrateJpaToSpringBootRecipeTest.java +++ b/components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jpa/recipes/MigrateJpaToSpringBootRecipeTest.java @@ -28,6 +28,7 @@ import org.springframework.sbm.jee.jpa.actions.MigratePersistenceXmlToApplicationPropertiesAction; import freemarker.template.Configuration; import org.junit.jupiter.api.Test; +import org.springframework.sbm.jee.jpa.actions.RenameUnitNameOfPersistenceContextAnnotationsToDefault; import java.nio.file.Path; import java.util.List; @@ -53,7 +54,9 @@ void migrateJpaToSpringBootRecipe() { RemoveDependenciesMatchingRegex.class, AddTypeAnnotationToTypeAnnotatedWith.class, MigrateEclipseLinkToSpringBoot.class, - DeleteFileMatchingPattern.class); + DeleteFileMatchingPattern.class, + RenameUnitNameOfPersistenceContextAnnotationsToDefault.class + ); assertThatRecipeHasCondition(recipe, FileExist.class); // Action: migrate persistence.xml to Spring application.properties diff --git a/components/sbm-support-weblogic/src/test/java/org/springframework/sbm/jee/wls/actions/MigrateWlsEjbDeploymentDescriptorTest.java b/components/sbm-support-weblogic/src/test/java/org/springframework/sbm/jee/wls/actions/MigrateWlsEjbDeploymentDescriptorTest.java index 5d8f7796e..6ef35d2dd 100644 --- a/components/sbm-support-weblogic/src/test/java/org/springframework/sbm/jee/wls/actions/MigrateWlsEjbDeploymentDescriptorTest.java +++ b/components/sbm-support-weblogic/src/test/java/org/springframework/sbm/jee/wls/actions/MigrateWlsEjbDeploymentDescriptorTest.java @@ -152,7 +152,7 @@ void shouldOverwriteTimeoutIfAttributeExist() { "import javax.ejb.Stateless;\n" + "import org.springframework.transaction.annotation.Transactional;\n" + "@Stateless(name=\"daFoo\")\n" + - "@Transactional(timeout = 200000)\n" + + "@Transactional(timeout=200000)\n" + "public class Foo {}" ); }