diff --git a/components/openrewrite-spring-recipes/src/main/java/org/springframework/sbm/OrRecipesConfig.java b/components/openrewrite-spring-recipes/src/main/java/org/springframework/sbm/OrRecipesConfig.java index 3ab742341..d1f15532c 100644 --- a/components/openrewrite-spring-recipes/src/main/java/org/springframework/sbm/OrRecipesConfig.java +++ b/components/openrewrite-spring-recipes/src/main/java/org/springframework/sbm/OrRecipesConfig.java @@ -16,6 +16,7 @@ package org.springframework.sbm; import org.openrewrite.maven.AddPluginDependency; +import org.openrewrite.maven.UpdateMavenModel; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.sbm.build.impl.OpenRewriteMavenBuildFile; @@ -25,6 +26,7 @@ import org.springframework.sbm.engine.recipe.Condition; import org.springframework.sbm.engine.recipe.Recipe; import org.springframework.sbm.spring.migration.actions.OpenRewriteRecipeAdapterAction; +import org.springframework.sbm.support.openrewrite.GenericOpenRewriteRecipe; import java.lang.reflect.InvocationTargetException; import java.util.List; @@ -69,7 +71,7 @@ Recipe recipeSpringBoot1To2Migration(RewriteRecipesRepository repo) { r.doNext(new RemoveMavenPlugin("org.codehaus.mojo", "cobertura-maven-plugin")); r.doNext(new AddPluginDependency("ro.isdc.wro4j", "wro4j-maven-plugin", "org.mockito", "mockito-core", "${mockito.version}")); - r.doNext(new OpenRewriteMavenBuildFile.RefreshPomModel()); + r.doNext(new GenericOpenRewriteRecipe<>(() -> new UpdateMavenModel<>())); AnyDeclaredDependencyExistMatchingRegex condition = new AnyDeclaredDependencyExistMatchingRegex(); condition.setDependencies(List.of("org\\.springframework\\.boot:.*:1\\..*")); diff --git a/components/openrewrite-spring-recipes/src/test/java/org/springframework/sbm/SpringBoot23To24MigrationTest.java b/components/openrewrite-spring-recipes/src/test/java/org/springframework/sbm/SpringBoot23To24MigrationTest.java index 211b52407..9e37afe1e 100644 --- a/components/openrewrite-spring-recipes/src/test/java/org/springframework/sbm/SpringBoot23To24MigrationTest.java +++ b/components/openrewrite-spring-recipes/src/test/java/org/springframework/sbm/SpringBoot23To24MigrationTest.java @@ -115,7 +115,7 @@ public void recipeUpdatesBootDependenciesAndParentVersion() throws IOException { List resources = List.of(); - ProjectContext projectContext = contextInitializer.initProjectContext(Path.of("./testcode/boot-23-app/given"), resources, new RewriteExecutionContext()); + ProjectContext projectContext = contextInitializer.initProjectContext(Path.of("./testcode/boot-23-app/given"), resources); projectContext.getApplicationModules().getRootModule().getMainResourceSet().addStringResource("src/main/resources/data.sql", "# Empty file"); diff --git a/components/recipe-test-support/src/main/java/org/springframework/sbm/test/ProjectContextFileSystemTestSupport.java b/components/recipe-test-support/src/main/java/org/springframework/sbm/test/ProjectContextFileSystemTestSupport.java index 40d43d919..d602663e6 100644 --- a/components/recipe-test-support/src/main/java/org/springframework/sbm/test/ProjectContextFileSystemTestSupport.java +++ b/components/recipe-test-support/src/main/java/org/springframework/sbm/test/ProjectContextFileSystemTestSupport.java @@ -65,7 +65,7 @@ public static ProjectContext createProjectContextFromDir(String projectRootDir, ProjectContextInitializer projectContextBuilder = ctx.getBean(ProjectContextInitializer.class); ScanCommand scanCommand = ctx.getBean(ScanCommand.class); List resources = scanCommand.scanProjectRoot(to.toString()); - ProjectContext projectContext = projectContextBuilder.initProjectContext(projectRoot, resources, new RewriteExecutionContext()); + ProjectContext projectContext = projectContextBuilder.initProjectContext(projectRoot, resources); projectContextHolder.setContext(projectContext); }, beanClasses.toArray(new Class[]{}) diff --git a/components/recipe-test-support/src/main/java/org/springframework/sbm/test/RecipeTestSupport.java b/components/recipe-test-support/src/main/java/org/springframework/sbm/test/RecipeTestSupport.java index f56bb81f8..11735df9f 100644 --- a/components/recipe-test-support/src/main/java/org/springframework/sbm/test/RecipeTestSupport.java +++ b/components/recipe-test-support/src/main/java/org/springframework/sbm/test/RecipeTestSupport.java @@ -16,6 +16,7 @@ package org.springframework.sbm.test; import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.sbm.build.impl.MavenBuildFileRefactoringFactory; import org.springframework.sbm.build.impl.MavenSettingsInitializer; import org.springframework.sbm.build.impl.RewriteMavenParser; import org.springframework.sbm.engine.context.ProjectContextHolder; @@ -24,6 +25,7 @@ import org.springframework.sbm.java.impl.RewriteJavaParser; import org.springframework.sbm.java.util.BasePackageCalculator; import org.springframework.sbm.project.RewriteSourceFileWrapper; +import org.springframework.sbm.project.resource.ProjectResourceSetHolder; import org.springframework.sbm.project.resource.SbmApplicationProperties; import org.springframework.sbm.project.resource.ResourceHelper; import org.springframework.sbm.search.recipe.actions.OpenRewriteJavaSearchAction; @@ -73,7 +75,9 @@ private RecipeTestSupport() { BasePackageCalculator.class, ProjectContextHolder.class, RewriteMavenParser.class, - MavenSettingsInitializer.class + MavenSettingsInitializer.class, + MavenBuildFileRefactoringFactory.class, + ProjectResourceSetHolder.class }; diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/api/BuildFile.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/api/BuildFile.java index 921e6a36c..ed60635e8 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/api/BuildFile.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/api/BuildFile.java @@ -21,7 +21,6 @@ import java.nio.file.Path; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; @@ -87,7 +86,9 @@ public interface BuildFile extends ProjectResource { void removeDependenciesInner(List dependencies); - List getDependencyManagement(); + List getEffectiveDependencyManagement(); + + List getRequestedDependencyManagement(); List getRequestedManagedDependencies(); @@ -115,6 +116,9 @@ public interface BuildFile extends ProjectResource { Path getMainResourceFolder(); + /** + * Sets existing property or adds new property. + */ void setProperty(String key, String value); String getProperty(String key); diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/api/SpringManagedDependencies.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/api/SpringManagedDependencies.java index e24136e6f..46ad55ab6 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/api/SpringManagedDependencies.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/api/SpringManagedDependencies.java @@ -15,6 +15,7 @@ */ package org.springframework.sbm.build.api; +import org.openrewrite.maven.MavenDownloadingException; import org.openrewrite.maven.internal.MavenPomDownloader; import org.openrewrite.maven.tree.GroupArtifactVersion; import org.openrewrite.maven.tree.MavenRepository; @@ -32,7 +33,7 @@ public class SpringManagedDependencies { private static List SPRING_REPOSITORIES = List.of( - new MavenRepository("spring-release", "https://repo.spring.io/release", true, false, null, null) + new MavenRepository("spring-release", "https://repo.spring.io/release", "true", "false", true, null, null, null) ); private List dependencies; @@ -47,9 +48,13 @@ public static SpringManagedDependencies by(String groupId, String artifact, Stri } private SpringManagedDependencies(GroupArtifactVersion groupArtifactVersion){ - dependencies = new MavenPomDownloader(Collections.emptyMap(), new RewriteExecutionContext()) - .download(groupArtifactVersion, null, null, SPRING_REPOSITORIES) - .getDependencies(); + try { + dependencies = new MavenPomDownloader(Collections.emptyMap(), new RewriteExecutionContext()) + .download(groupArtifactVersion, null, null, SPRING_REPOSITORIES) + .getDependencies(); + } catch (MavenDownloadingException e) { + throw new RuntimeException(e); + } } public Stream stream(){ diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/MavenBuildFileRefactoring.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/MavenBuildFileRefactoring.java index e02836802..d33a3c86d 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/MavenBuildFileRefactoring.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/MavenBuildFileRefactoring.java @@ -15,25 +15,43 @@ */ package org.springframework.sbm.build.impl; +import lombok.Getter; import lombok.RequiredArgsConstructor; -import org.openrewrite.Recipe; -import org.openrewrite.Result; -import org.openrewrite.maven.MavenParser; +import org.jetbrains.annotations.NotNull; +import org.openrewrite.*; +import org.openrewrite.marker.Markers; +import org.openrewrite.marker.SearchResult; import org.openrewrite.maven.MavenVisitor; +import org.openrewrite.maven.tree.MavenResolutionResult; import org.openrewrite.xml.tree.Xml; import org.springframework.sbm.openrewrite.RewriteExecutionContext; +import org.springframework.sbm.project.resource.ProjectResourceSet; import org.springframework.sbm.project.resource.RewriteSourceFileHolder; import org.springframework.sbm.support.openrewrite.GenericOpenRewriteRecipe; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +/** + * This class provides a facade to apply OpenRewrite {@code Recipe}s and {@code Visitor}s to the project Maven build files. + * + * @author Fabian Krüger + */ @RequiredArgsConstructor -class MavenBuildFileRefactoring

{ - - private final RewriteSourceFileHolder pom; +public class MavenBuildFileRefactoring { + private final ProjectResourceSet projectResourceSet; + private final RewriteMavenParser mavenParser; + /** + * Applies the provided {@code Visitor}s to all Maven build files in the {@code ProjectContext}. + * + * The changes are immediately reflected in the wrapping {@code BuildFile}s. + */ public void execute(MavenVisitor... visitors) { List results = Arrays.stream(visitors) .map(v -> new GenericOpenRewriteRecipe(() -> v)) @@ -43,32 +61,136 @@ public void execute(MavenVisitor... visitors) { processResults(results); } - public void execute(Recipe... visitors) { - for (Recipe recipe : visitors) { + /** + * Applies the provided {@code Recipe}s to all Maven build files in the {@code ProjectContext}. + * + * The changes are immediately reflected in the wrapping {@code BuildFile}s. + */ + public void execute(Recipe... recipes) { + for (Recipe recipe : recipes) { List results = executeRecipe(recipe); processResults(results); } } + /** + * Applies the provided {@code Recipe}s to the provided Maven build file. + * + * The changes are immediately reflected in the wrapping {@code BuildFile}. + * A caller must decide if refreshing the Pom files in {@code ProjectContext} is required after this method. + */ + public > void execute(RewriteSourceFileHolder resource, Recipe... recipes) { + for (Recipe recipe : recipes) { + List results = executeRecipe(recipe, resource); + processResults(results); + } + } + + public void refreshPomModels() { + // store buildfiles and their index in project resource list + List buildFilesWithIndex = new ArrayList<>(); + List> projectResources = projectResourceSet.list(); + for(RewriteSourceFileHolder sf : projectResources) { + if(isMavenBuildFile(sf)) { + int index = projectResources.indexOf(sf); + Xml.Document xmlDoc = (Xml.Document) sf.getSourceFile(); + buildFilesWithIndex.add(new BuildFileWithIndex(index, (RewriteSourceFileHolder) sf)); + } + } + + // create parser inputs from buildfiles content + List parserInputs = buildFilesWithIndex + .stream() + .map(BuildFileWithIndex::getXmlDoc) + .map(m -> new Parser.Input(m.getSourcePath(), null, () -> new ByteArrayInputStream( + m.print().getBytes(StandardCharsets.UTF_8)), !Files.exists(m.getSourcePath()))) + .collect(Collectors.toList()); + + // parse buildfiles + List newMavenFiles = mavenParser.parseInputs(parserInputs, null, new RewriteExecutionContext()); + + // replace new model in build files + newMavenFiles.stream() + .forEach(mf -> { + replaceModelInBuildFile(projectResources, buildFilesWithIndex, newMavenFiles, mf); + }); + } + + private void replaceModelInBuildFile( + List> projectResources, + List buildFilesWithIndex, + List newMavenFiles, + Xml.Document mf + ) { + // get index in list of build files + int indexInNewMavenFiles = newMavenFiles.indexOf(mf); + RewriteSourceFileHolder originalPom = buildFilesWithIndex.get(indexInNewMavenFiles).getXmlDoc(); + int indexInProjectResources = projectResources.indexOf(originalPom); + // replace marker + Markers markers = originalPom.getSourceFile().getMarkers().removeByType(MavenResolutionResult.class); + MavenResolutionResult updatedModel = mf.getMarkers().findFirst(MavenResolutionResult.class).get(); + markers = markers.addIfAbsent(updatedModel); + Xml.Document refreshedPom = originalPom.getSourceFile().withMarkers(markers); + RewriteSourceFileHolder rewriteSourceFileHolder = (RewriteSourceFileHolder) projectResources.get(indexInProjectResources); + rewriteSourceFileHolder.replaceWith(refreshedPom); + } + + private boolean isMavenBuildFile(RewriteSourceFileHolder sf) { + return Xml.Document.class.isInstance(sf.getSourceFile()) && Xml.Document.class.cast(sf.getSourceFile()).getMarkers().findFirst(MavenResolutionResult.class).isPresent(); + } + + @Getter + class BuildFileWithIndex { + private final int index; + private final RewriteSourceFileHolder xmlDoc; + + public BuildFileWithIndex(int index, RewriteSourceFileHolder xmlDoc) { + + this.index = index; + this.xmlDoc = xmlDoc; + } + } + private List executeRecipe(Recipe recipe) { - List results = recipe.run(List.of(pom.getSourceFile()), new RewriteExecutionContext()).getResults(); + List results = recipe.run(getDocumentsWrappedInOpenRewriteMavenBuildFile(), new RewriteExecutionContext()).getResults(); + return results; + } + + private List executeRecipe(Recipe recipe, RewriteSourceFileHolder resource) { + List results = recipe.run(List.of(resource.getSourceFile()), new RewriteExecutionContext()).getResults(); return results; } + private List getDocumentsWrappedInOpenRewriteMavenBuildFile() { + return getOpenRewriteMavenBuildFiles() + .stream() + .map(bf -> bf.getSourceFile()) + .collect(Collectors.toList()); + } + + @NotNull + private List getOpenRewriteMavenBuildFiles() { + return this.projectResourceSet + .stream() + .filter(r -> OpenRewriteMavenBuildFile.class.isInstance(r)) + .map(OpenRewriteMavenBuildFile.class::cast) + .collect(Collectors.toList()); + } + private void processResults(List results) { if (!results.isEmpty()) { - // FIXME: Works only on a single POM and does not apply to all other resources - pom.replaceWith((Xml.Document) results.get(0).getAfter()); - // results.forEach(c -> processResult(c)); + results.forEach(r -> { + if(!(r.getAfter() instanceof Xml.Document)) { + throw new RuntimeException("Return type of refactoring result is not Xml.Document but " + r.getAfter().getClass() + " with content: \n" + r.getAfter().printAll()); + } + OpenRewriteMavenBuildFile openRewriteMavenBuildFile = getOpenRewriteMavenBuildFiles() + .stream() + .filter(bf -> bf.getSourceFile().getId().equals(r.getAfter().getId())) + .findFirst() + .orElseThrow(() -> new RuntimeException("Could not find a BuildFile that wraps Xml.Document with id '%s' in the Result.".formatted(r.getAfter().getId()))); + openRewriteMavenBuildFile.replaceWith((Xml.Document) r.getAfter()); + }); } } - private void processResult(Result result) { - MavenParser parser = MavenParser - .builder() - .build(); - Xml.Document wrappedMavenFile = parser.parse(result.getAfter().printAll()).get(0); - wrappedMavenFile = (Xml.Document) wrappedMavenFile.withSourcePath(pom.getSourceFile().getSourcePath()); - pom.replaceWith(wrappedMavenFile); - } } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/MavenBuildFileRefactoringFactory.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/MavenBuildFileRefactoringFactory.java new file mode 100644 index 000000000..a5ab0ca99 --- /dev/null +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/MavenBuildFileRefactoringFactory.java @@ -0,0 +1,35 @@ +/* + * 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.build.impl; + +import lombok.RequiredArgsConstructor; +import org.openrewrite.xml.tree.Xml; +import org.springframework.sbm.project.resource.ProjectResourceSetHolder; +import org.springframework.stereotype.Component; + +/** + * @author Fabian Krüger + */ +@Component +@RequiredArgsConstructor +public class MavenBuildFileRefactoringFactory { + private final ProjectResourceSetHolder projectResourceSetHolder; + private final RewriteMavenParser rewriteMavenParser; + + public MavenBuildFileRefactoring createRefactoring() { + return new MavenBuildFileRefactoring(projectResourceSetHolder.getProjectResourceSet(), rewriteMavenParser); + } +} diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenBuildFile.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenBuildFile.java index 3696fdb1f..322a0a118 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenBuildFile.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenBuildFile.java @@ -15,25 +15,14 @@ */ package org.springframework.sbm.build.impl; -import com.fasterxml.jackson.core.JsonProcessingException; import lombok.extern.slf4j.Slf4j; -import org.openrewrite.ExecutionContext; -import org.openrewrite.Parser; -import org.openrewrite.Recipe; -import org.openrewrite.Result; -import org.openrewrite.SourceFile; +import org.jetbrains.annotations.NotNull; +import org.openrewrite.*; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.marker.Markers; import org.openrewrite.maven.*; -import org.openrewrite.maven.internal.MavenXmlMapper; -import org.openrewrite.maven.tree.MavenResolutionResult; -import org.openrewrite.maven.tree.Parent; -import org.openrewrite.maven.tree.ResolvedDependency; -import org.openrewrite.maven.tree.ResolvedManagedDependency; -import org.openrewrite.maven.tree.Scope; -import org.openrewrite.xml.ChangeTagValueVisitor; +import org.openrewrite.maven.tree.*; import org.openrewrite.xml.tree.Xml; -import org.openrewrite.xml.tree.Xml.Tag; import org.springframework.context.ApplicationEventPublisher; import org.springframework.sbm.build.api.BuildFile; @@ -47,7 +36,6 @@ import org.springframework.sbm.build.migration.recipe.AddMavenPlugin; import org.springframework.sbm.build.migration.recipe.RemoveMavenPlugin; import org.springframework.sbm.build.migration.visitor.AddOrUpdateDependencyManagement; -import org.springframework.sbm.build.migration.visitor.AddProperty; import org.springframework.sbm.java.impl.ClasspathRegistry; import org.springframework.sbm.openrewrite.RewriteExecutionContext; import org.springframework.sbm.project.resource.RewriteSourceFileHolder; @@ -57,15 +45,8 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -76,9 +57,8 @@ public class OpenRewriteMavenBuildFile extends RewriteSourceFileHolder refactoring ; + private final MavenBuildFileRefactoring refactoring; - // TODO: #7 clarify if RefreshPomModel is still required? // Execute separately since RefreshPomModel caches the refreshed maven files after the first visit public static class RefreshPomModel extends Recipe { @@ -145,11 +125,12 @@ public String getDisplayName() { public OpenRewriteMavenBuildFile(Path absoluteProjectPath, Xml.Document sourceFile, ApplicationEventPublisher eventPublisher, - RewriteExecutionContext executionContext) { + RewriteExecutionContext executionContext, + MavenBuildFileRefactoring refactoring) { super(absoluteProjectPath, sourceFile); this.eventPublisher = eventPublisher; this.executionContext = executionContext; - this.refactoring = new MavenBuildFileRefactoring<>(this.getResource()); + this.refactoring = refactoring; } public void apply(Recipe recipe) { @@ -448,8 +429,8 @@ protected void addDependenciesInner(List dependencies) { if (!dependencies.isEmpty()) { Recipe r = getAddDependencyRecipe(dependencies.get(0)); dependencies.stream().skip(1).forEach(d -> r.doNext(getAddDependencyRecipe(d))); - apply(r); - apply(new RefreshPomModel()); + apply(r, getResource()); + refreshPomModel(); List exclusions = dependencies.stream() .filter(not(d -> d.getExclusions().isEmpty())) .flatMap(d -> d.getExclusions().stream()) @@ -461,6 +442,11 @@ protected void addDependenciesInner(List dependencies) { } } + private void refreshPomModel() { +// apply(new GenericOpenRewriteRecipe<>(() -> new UpdateMavenModel<>())); + refactoring.refreshPomModels(); + } + /** * Does not updateClasspathRegistry */ @@ -470,7 +456,7 @@ private void excludeDependenciesInner(List exclusions) { ExcludeDependency excludeDependency = new ExcludeDependency(excludedDependency.getGroupId(), excludedDependency.getArtifactId(), excludedDependency.getScope()); exclusions.stream().skip(1).forEach(d -> excludeDependency.doNext(new ExcludeDependency(d.getGroupId(), d.getArtifactId(), d.getScope()))); apply(excludeDependency); - apply(new RefreshPomModel()); // TODO: 482: check if required + refreshPomModel(); } } @@ -510,7 +496,7 @@ public void removeDependenciesInner(List dependencies) { r.doNext(getDeleteDependencyVisitor(d)); }); apply(r); - apply(new RefreshPomModel()); // TODO: Should be obsolete with 7.23.0, see https://github.com/openrewrite/rewrite/issues/1754 + refreshPomModel(); } } @@ -521,7 +507,7 @@ private Recipe getDeleteDependencyVisitor(Dependency dependency) { } @Override - public List getDependencyManagement() { + public List getEffectiveDependencyManagement() { MavenResolutionResult pom = getPom(); if (pom.getPom().getDependencyManagement() == null) { return Collections.emptyList(); @@ -532,6 +518,18 @@ public List getDependencyManagement() { .collect(Collectors.toList()); } + @Override + public List getRequestedDependencyManagement() { + MavenResolutionResult pom = getPom(); + if (pom.getPom().getRequested().getDependencyManagement() == null) { + return Collections.emptyList(); + } + return pom.getPom().getRequested().getDependencyManagement().stream() + .map(this::getDependency) + .distinct() + .collect(Collectors.toList()); + } + @Override public List getRequestedManagedDependencies() { return this.getPom().getPom().getRequested() @@ -554,12 +552,23 @@ private Dependency getDependency(ResolvedManagedDependency d) { .build(); } + private Dependency getDependency(ManagedDependency d) { + return Dependency.builder() + .groupId(d.getGroupId()) + .artifactId(d.getArtifactId()) + .version(d.getVersion()) + .build(); + } + @Override public void addToDependencyManagementInner(Dependency dependency) { AddOrUpdateDependencyManagement addOrUpdateDependencyManagement = new AddOrUpdateDependencyManagement(dependency); - apply(new GenericOpenRewriteRecipe<>(() -> addOrUpdateDependencyManagement)); - // Execute separately since RefreshPomModel caches the refreshed maven files after the first visit - apply(new RefreshPomModel()); + apply(new GenericOpenRewriteRecipe<>(() -> addOrUpdateDependencyManagement), getResource()); + refreshPomModel(); + } + + private > void apply(Recipe recipe, RewriteSourceFileHolder resource) { + refactoring.execute(resource, recipe); } // FIXME: #7 rework dependencies/classpath registry // collect declared dependencies (jar/pom) @@ -569,10 +578,16 @@ public void addToDependencyManagementInner(Dependency dependency) { public List getResolvedDependenciesPaths() { RewriteMavenArtifactDownloader rewriteMavenArtifactDownloader = new RewriteMavenArtifactDownloader(); return getPom().getDependencies().get(Scope.Provided).stream() - .map(rewriteMavenArtifactDownloader::downloadArtifact) + .filter(this::filterProjectDependencies) + .map(rd -> rewriteMavenArtifactDownloader.downloadArtifact(rd)) .collect(Collectors.toList()); } + @NotNull + private boolean filterProjectDependencies(ResolvedDependency rd) { + return rd.getRepository() != null; + } + @Override public boolean hasPlugin(Plugin plugin) { // TODO: [FK] discuss how to handle conditions. This code is exactly the same as in #AddMavenPluginVisitor.pluginDefinitionExists(Maven.Pom pom) which is private and the test would repeat the test for AddMavenPluginVisitor @@ -595,7 +610,7 @@ public boolean hasPlugin(Plugin plugin) { @Override public void addPlugin(Plugin plugin) { - apply(new AddMavenPlugin((OpenRewriteMavenPlugin) plugin)); + apply(new AddMavenPlugin((OpenRewriteMavenPlugin) plugin), getResource()); } @Override @@ -632,14 +647,15 @@ final public String getProperty(String key) { @Override final public void deleteProperty(String key){ - apply(new RemoveProperty(key)); - apply(new RefreshPomModel()); - } + apply(new RemoveProperty(key), getResource()); + refreshPomModel(); + } final public void setProperty(String key, String value) { String current = getProperty(key); - apply(current == null ? new ChangePropertyValue(key, value, true) : new ChangePropertyValue(key, value, false)); - apply(new RefreshPomModel()); + Recipe recipe = current == null ? new AddProperty(key, value, false, false) : new ChangePropertyValue(key, value, false, false); + apply(recipe, getResource()); + refreshPomModel(); } @Override @@ -733,10 +749,9 @@ public void excludeDependencies(List excludedDependencies) { @Override public void addRepository(RepositoryDefinition repository) { - Recipe recipe = new AddMavenRepository(repository) - .doNext(new RefreshPomModel()); - + Recipe recipe = new AddMavenRepository(repository); apply(recipe); + refreshPomModel(); } @Override @@ -751,8 +766,8 @@ public List getRepositories() { .map(r -> RepositoryDefinition.builder() .id(r.getId()) .url(r.getUri()) - .releasesEnabled(r.isReleases()) - .snapshotsEnabled(r.isSnapshots()) + .releasesEnabled("true".equalsIgnoreCase(r.getReleases())) + .snapshotsEnabled("true".equalsIgnoreCase(r.getSnapshots())) .build() ).collect(Collectors.toList()); } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenPlugin.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenPlugin.java index 9b93f9fb6..2ab7aa711 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenPlugin.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenPlugin.java @@ -157,8 +157,15 @@ private void changeConfiguration() { String configurationXml = MavenXmlMapper.writeMapper().writerWithDefaultPrettyPrinter() .writeValueAsString(configuration).replaceFirst("", "") .replace("", "").replace("", "").trim(); - OpenRewriteMavenPlugin.this.refactoring.execute(new ChangePluginConfiguration( - OpenRewriteMavenPlugin.this.groupId, OpenRewriteMavenPlugin.this.artifactId, configurationXml)); + OpenRewriteMavenPlugin.this.refactoring.execute( + OpenRewriteMavenPlugin.this.getResourceWrapper(), + new ChangePluginConfiguration( + OpenRewriteMavenPlugin.this.groupId, + OpenRewriteMavenPlugin.this.artifactId, + configurationXml + ) + ); + OpenRewriteMavenPlugin.this.refactoring.refreshPomModels(); } catch (JsonProcessingException e) { throw new RuntimeException(e); diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/RewriteMavenArtifactDownloader.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/RewriteMavenArtifactDownloader.java index 848e559eb..ce6d73dad 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/RewriteMavenArtifactDownloader.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/RewriteMavenArtifactDownloader.java @@ -52,7 +52,7 @@ public RewriteMavenArtifactDownloader() { .readTimeout(2, TimeUnit.SECONDS) .build() ), - (t) -> log.warn("Error while downloading dependencies", t) + (t) -> log.warn("Error while downloading dependencies: " + t.getMessage(), t) ); // super(new LocalMavenArtifactCache(Paths.get(System.getProperty("user.home"), ".m2", "repository")), diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddDependenciesToApplicationModules.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddDependenciesToApplicationModules.java index 4fa5b93b9..dae603208 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddDependenciesToApplicationModules.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddDependenciesToApplicationModules.java @@ -27,7 +27,7 @@ public class AddDependenciesToApplicationModules implements MultiModuleHandler action.getDependencies().forEach(d -> m.getBuildFile().addDependency(d))); + context.getApplicationModules().getTopmostApplicationModules().forEach(m -> m.getBuildFile().addDependencies(action.getDependencies())); } } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddMinimalPomXml.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddMinimalPomXml.java index 92d882403..76c96f4fa 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddMinimalPomXml.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddMinimalPomXml.java @@ -22,6 +22,7 @@ import org.openrewrite.Parser; import org.openrewrite.xml.tree.Xml; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.sbm.build.impl.MavenBuildFileRefactoringFactory; import org.springframework.sbm.build.impl.OpenRewriteMavenBuildFile; import org.springframework.sbm.build.impl.RewriteMavenParser; import org.springframework.sbm.engine.context.ProjectContext; @@ -47,6 +48,10 @@ public class AddMinimalPomXml extends AbstractAction { @JsonIgnore private RewriteMavenParser rewriteMavenParser; + @Autowired + @JsonIgnore + private MavenBuildFileRefactoringFactory mavenBuildFileRefactoringFactory; + @Override public void apply(ProjectContext context) { String projectDir = context.getProjectRootDirectory().toString(); @@ -70,8 +75,8 @@ public void apply(ProjectContext context) { .parseInputs(List.of(input), null, new RewriteExecutionContext(getEventPublisher())).get(0); OpenRewriteMavenBuildFile rewriteMavenBuildFile = new OpenRewriteMavenBuildFile( context.getProjectRootDirectory(), - maven, getEventPublisher(), new RewriteExecutionContext(getEventPublisher()) - ); + maven, getEventPublisher(), new RewriteExecutionContext(getEventPublisher()), + mavenBuildFileRefactoringFactory.createRefactoring()); context.getProjectResources().add(rewriteMavenBuildFile); } } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/resource/BuildFileResourceWrapper.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/resource/BuildFileResourceWrapper.java index 0b8418fba..82d176c06 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/resource/BuildFileResourceWrapper.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/resource/BuildFileResourceWrapper.java @@ -17,10 +17,11 @@ import lombok.RequiredArgsConstructor; import org.openrewrite.SourceFile; -import org.openrewrite.java.JavaParser; import org.openrewrite.xml.tree.Xml; import org.springframework.context.ApplicationEventPublisher; import org.springframework.core.annotation.Order; +import org.springframework.sbm.build.impl.MavenBuildFileRefactoring; +import org.springframework.sbm.build.impl.MavenBuildFileRefactoringFactory; import org.springframework.sbm.build.impl.OpenRewriteMavenBuildFile; import org.springframework.sbm.openrewrite.RewriteExecutionContext; import org.springframework.sbm.project.resource.ProjectResourceWrapper; @@ -34,6 +35,8 @@ public class BuildFileResourceWrapper implements ProjectResourceWrapper rewriteSourceFileHolder) { return Xml.Document.class.isAssignableFrom(rewriteSourceFileHolder.getSourceFile().getClass()) && rewriteSourceFileHolder.getAbsolutePath().endsWith("pom.xml"); @@ -42,11 +45,13 @@ public boolean shouldHandle(RewriteSourceFileHolder rewrit @Override public OpenRewriteMavenBuildFile wrapRewriteSourceFileHolder(RewriteSourceFileHolder rewriteSourceFileHolder) { Xml.Document maven = (Xml.Document) rewriteSourceFileHolder.getSourceFile(); - + MavenBuildFileRefactoring refactoring = mavenBuildFileRefactoringFactory.createRefactoring(); return new OpenRewriteMavenBuildFile( rewriteSourceFileHolder.getAbsoluteProjectDir(), - maven, eventPublisher, - new RewriteExecutionContext(eventPublisher) + maven, + eventPublisher, + new RewriteExecutionContext(), + refactoring ); } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/engine/commands/ScanCommand.java b/components/sbm-core/src/main/java/org/springframework/sbm/engine/commands/ScanCommand.java index 5b9470168..a1efbad40 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/engine/commands/ScanCommand.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/engine/commands/ScanCommand.java @@ -54,7 +54,7 @@ public ProjectContext execute(String... arguments) { List resources = pathScanner.scan(projectRoot); - return projectContextInitializer.initProjectContext(projectRoot, resources, new RewriteExecutionContext(eventPublisher)); + return projectContextInitializer.initProjectContext(projectRoot, resources); } public List scanProjectRoot(String projectRoot) { diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/DependenciesChangedEventHandler.java b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/DependenciesChangedEventHandler.java index 3e2f42663..84ec594fe 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/DependenciesChangedEventHandler.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/DependenciesChangedEventHandler.java @@ -39,28 +39,25 @@ public class DependenciesChangedEventHandler { private final ProjectContextHolder projectContextHolder; private final ApplicationEventPublisher applicationEventPublisher; - private JavaParser javaParser; + private final JavaParser javaParser; @EventListener public void onDependenciesChanged(DependenciesChangedEvent event) { if (projectContextHolder.getProjectContext() != null) { - Set compilationUnitsSet = projectContextHolder.getProjectContext().getProjectJavaSources().asStream() + Set compilationUnitsSet = projectContextHolder.getProjectContext().getProjectJavaSources().stream() .map(js -> js.getResource().getSourceFile()) .map(js -> new Parser.Input(js.getSourcePath(), () -> new ByteArrayInputStream(js.printAll().getBytes(StandardCharsets.UTF_8)))) .collect(Collectors.toSet()); List compilationUnits = new ArrayList<>(compilationUnitsSet); Path projectRootDirectory = projectContextHolder.getProjectContext().getProjectRootDirectory(); - // FIXME: #7 only affected modules and source sets must be parsed - javaParser = JavaParser.fromJavaVersion().classpath(ClasspathRegistry.getInstance().getCurrentDependencies()).build(); - //javaParser.setClasspath(ClasspathRegistry.getInstance().getCurrentDependencies()); - // FIXME: #7 handle "test" - // FIXME: #7 Provide a unified interface that calculates source set names by path javaParser.setSourceSet("main"); + javaParser.setClasspath(ClasspathRegistry.getInstance().getCurrentDependencies()); + List parsedCompilationUnits = javaParser.parseInputs(compilationUnits, null, new RewriteExecutionContext(applicationEventPublisher)); // ((J.VariableDeclarations)parsedCompilationUnits.get(0).getClasses().get(0).getBody().getStatements().get(0)).getLeadingAnnotations().get(0).getType() parsedCompilationUnits.forEach(cu -> { - projectContextHolder.getProjectContext().getProjectJavaSources().asStream() + projectContextHolder.getProjectContext().getProjectJavaSources().stream() .filter(js -> js.getResource().getAbsolutePath().equals(projectRootDirectory.resolve(cu.getSourcePath()).normalize())) .forEach(js -> js.getResource().replaceWith(cu)); }); diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteJavaSource.java b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteJavaSource.java index 6e133cb80..d64f96498 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteJavaSource.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/OpenRewriteJavaSource.java @@ -135,13 +135,14 @@ public void renameMethodCalls(String methodMatchingPattern, String newName) { /** * Searches in the source file for the usage of the given annotation. + * Meta annotations are found. */ @Override public boolean hasAnnotation(String annotation) { if (!annotation.startsWith("@")) { annotation = "@" + annotation; } - FindAnnotations findAnnotation = new FindAnnotations(annotation); + FindAnnotations findAnnotation = new FindAnnotations(annotation, true); List results = findAnnotation.run(List.of(getCompilationUnit())).getResults(); return !results.isEmpty(); } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/java/migration/visitor/VisitorUtils.java b/components/sbm-core/src/main/java/org/springframework/sbm/java/migration/visitor/VisitorUtils.java index 969c302cc..badf1e823 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/java/migration/visitor/VisitorUtils.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/java/migration/visitor/VisitorUtils.java @@ -141,9 +141,9 @@ public UUID getId() { } @Override - public T withId(final UUID id) { + public M withId(UUID id) { MarkReturnType commentJavaSearchResult = this.id == id ? this : new MarkReturnType(id, null, searchResult.getDescription(), expression, imports); - return (T) commentJavaSearchResult; + return (M) commentJavaSearchResult; } } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/openrewrite/RewriteExecutionContext.java b/components/sbm-core/src/main/java/org/springframework/sbm/openrewrite/RewriteExecutionContext.java index 9a52d8be1..6abda09d6 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/openrewrite/RewriteExecutionContext.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/openrewrite/RewriteExecutionContext.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.java.JavaParsingException; -import org.openrewrite.maven.internal.MavenDownloadingException; +import org.openrewrite.maven.MavenDownloadingException; import org.openrewrite.maven.internal.MavenParsingException; import org.springframework.context.ApplicationEventPublisher; diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/DependencyHelper.java b/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/DependencyHelper.java index 8171453dd..ef095bf3d 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/DependencyHelper.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/DependencyHelper.java @@ -81,22 +81,11 @@ public Set mapCoordinatesToDependencies(List coordinates) { version = parts[2]; } - - MavenRepository mavenRepository = new MavenRepository( - "jcenter", - "https://jcenter.bintray.com", - true, - true, - true, - null, - null - ); - @Nullable String classifier = null; @Nullable String type = null; String scope = Scope.Compile.name(); List exclusions = new ArrayList<>(); - boolean optional = false; + String optional = null; Dependency dependency = new Dependency( new GroupArtifactVersion(groupId, artifactId, version), diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/MavenProjectParser.java b/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/MavenProjectParser.java index 7ca081c65..d4b813f72 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/MavenProjectParser.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/MavenProjectParser.java @@ -53,7 +53,6 @@ @Slf4j @Component @RequiredArgsConstructor -// FIXME: #7 rename to ProjectParser public class MavenProjectParser { private final ResourceParser resourceParser; @@ -80,12 +79,13 @@ public List parse(Path projectDirectory, List resources) { })).collect(Collectors.toList()); eventPublisher.publishEvent(new StartedScanningProjectResourceSetEvent("Maven", inputs.size())); + List mavens = mavenParser.parseInputs(inputs, projectDirectory, ctx); eventPublisher.publishEvent(new FinishedScanningProjectResourceSetEvent()); mavens = sort(mavens); - if (log.isDebugEnabled()) { + if(log.isDebugEnabled()) { for (Xml.Document maven : mavens) { MavenResolutionResult mavenResolution = MavenBuildFileUtil.getMavenResolution(maven); log.debug(" {}:{}", mavenResolution.getPom().getGroupId(), mavenResolution.getPom().getArtifactId()); @@ -127,16 +127,20 @@ public List parse(Path projectDirectory, List resources) { // -------- // Main resources - Set mainResourcePaths = Set.of(Path.of("src/main/resources"), Path.of("src/main/webapp"), - Path.of("src/main/mule")); + Set mainResourcePaths = Set.of( + Path.of("src/main/resources"), + Path.of("src/main/webapp"), + Path.of("src/main/mule") + ); // FIXME: mainSourceSetMarker and provenance marker must be added to all resources - List resourceList = resourceParser.filter(projectDirectory, mainResourcePaths, resources, - relativeModuleDir); + List resourceList = resourceParser.filter(projectDirectory, mainResourcePaths, resources, relativeModuleDir); List resourceMarker = new ArrayList(javaProvenanceMarkers); resourceMarker.add(mainSourceSet); - resourceMarker.add(gitProvenance); + if(gitProvenance != null) { + resourceMarker.add(gitProvenance); + } List mainResources = resourceParser.parse(projectDirectory, resourceList, resourceMarker); sourceFiles.addAll(mainResources); @@ -144,27 +148,28 @@ public List parse(Path projectDirectory, List resources) { // Test Java sources ArrayList markers = new ArrayList<>(javaProvenanceMarkers); markers.add(mainSourceSet); - List testJavaSources = parseTestJavaSources(projectDirectory, resources, ctx, javaParser, - pomXml, mavenWithMarkers, - mavenProjectDirectory, markers); + List testJavaSources = parseTestJavaSources(projectDirectory, resources, ctx, javaParser, pomXml, mavenWithMarkers, mavenProjectDirectory, markers); JavaSourceSet testSourceSet = javaParser.getSourceSet(ctx); sourceFiles.addAll(testJavaSources); // -------- // Test resources - Set testResourcePaths = Set.of(Path.of("src/test/resources"), Path.of("src/test/webapp"), - Path.of("src/test/mule")); + Set testResourcePaths = Set.of( + Path.of("src/test/resources"), + Path.of("src/test/webapp"), + Path.of("src/test/mule") + ); - List filteredResources = resourceParser.filter(projectDirectory, testResourcePaths, resources, - relativeModuleDir); + List filteredResources = resourceParser.filter(projectDirectory, testResourcePaths, resources, relativeModuleDir); List testResourceMarker = new ArrayList(javaProvenanceMarkers); testResourceMarker.add(testSourceSet); - testResourceMarker.add(gitProvenance); - List testResources = resourceParser.parse(projectDirectory, filteredResources, - testResourceMarker); + if(gitProvenance != null) { + testResourceMarker.add(gitProvenance); + } + List testResources = resourceParser.parse(projectDirectory, filteredResources, testResourceMarker); sourceFiles.addAll(testResources); } - if (gitProvenance != null) { + if(gitProvenance != null) { sourceFiles = ListUtils.map(sourceFiles, s -> s.withMarkers(s.getMarkers().addIfAbsent(gitProvenance))); } return sourceFiles; @@ -214,8 +219,7 @@ private List parseMainJavaSources(Path projectDirectory, List return content; }); }).collect(Collectors.toList()); - List mainCompilationUnits = javaParser.parseInputs(mainJavaSourcesInput, projectDirectory, - ctx); + List mainCompilationUnits = javaParser.parseInputs(mainJavaSourcesInput, projectDirectory, ctx); // FIXME: #7 JavaParser and adding markers is required when adding java sources and should go into dedicated component mainCompilationUnits.stream().forEach(cu -> cu.getMarkers().getMarkers().addAll(javaProvenanceMarkers)); return mainCompilationUnits; @@ -317,7 +321,11 @@ public static List sort(List mavens) { } } } - + sorted.sort((d, e) -> d.getSourcePath().toString().compareTo(e.getSourcePath().toString())); + if(log.isDebugEnabled()) { + String collect = sorted.stream().map(Xml.Document::getSourcePath).map(Object::toString).collect(Collectors.joining(", ")); + log.debug("Sorted Maven files: \"%s\"".formatted(collect)); + } return sorted; } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/ProjectContextInitializer.java b/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/ProjectContextInitializer.java index 6c732e2ae..c0da92e4d 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/ProjectContextInitializer.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/ProjectContextInitializer.java @@ -45,7 +45,7 @@ public class ProjectContextInitializer { private final RewriteSourceFileWrapper rewriteSourceFileWrapper; - public ProjectContext initProjectContext(Path projectDir, List resources, RewriteExecutionContext rewriteExecutionContext) { + public ProjectContext initProjectContext(Path projectDir, List resources) { final Path absoluteProjectDir = projectDir.toAbsolutePath().normalize(); // TODO: remove git initialization, handled by precondition check initializeGitRepoIfNoneExists(absoluteProjectDir); diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/ResourceParser.java b/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/ResourceParser.java index 1a6627710..4d4a6017e 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/ResourceParser.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/ResourceParser.java @@ -17,6 +17,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.openrewrite.Parser; import org.openrewrite.SourceFile; import org.openrewrite.hcl.HclParser; @@ -28,7 +29,6 @@ import org.openrewrite.text.PlainTextParser; import org.openrewrite.tree.ParsingExecutionContextView; import org.openrewrite.xml.XmlParser; -import org.openrewrite.xml.tree.Xml; import org.openrewrite.yaml.YamlParser; import org.springframework.context.ApplicationEventPublisher; import org.springframework.core.io.Resource; @@ -40,6 +40,8 @@ import java.io.InputStream; import java.nio.file.Path; import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.Collectors; @Slf4j @@ -115,13 +117,24 @@ public List parse(Path baseDir, List relevantResources, Li ctx.setParsingListener((input, sourceFile) -> eventPublisher.publishEvent(new StartedScanningProjectResourceEvent(sourceFile.getSourcePath()))); return parserAndParserInputMappings.entrySet().stream() - .map(e -> e.getKey().parseInputs(e.getValue(), baseDir, ctx)) + .filter(ifNoInput()) + .map(parseEntry(baseDir, ctx)) .flatMap(List::stream) .map(e -> addMarkers(e, markers)) .collect(Collectors.toList()); } + @NotNull + private Function, List>, ? extends List> parseEntry(Path baseDir, ParsingExecutionContextView ctx) { + return e -> e.getKey().parseInputs(e.getValue(), baseDir, ctx); + } + + @NotNull + private Predicate, List>> ifNoInput() { + return e -> !e.getValue().isEmpty(); + } + private SourceFile addMarkers(SourceFile e, List markers) { return e.withMarkers(Markers.build(markers)); } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/project/resource/RewriteSourceFileHolder.java b/components/sbm-core/src/main/java/org/springframework/sbm/project/resource/RewriteSourceFileHolder.java index 404a48c24..0a9ef2806 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/project/resource/RewriteSourceFileHolder.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/project/resource/RewriteSourceFileHolder.java @@ -40,7 +40,11 @@ public RewriteSourceFileHolder(Path absoluteProjectDir, T sourceFile) { } public String print() { - return sourceFile.printAll(); + try { + return sourceFile.printAll(); + } catch (Exception e) { + throw new RuntimeException("Exception while printing '%s'".formatted(sourceFile.getSourcePath()), e); + } } @Override diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/properties/migration/recipes/AddProperty.java b/components/sbm-core/src/main/java/org/springframework/sbm/properties/migration/recipes/AddProperty.java index 54f28d8f8..f337c2949 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/properties/migration/recipes/AddProperty.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/properties/migration/recipes/AddProperty.java @@ -41,6 +41,15 @@ public class AddProperty extends Recipe { example = "false") String value; + /* + @Option(displayName = "Optional delimiter", + description = "Property entries support different delimiters (`=`, `:`, or whitespace). The default value is `=` unless provided the delimiter of the new property entry.", + required = false, + example = ":") + @Nullable + String delimiter; + */ + @Override public String getDisplayName() { return "Add property with key and value"; @@ -71,7 +80,15 @@ public Properties visitFile(File file, P p) { if (!contents.isEmpty()) { prefix = "\n"; } - contents.add(new Entry(Tree.randomId(), prefix, Markers.EMPTY, key, "", new Value(Tree.randomId(), "", Markers.EMPTY, value))); + contents.add( + new Entry( + Tree.randomId(), + prefix, + Markers.EMPTY, + key, + "", + Entry.Delimiter.EQUALS, + new Value(Tree.randomId(), "", Markers.EMPTY, value))); return file.withContent(Collections.unmodifiableList(contents)); } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/search/recipe/CommentJavaSearchResult.java b/components/sbm-core/src/main/java/org/springframework/sbm/search/recipe/CommentJavaSearchResult.java index f38caa262..2b2d0145b 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/search/recipe/CommentJavaSearchResult.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/search/recipe/CommentJavaSearchResult.java @@ -48,9 +48,9 @@ public UUID getId() { } @Override - public T withId(final UUID id) { + public M withId(final UUID id) { CommentJavaSearchResult commentJavaSearchResult = this.id == id ? this : new CommentJavaSearchResult(id, searchResult.getDescription()); - return (T) commentJavaSearchResult; + return (M) commentJavaSearchResult; } public String getComment() { diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/build/impl/MavenSettingsInitializerTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/build/impl/MavenSettingsInitializerTest.java index 6f310a323..40536b21d 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/build/impl/MavenSettingsInitializerTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/build/impl/MavenSettingsInitializerTest.java @@ -65,16 +65,16 @@ void mavenParserMustAdhereToSettingsXmlTest() throws URISyntaxException { assertThat(mavenRepository.getId()).isEqualTo("central"); assertThat(mavenRepository.getUri()).isEqualTo("https://jcenter.bintray.com"); - assertThat(mavenRepository.isReleases()).isTrue(); - assertThat(mavenRepository.isSnapshots()).isFalse(); + assertThat(mavenRepository.getReleases()).isNull(); + assertThat(mavenRepository.getSnapshots()).isEqualToIgnoringCase("false"); MavenRepository localRepository = mavenExecutionContextView.getLocalRepository(); - assertThat(localRepository.isSnapshots()).isTrue(); + assertThat(localRepository.getSnapshots()).isNull(); String tmpDir = removeTrailingSlash(System.getProperty("java.io.tmpdir")); String customLocalRepository = new URI("file://" + tmpDir).toString(); assertThat(removeTrailingSlash(localRepository.getUri())).isEqualTo(customLocalRepository); - assertThat(localRepository.isSnapshots()).isTrue(); + assertThat(localRepository.getSnapshots()).isNull(); assertThat(localRepository.isKnownToExist()).isTrue(); assertThat(localRepository.getUsername()).isNull(); assertThat(localRepository.getPassword()).isNull(); diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/AddMavenDependencyManagementActionTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/AddMavenDependencyManagementActionTest.java index d6dd5f997..845c75581 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/AddMavenDependencyManagementActionTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/AddMavenDependencyManagementActionTest.java @@ -160,7 +160,7 @@ void shouldAddToRootPomInSingleModuleProject() { " 4.0.0\n" + " org.springframework.sbm.examples\n" + " artifact-id\n" + - " jar\n" + + " pom\n" + " 0.0.1-SNAPSHOT\n" + "\n"; @@ -171,7 +171,7 @@ void shouldAddToRootPomInSingleModuleProject() { " 4.0.0\n" + " org.springframework.sbm.examples\n" + " artifact-id\n" + - " jar\n" + + " pom\n" + " 0.0.1-SNAPSHOT\n" + " \n" + " \n" + diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/RemoveManagedDependenciesTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/RemoveManagedDependenciesTest.java index ddc96c7b6..6526f928c 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/RemoveManagedDependenciesTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/RemoveManagedDependenciesTest.java @@ -21,6 +21,8 @@ import org.springframework.sbm.engine.context.ProjectContext; import org.springframework.sbm.project.resource.TestProjectContext; +import java.util.List; + import static org.assertj.core.api.AssertionsForClassTypes.assertThat; public class RemoveManagedDependenciesTest { @@ -51,7 +53,7 @@ public void givenProjectWithManagedDependency_removeSpringManagedDependencies_ex @Test public void givenProjectWithLowerVersionedManagedDependency_removeSpringManagedDependencies_expectDependencyRemoved(){ - final String hibernateCoordinates = "org.hibernate:hibernate-core:5.3.2.Final"; + final String hibernateCoordinates = "org.hibernate:hibernate-core:5.6.10.Final"; final String springBootDataJpaCoordinates = "org.springframework.boot:spring-boot-starter-data-jpa:2.7.4"; final ProjectContext projectContext = TestProjectContext.buildProjectContext() @@ -70,8 +72,10 @@ public void givenProjectWithLowerVersionedManagedDependency_removeSpringManagedD } @Test - public void givenProjectWithHigherVersionedManagedDependency_removeSpringManagedDependencies_expectDependencyRemoved(){ - final String hibernateCoordinates = "org.hibernate:hibernate-core:5.12.2.Final"; + public void givenProjectWithSameVersionedManagedDependency_removeSpringManagedDependencies_expectDependencyRemoved(){ + // explicitly declared + final String hibernateCoordinates = "org.hibernate:hibernate-core:5.6.11.Final"; + // brings managed hibernate 5.6.11.Final final String springBootDataJpaCoordinates = "org.springframework.boot:spring-boot-starter-data-jpa:2.7.4"; final ProjectContext projectContext = TestProjectContext.buildProjectContext() @@ -81,11 +85,49 @@ public void givenProjectWithHigherVersionedManagedDependency_removeSpringManaged RemoveManagedDependencies removeManagedDependencies = new RemoveManagedDependencies(); removeManagedDependencies.apply(projectContext); - assertThat(projectContext.getBuildFile() - .getDeclaredDependencies() - .stream() - .map(Dependency::getCoordinates) - .anyMatch(hibernateCoordinates::equals) - ).isTrue(); + List declaredDependencies = projectContext + .getApplicationModules() + .getRootModule() + .getBuildFile() + .getDeclaredDependencies(); + + // only one dependency left + assertThat(declaredDependencies.size()).isEqualTo(1); + // dependency to older hibernate was removed + assertThat(declaredDependencies + .get(0) + .getCoordinates()) + .isEqualTo(springBootDataJpaCoordinates); + } + + @Test + public void givenProjectWithHigherVersionedManagedDependency_removeSpringManagedDependencies_expectDependencyKept(){ + final String hibernateCoordinates = "org.hibernate:hibernate-core:5.6.12.Final"; + // brings older hibernate 5.6.11.Final + final String springBootDataJpaCoordinates = "org.springframework.boot:spring-boot-starter-data-jpa:2.7.4"; + + final ProjectContext projectContext = TestProjectContext.buildProjectContext() + .withBuildFileHavingDependencies(hibernateCoordinates, springBootDataJpaCoordinates) + .build(); + + RemoveManagedDependencies removeManagedDependencies = new RemoveManagedDependencies(); + removeManagedDependencies.apply(projectContext); + + List declaredDependencies = projectContext + .getApplicationModules() + .getRootModule() + .getBuildFile() + .getDeclaredDependencies(); + + // both dependencies kept + assertThat(declaredDependencies.size()).isEqualTo(2); + assertThat(declaredDependencies + .get(0) + .getCoordinates()) + .isEqualTo(hibernateCoordinates); + assertThat(declaredDependencies + .get(1) + .getCoordinates()) + .isEqualTo(springBootDataJpaCoordinates); } } diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/OpenRewriteMethodTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/OpenRewriteMethodTest.java index b739dbbda..ceb57d30f 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/OpenRewriteMethodTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/OpenRewriteMethodTest.java @@ -245,17 +245,18 @@ void testImplicitDefaultMethod() { @Test void testOtherVisibilityMethod() { - String sourceCode = - "public class Foo { \n" + - " public void foo1() { \n" + - " } \n" + - " protected void foo2() { \n" + - " } \n" + - " private void foo3() { \n" + - " } \n" + - " default void foo4() { \n" + - " } \n" + - "}"; + String sourceCode = """ + public class Foo { \s + public void foo1() { + } + protected void foo2() { + } + private void foo3() { + } + void foo4() { + } + } + """; JavaSource javaSource = TestProjectContext.buildProjectContext() .withBuildFileHavingDependencies("org.junit.jupiter:junit-jupiter-api:5.7.0") diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/OpenRewriteSearchAndCommentTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/OpenRewriteSearchAndCommentTest.java index 68c884f2e..c2c3de086 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/OpenRewriteSearchAndCommentTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/OpenRewriteSearchAndCommentTest.java @@ -30,13 +30,17 @@ class OpenRewriteSearchAndCommentTest { void markMatches() { String javaSource1 = - "public class SomeTest {" + - " @Deprecated public void test() {}" + - "}"; + """ + public class SomeTest { + @Deprecated public void test() {} + } + """; String javaSource2 = - "public class SomeTest2 {" + - " public void test2() {}" + - "}"; + """ + public class SomeTest2 { + public void test2() {} + } + """; ProjectContext projectContext = TestProjectContext.buildProjectContext() .withJavaSources(javaSource1, javaSource2) @@ -45,16 +49,22 @@ void markMatches() { String markerText = "marker text"; JavaParser javaParser = new RewriteJavaParser(new SbmApplicationProperties()); - OpenRewriteRecipeJavaSearch sut = new OpenRewriteRecipeJavaSearch(compilationUnits -> new FindAnnotations("@java.lang.Deprecated").run(compilationUnits).getResults(), javaParser); + OpenRewriteRecipeJavaSearch sut = new OpenRewriteRecipeJavaSearch(compilationUnits -> new FindAnnotations("@java.lang.Deprecated", false).run(compilationUnits).getResults(), javaParser); sut.commentFindings(projectContext.getProjectJavaSources().list(), markerText); assertThat(projectContext.getProjectJavaSources().list().size()).isEqualTo(2); assertThat(projectContext.getProjectJavaSources().list().get(1).print()).isEqualTo(javaSource2); assertThat(projectContext.getProjectJavaSources().list().get(0).print()).isEqualTo( - "public class SomeTest { \n" + - "/*\n" + - markerText + - "\n*/\n@Deprecated public void test() {}}"); + """ + public class SomeTest { + \s + /* + marker text + */ + /*~~>*/@Deprecated public void test() {} + } + """ + ); } } \ No newline at end of file diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/AddDependencyTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/AddDependencyTest.java new file mode 100644 index 000000000..051aa18dc --- /dev/null +++ b/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/AddDependencyTest.java @@ -0,0 +1,160 @@ +/* + * 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.project.buildfile; + +import org.checkerframework.checker.units.qual.A; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.maven.tree.Scope; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.sbm.build.api.BuildFile; +import org.springframework.sbm.build.api.Dependency; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.engine.context.ProjectContextHolder; +import org.springframework.sbm.java.api.Member; +import org.springframework.sbm.java.impl.ClasspathRegistry; +import org.springframework.sbm.java.impl.DependenciesChangedEventHandler; +import org.springframework.sbm.java.impl.RewriteJavaParser; +import org.springframework.sbm.project.resource.SbmApplicationProperties; +import org.springframework.sbm.project.resource.TestProjectContext; +import org.springframework.test.util.ReflectionTestUtils; + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test the inner workings when adding a dependency + * + * @author Fabian Krüger + */ +@SpringBootTest(classes ={ + DependenciesChangedEventHandler.class, + ProjectContextHolder.class, + RewriteJavaParser.class, + SbmApplicationProperties.class +}) +@Disabled("See comment in test") +public class AddDependencyTest { + + @Autowired + DependenciesChangedEventHandler handler; + + @Autowired + ApplicationEventPublisher eventPublisher; + + @Autowired + ProjectContextHolder contextHolder; + + @Autowired + RewriteJavaParser rewriteJavaParser; + + /** + * Test that after adding a dependency... + * + * * The ClasspathRegistry was updated + * * The types are in the type cache of encapsulated JavaParser + * * The new types can be resolved + * + * Also see {@link DependenciesChangedEventHandler} + */ + @Test + void whenDependencyIsAdded_thenJavaParserTypeCacheGetsUpdated() { + // simple ProjectContext + String javaSourceCode = "import javax.validation.constraints.Email; class Y {@Email String email;}"; + ProjectContext context = TestProjectContext + .buildProjectContext(eventPublisher, rewriteJavaParser) + .addJavaSource("src/main/java", javaSourceCode) + .build(); + // provide ProjectContext to Spring beans + contextHolder.setProjectContext(context); + + String javaxValidationEmail = "javax.validation.constraints.Email"; + HashMap typeCache0 = retrieveTypeCache(rewriteJavaParser.getJavaParser()); + assertThat(typeCache0).isEmpty(); + + // Parse the java source to fill the type cache + rewriteJavaParser.parse(javaSourceCode); + HashMap typeCache = retrieveTypeCache(rewriteJavaParser.getJavaParser()); + assertThat(typeCache).hasSize(17_590); + + // javax.validation.Email not in type cache + Optional s = findInTypeCache(typeCache, javaxValidationEmail); + assertThat(s).isNotPresent(); + + // Classpath empty + assertThat(ClasspathRegistry.getInstance().getCurrentDependencies()).isEmpty(); + + + // add dependency + BuildFile buildFile = context.getBuildFile(); + buildFile.addDependency(Dependency.builder() + .groupId("javax.validation") + .artifactId("validation-api") + .version("2.0.1.Final") + .build()); + + System.out.println(buildFile.print()); + assertThat(buildFile.getDeclaredDependencies(Scope.Compile).get(0).getArtifactId()).isEqualTo("validation-api"); + + // validation-api added to Classpath + assertThat(ClasspathRegistry.getInstance().getCurrentDependencies()).hasSize(1); + assertThat(ClasspathRegistry.getInstance().getCurrentDependencies().iterator().next().toString()).contains("validation-api"); + + // type cache contains the new types as classes were recompiled in DependenciesChangeEventListener + //rewriteJavaParser.getJavaParser().parse(javaSourceCode); + context.getApplicationModules().getRootModule().getMainJavaSourceSet().addJavaSource(TestProjectContext.getDefaultProjectRoot(), + Path.of("src/main/java"), + "import javax.validation.constraints.Email; class X {@Email String email;}"); + + // The Email annotation can now be resolved + HashMap typeCacheAfter = retrieveTypeCache(rewriteJavaParser.getJavaParser()); + Optional emailType = findInTypeCache(typeCacheAfter, javaxValidationEmail); + assertThat(emailType).isPresent(); // currently failing + assertThat(typeCacheAfter).hasSize(17697); + } + + @NotNull + private Optional findInTypeCache(HashMap typeCache1, String emailFqName) { + Optional s = typeCache1 + .values() + .stream() + .filter(JavaType.Class.class::isInstance) + .map(JavaType.Class.class::cast) + .map(jt -> jt.getFullyQualifiedName()) + .filter(emailFqName::equals) + .findAny(); + return s; + } + + @Nullable + private HashMap retrieveTypeCache(JavaParser javaParser) { + HashMap typeCache1 = (HashMap) ReflectionTestUtils.getField(ReflectionTestUtils.getField(ReflectionTestUtils.getField( + javaParser, "delegate"), "typeCache"), "typeCache"); + return typeCache1; + } +} diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java index 2a2ec6e56..5367b0bc6 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java @@ -17,7 +17,6 @@ import org.jetbrains.annotations.NotNull; import org.intellij.lang.annotations.Language; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Tag; @@ -35,6 +34,8 @@ import org.springframework.sbm.engine.context.ProjectContextHolder; import org.springframework.sbm.java.api.Member; import org.springframework.sbm.java.impl.DependenciesChangedEventHandler; +import org.springframework.sbm.java.impl.RewriteJavaParser; +import org.springframework.sbm.project.resource.SbmApplicationProperties; import org.springframework.sbm.project.resource.TestProjectContext; import java.nio.file.Path; @@ -375,7 +376,6 @@ void testGetResolvedDependenciesPaths() { */ @Test @Tag("integration") - @Disabled("Fails in CI with 'java.io.FileNotFoundException: /root/.m2/repository/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar '") void testResolvedDependenciesWithPomTypeDependency() { String pomXml = "\n" + - "\n" + - " 4.0.0\n" + - " org.springframework.sbm\n" + - " dummy-test-artifact\n" + - " 1.0.0\n" + - "\n"; - - String javaSource = "import javax.validation.constraints.Email;\n" + - "public class Cat {\n" + - " @Email\n" + - " private String email;\n" + - "}"; - - // precondition: jar does not exist - // precondition: types from jar not resolvable - - // verify jar was downloaded - // verify types from jar can be resolved - + void addDependencyShouldPublishEvent() { ApplicationEventPublisher eventPublisher = mock(ApplicationEventPublisher.class); + ProjectContext context = TestProjectContext.buildProjectContext(eventPublisher) - .withMavenRootBuildFileSource(pomXml) - .addJavaSource("src/main/java", javaSource) + .withMavenRootBuildFileSource( + """ + + + 4.0.0 + org.springframework.sbm + dummy-test-artifact + 1.0.0 + + """ + ) + .addJavaSource("src/main/java", + """ + import javax.validation.constraints.Email; + public class Cat { + @Email + private String email; + } + """ + ) .build(); BuildFile buildFile = context.getBuildFile(); Member member = context.getProjectJavaSources().list().get(0).getTypes().get(0).getMembers().get(0); + // The Email annotation cannot be resolved boolean b = member.hasAnnotation("javax.validation.constraints.Email"); assertThat(b).isFalse(); + // adding the validation-api brings the Email annotation buildFile.addDependency(Dependency.builder() .groupId("javax.validation") .artifactId("validation-api") @@ -553,18 +552,18 @@ void addDependencyWithNoTransitiveDependencies() { .build()); - Class event = DependenciesChangedEvent.class; ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(event); assertEventPublished(eventPublisher, argumentCaptor, event, 1); -// verify(eventPublisher).publishEvent(argumentCaptor); - assertThat(argumentCaptor.getValue().getResolvedDependencies().get(0).toString()).endsWith("javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar"); - DependenciesChangedEvent fireEvent = argumentCaptor.getValue(); + assertThat(fireEvent.getResolvedDependencies().get(0).toString()).endsWith("javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar"); + + // call DependenciesChangedEventHandler to trigger recompile + RewriteJavaParser rewriteJavaParser = new RewriteJavaParser(new SbmApplicationProperties()); ProjectContextHolder projectContextHolder = new ProjectContextHolder(); projectContextHolder.setProjectContext(context); - DependenciesChangedEventHandler handler = new DependenciesChangedEventHandler(projectContextHolder, eventPublisher); + DependenciesChangedEventHandler handler = new DependenciesChangedEventHandler(projectContextHolder, eventPublisher, rewriteJavaParser); handler.onDependenciesChanged(fireEvent); Member member2 = context.getProjectJavaSources().list().get(0).getTypes().get(0).getMembers().get(0); @@ -636,7 +635,7 @@ void testAddDependency() { .version("1.2") // FIXME: using 1.2.1 results in 1.2-b03 ?! Is this the dependency in the pm.xml or the resolved from bom .build()); - assertThat(sut.getDependencyManagement()).hasSize(0); + assertThat(sut.getEffectiveDependencyManagement()).hasSize(0); assertThat(sut.getDeclaredDependencies()).hasSize(1); Dependency addedDependency = sut.getDeclaredDependencies().get(0); @@ -678,7 +677,7 @@ void addDependency() { sut.addDependency(dependency); - assertThat(sut.getDependencyManagement()).hasSize(0); + assertThat(sut.getEffectiveDependencyManagement()).hasSize(0); assertThat(sut.getDeclaredDependencies()).hasSize(1); assertThat(sut.getDeclaredDependencies()).contains(dependency); ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(DependenciesChangedEvent.class); @@ -771,7 +770,7 @@ void testAddDependencies() { + "\n", sut.print()); - assertThat(sut.getDependencyManagement()).hasSize(0); + assertThat(sut.getEffectiveDependencyManagement()).hasSize(0); assertThat(sut.getDeclaredDependencies()).hasSize(2); Dependency addedDependency = sut.getDeclaredDependencies().get(0); @@ -828,7 +827,7 @@ void testDeleteDependencies() { .build()) ); - assertThat(sut.getDependencyManagement()).hasSize(0); + assertThat(sut.getEffectiveDependencyManagement()).hasSize(0); assertThat(sut.getDeclaredDependencies()).hasSize(0); } @@ -1272,7 +1271,7 @@ void testDeleteTypePomDependencies() { .withMavenRootBuildFileSource(pomXml) .build() .getBuildFile(); - assertThat(sut.getDependencyManagement()).hasSize(0); + assertThat(sut.getEffectiveDependencyManagement()).hasSize(0); assertThat(sut.getDeclaredDependencies()).hasSize(2); sut.removeDependencies(List.of( @@ -1283,7 +1282,7 @@ void testDeleteTypePomDependencies() { .build()) ); - assertThat(sut.getDependencyManagement()).hasSize(0); + assertThat(sut.getEffectiveDependencyManagement()).hasSize(0); assertThat(sut.getDeclaredDependencies()).hasSize(1); assertThat(sut.print()).isEqualTo("\n" + @@ -2254,6 +2253,137 @@ void deleteProperty() { } + @Test + void deletePropertyCalledOnRootModule_withMultiModules() { + String rootPom = PomBuilder.buildPom("com.example:parent:1.0") + .packaging("pom") + .property("maven.compiler.source", "17") + .property("maven.compiler.target", "17") + .withModules("module1") + .build(); + + String module1Pom = PomBuilder.buildPom("com.example:parent:1.0", "module1") + .packaging("jar") + .property("maven.compiler.source", "17") + .property("maven.compiler.target", "17") + .build(); + + ProjectContext projectContext = TestProjectContext.buildProjectContext() + .withMavenBuildFileSource("pom.xml", rootPom) + .withMavenBuildFileSource("module1/pom.xml", module1Pom) + .build(); + + BuildFile rootModule = projectContext.getApplicationModules().getRootModule().getBuildFile(); + + rootModule.deleteProperty("maven.compiler.source"); + + assertThat(rootModule.getProperty("maven.compiler.source")).isNull(); + assertThat(rootModule.getProperty("maven.compiler.target")).isEqualTo("17"); + assertThat(rootModule.print()).isEqualTo( """ + + + 4.0.0 + com.example + parent + 1.0 + pom + + 17 + + + module1 + + + """); + + BuildFile module1 = projectContext.getApplicationModules().getModule("module1").getBuildFile(); + assertThat(module1.getProperty("maven.compiler.source")).isEqualTo("17"); + assertThat(module1.getProperty("maven.compiler.target")).isEqualTo("17"); + assertThat(module1.print()).isEqualTo(""" + + + 4.0.0 + + com.example + parent + 1.0 + + module1 + jar + + 17 + 17 + + + """); + } + + @Test + void deletePropertyCalledOnChildModule_withMultiModules() { + String rootPom = PomBuilder.buildPom("com.example:parent:1.0") + .packaging("pom") + .property("maven.compiler.source", "17") + .property("maven.compiler.target", "17") + .withModules("module1") + .build(); + + String module1Pom = PomBuilder.buildPom("com.example:parent:1.0", "module1") + .packaging("jar") + .property("maven.compiler.source", "17") + .property("maven.compiler.target", "17") + .build(); + + ProjectContext projectContext = TestProjectContext.buildProjectContext() + .withMavenBuildFileSource("pom.xml", rootPom) + .withMavenBuildFileSource("module1/pom.xml", module1Pom) + .build(); + + BuildFile rootModule = projectContext.getApplicationModules().getRootModule().getBuildFile(); + BuildFile module1 = projectContext.getApplicationModules().getModule("module1").getBuildFile(); + + module1.deleteProperty("maven.compiler.source"); + + assertThat(rootModule.getProperty("maven.compiler.source")).isEqualTo("17"); + assertThat(rootModule.getProperty("maven.compiler.target")).isEqualTo("17"); + assertThat(rootModule.print()).isEqualTo(""" + + + 4.0.0 + com.example + parent + 1.0 + pom + + 17 + 17 + + + module1 + + + """); + + + assertThat(module1.getProperty("maven.compiler.source")).isNull(); + assertThat(module1.getProperty("maven.compiler.target")).isEqualTo("17"); + assertThat(module1.print()).isEqualTo(""" + + + 4.0.0 + + com.example + parent + 1.0 + + module1 + jar + + 17 + + + """); + } + @Test void removePluginsMatchingRegex() { String pomXml = @@ -2426,6 +2556,27 @@ void removePlugins() { assertThat(openRewriteMavenBuildFile.print()).isEqualTo(expected); } + @Test + // FIXME: To make this setProperty work with multi-module projects the MavenBuildFileRefactoring as well as the ResourceWrapper logic must be refactored. + void setProperty() { + String parentPom = PomBuilder.buildPom("com.example:parent:0.1") + .packaging("pom") + .withModules("moduleA") + .withProperties(Map.of("some-property", "value1")) + .build(); + String moduleA = PomBuilder.buildPom("com.example:parent:0.1", "moduleA").build(); + ProjectContext context = TestProjectContext + .buildProjectContext() + .withMavenRootBuildFileSource(parentPom) + .withMavenBuildFileSource("moduleA", moduleA) + .build(); + BuildFile moduleABuildFile = context.getApplicationModules().getTopmostApplicationModules().get(0).getBuildFile(); + moduleABuildFile.setProperty("some-property", "different-value"); + + assertThat(moduleABuildFile.getProperty("some-property")).isEqualTo("different-value"); + assertThat(context.getApplicationModules().getRootModule().getBuildFile().getProperty("some-property")).isEqualTo("value1"); + } + @Test void hasParentWithParentShouldReturnTrue() { String pomXml = diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/project/parser/MavenProjectParserTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/project/parser/MavenProjectParserTest.java index bbff52a22..f33249473 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/project/parser/MavenProjectParserTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/project/parser/MavenProjectParserTest.java @@ -15,101 +15,34 @@ */ package org.springframework.sbm.project.parser; -import com.fasterxml.jackson.core.JsonParser; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import org.openrewrite.java.JavaParser; -import org.openrewrite.maven.utilities.MavenArtifactDownloader; -import org.openrewrite.properties.PropertiesParser; -import org.openrewrite.text.PlainTextParser; -import org.openrewrite.xml.XmlParser; -import org.openrewrite.yaml.YamlParser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.core.io.ResourceLoader; -import org.springframework.sbm.build.impl.MavenSettingsInitializer; -import org.springframework.sbm.build.impl.RewriteMavenArtifactDownloader; -import org.springframework.sbm.build.impl.RewriteMavenParser; -import org.springframework.sbm.build.migration.MavenPomCacheProvider; +import org.openrewrite.maven.MavenParser; +import org.openrewrite.xml.tree.Xml; +import java.util.List; +import org.openrewrite.maven.tree.MavenResolutionResult; import org.springframework.sbm.build.util.PomBuilder; -import org.springframework.sbm.engine.commands.ScanCommand; -import org.springframework.sbm.engine.context.ProjectContextFactory; -import org.springframework.sbm.engine.context.ProjectRootPathResolver; -import org.springframework.sbm.engine.git.GitSupport; -import org.springframework.sbm.engine.precondition.PreconditionVerifier; -import org.springframework.sbm.java.impl.RewriteJavaParser; -import org.springframework.sbm.java.refactoring.JavaRefactoringFactoryImpl; -import org.springframework.sbm.java.util.BasePackageCalculator; -import org.springframework.sbm.project.RewriteSourceFileWrapper; -import org.springframework.sbm.project.resource.ProjectResourceSetHolder; -import org.springframework.sbm.project.resource.ProjectResourceWrapperRegistry; -import org.springframework.sbm.project.resource.ResourceHelper; -import org.springframework.sbm.project.resource.SbmApplicationProperties; -import org.springframework.sbm.properties.parser.RewritePropertiesParser; -import org.springframework.sbm.xml.parser.RewriteXmlParser; -import static org.junit.jupiter.api.Assertions.*; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; /** * @author Fabian Krüger */ -@SpringBootTest(classes = { -// MavenProjectParser.class, -// ResourceParser.class, -// JsonParser.class, -// XmlParser.class, -// YamlParser.class, -// PropertiesParser.class, -// PlainTextParser.class, -// ResourceParser.ResourceFilter.class, -// RewriteMavenParser.class, -// MavenArtifactDownloader.class, -// ApplicationEventPublisher.class, -// JavaProvenanceMarkerFactory.class, -// JavaParser.class, - MavenConfigHandler.class, - ProjectContextInitializer.class, - RewriteMavenArtifactDownloader.class, - JavaProvenanceMarkerFactory.class, - BasePackageCalculator.class, - BasePackageCalculator.class, - ProjectRootPathResolver.class, - PreconditionVerifier.class, - ProjectContextFactory.class, - MavenPomCacheProvider.class, - SbmApplicationProperties.class, - PathScanner.class, - RewriteJavaParser.class, - RewritePlainTextParser.class, - RewriteYamlParser.class, - RewriteJsonParser.class, - ResourceParser.class, - RewritePropertiesParser.class, - MavenProjectParser.class, - RewriteMavenParser.class, - MavenSettingsInitializer.class, - RewriteXmlParser.class, - ResourceHelper.class, - ResourceLoader.class, - GitSupport.class, - ScanCommand.class, - ProjectResourceSetHolder.class, - JavaRefactoringFactoryImpl.class, - ProjectResourceWrapperRegistry.class, - RewriteSourceFileWrapper.class -}) class MavenProjectParserTest { - @Autowired - private MavenProjectParser sut; - @Test void testSort() { - String parent = PomBuilder.buildPom("com.example:parent:1.0").withModules("child").build(); - String child = PomBuilder.buildPom("com.example:parent:1.0", "child").build(); - - - Assertions.assertThat(true).isFalse(); + String parentPom = PomBuilder.buildPom("com.example:parent:0.1") + .packaging("pom") + .withModules("moduleA") + .withProperties(Map.of("some-property", "value1")) + .build(); + String moduleA = PomBuilder.buildPom("com.example:parent:0.1", "moduleA").build(); + List poms = MavenParser.builder().build().parse(parentPom, moduleA); + List sortedPoms = MavenProjectParser.sort(poms); + assertThat(sortedPoms.get(0).getMarkers().findFirst(MavenResolutionResult.class).get().getPom().getArtifactId()).isEqualTo("parent"); + assertThat(sortedPoms.get(1).getMarkers().findFirst(MavenResolutionResult.class).get().getPom().getArtifactId()).isEqualTo("moduleA"); } + } \ No newline at end of file diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/project/parser/ProjectContextInitializerTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/project/parser/ProjectContextInitializerTest.java index 01cfad1ed..4a4286e4e 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/project/parser/ProjectContextInitializerTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/project/parser/ProjectContextInitializerTest.java @@ -291,7 +291,7 @@ void test() { ApplicationEventPublisher eventPublisher = mock(ApplicationEventPublisher.class); RewriteExecutionContext executionContext = new RewriteExecutionContext(eventPublisher); List resources = scanCommand.scanProjectRoot(projectDirectory.toString()); - ProjectContext projectContext = sut.initProjectContext(projectDirectory, resources, executionContext); + ProjectContext projectContext = sut.initProjectContext(projectDirectory, resources); List> projectResources = projectContext.getProjectResources().list(); //assertThat(projectDirectory.toAbsolutePath().resolve(".git")).exists(); diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/project/resource/TestProjectContext.java b/components/sbm-core/src/test/java/org/springframework/sbm/project/resource/TestProjectContext.java index ef57b4e72..b04eea190 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/project/resource/TestProjectContext.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/project/resource/TestProjectContext.java @@ -23,10 +23,7 @@ import org.springframework.core.annotation.Order; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; -import org.springframework.sbm.build.impl.MavenSettingsInitializer; -import org.springframework.sbm.build.impl.OpenRewriteMavenBuildFile; -import org.springframework.sbm.build.impl.RewriteMavenArtifactDownloader; -import org.springframework.sbm.build.impl.RewriteMavenParser; +import org.springframework.sbm.build.impl.*; import org.springframework.sbm.build.resource.BuildFileResourceWrapper; import org.springframework.sbm.engine.context.ProjectContext; import org.springframework.sbm.engine.context.ProjectContextFactory; @@ -89,23 +86,24 @@ * TestProjectContext.buildProjectContext() * .addJavaSources("class Foo{}", "class Bar{}") * .build(); - * * ..... * - */ - /* To - * - *

* == Examples - *

+ * * === ProjectContext with a JavaSource - *

+ * * [source, java] * .... * ProjectContext context = TestProjectContext.buildProjectContext() * .withJavaSources("public class Foo{}") * .build(); * .... + * + * + */ + /* To + * + *

*

* === ProjectContext with a JavaSource and classpath @@ -200,14 +198,21 @@ public static Builder buildProjectContext() { /** * Build {@code ProjectContext} with default project root of absolute path of './dummy-test-path' *

- * Be aware that @EventListener annotations are not called, {@code eventPublisher} can be provided to verify calls. - * * @param eventPublisher the eventPublisher to use */ public static Builder buildProjectContext(ApplicationEventPublisher eventPublisher) { return new Builder(DEFAULT_PROJECT_ROOT, eventPublisher); } + /** + * Build {@code ProjectContext} with default project root of absolute path of './dummy-test-path' + *

+ * @param eventPublisher the eventPublisher to use + */ + public static Builder buildProjectContext(ApplicationEventPublisher eventPublisher, RewriteJavaParser rewriteJavaParser) { + return new Builder(DEFAULT_PROJECT_ROOT, eventPublisher, rewriteJavaParser); + } + /** * @return the default project root dir */ @@ -254,6 +259,7 @@ public static class Builder { private Optional springVersion = Optional.empty(); private JavaParser javaParser; + private RewriteMavenParser mavenParser = new RewriteMavenParser(new MavenSettingsInitializer());; public Builder(Path projectRoot) { this.projectRoot = projectRoot; @@ -267,6 +273,11 @@ public Builder(Path projectRoot, ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } + public Builder(Path defaultProjectRoot, ApplicationEventPublisher eventPublisher, RewriteJavaParser rewriteJavaParser) { + this(defaultProjectRoot, eventPublisher); + this.javaParser = rewriteJavaParser; + } + public Builder withProjectRoot(Path projectRoot) { this.projectRoot = projectRoot.toAbsolutePath().normalize(); return this; @@ -464,16 +475,18 @@ public ProjectContext build() { verifyValidBuildFileSetup(); if(!containsAnyPomXml()) { - String xml = "\n" + - "\n" + - " 4.0.0\n" + - "{{springParentPom}}" + - " com.example\n" + - " dummy-root\n" + - " 0.1.0-SNAPSHOT\n" + - " jar\n" + - "{{dependencies}}" + - "\n"; + String xml = """ + + + 4.0.0 + {{springParentPom}} + com.example + dummy-root + 0.1.0-SNAPSHOT + jar + {{dependencies}} + + """; xml = xml .replace("{{dependencies}}", getDependenciesSection()) @@ -499,8 +512,9 @@ public ProjectContext build() { JavaRefactoringFactory javaRefactoringFactory = new JavaRefactoringFactoryImpl(projectResourceSetHolder); // create ProjectResourceWrapperRegistry and register Java and Maven resource wrapper - BuildFileResourceWrapper buildFileResourceWrapper = new BuildFileResourceWrapper( - eventPublisher); + MavenBuildFileRefactoringFactory mavenBuildFileRefactoringFactory = new MavenBuildFileRefactoringFactory(projectResourceSetHolder, mavenParser); + BuildFileResourceWrapper buildFileResourceWrapper = new BuildFileResourceWrapper(eventPublisher, + mavenBuildFileRefactoringFactory); resourceWrapperList.add(buildFileResourceWrapper); JavaSourceProjectResourceWrapper javaSourceProjectResourceWrapper = new JavaSourceProjectResourceWrapper(javaRefactoringFactory, javaParser); resourceWrapperList.add(javaSourceProjectResourceWrapper); @@ -512,7 +526,7 @@ public ProjectContext build() { ProjectContextInitializer projectContextInitializer = createProjectContextInitializer(projectContextFactory); // create ProjectContext - ProjectContext projectContext = projectContextInitializer.initProjectContext(projectRoot, scannedResources, new RewriteExecutionContext(eventPublisher)); + ProjectContext projectContext = projectContextInitializer.initProjectContext(projectRoot, scannedResources); // replace with mocks if (mockedBuildFile != null) { @@ -552,8 +566,6 @@ private ProjectContextInitializer createProjectContextInitializer(ProjectContext new ResourceParser.ResourceFilter(), eventPublisher); - RewriteMavenParser mavenParser = new RewriteMavenParser(new MavenSettingsInitializer()); - MavenArtifactDownloader artifactDownloader = new RewriteMavenArtifactDownloader(); JavaProvenanceMarkerFactory javaProvenanceMarkerFactory = new JavaProvenanceMarkerFactory(); diff --git a/components/sbm-openrewrite/src/main/java/org/openrewrite/maven/spring/UpgradeUnmanagedSpringProject.java b/components/sbm-openrewrite/src/main/java/org/openrewrite/maven/spring/UpgradeUnmanagedSpringProject.java index 4af8c2dd8..4f39f1a64 100644 --- a/components/sbm-openrewrite/src/main/java/org/openrewrite/maven/spring/UpgradeUnmanagedSpringProject.java +++ b/components/sbm-openrewrite/src/main/java/org/openrewrite/maven/spring/UpgradeUnmanagedSpringProject.java @@ -16,6 +16,7 @@ package org.openrewrite.maven.spring; +import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; @@ -23,6 +24,7 @@ import org.openrewrite.TreeVisitor; import org.openrewrite.marker.SearchResult; import org.openrewrite.maven.ChangePropertyValue; +import org.openrewrite.maven.MavenDownloadingException; import org.openrewrite.maven.MavenIsoVisitor; import org.openrewrite.maven.UpdateMavenModel; import org.openrewrite.maven.internal.MavenPomDownloader; @@ -36,6 +38,7 @@ import java.util.*; import java.util.regex.Pattern; +@Slf4j public class UpgradeUnmanagedSpringProject extends Recipe { public static final String SPRINGBOOT_GROUP = "org.springframework.boot"; @@ -147,7 +150,7 @@ private void mayBeUpdateVersion(String key, Xml.Tag tag) { } if (versionValue.startsWith("${")) { String propertyName = versionValue.substring(2, versionValue.length() - 1); - version.ifPresent(xml -> doAfterVisit(new ChangePropertyValue(propertyName, dependencyVersion, true))); + version.ifPresent(xml -> doAfterVisit(new ChangePropertyValue(propertyName, dependencyVersion, true, true))); } else { version.ifPresent(xml -> doAfterVisit(new ChangeTagValueVisitor(xml, dependencyVersion))); } @@ -178,17 +181,23 @@ private Map buildDependencyMap() { String relativePath = ""; ResolvedPom containingPom = null; List repositories = new ArrayList<>(); - repositories.add(new MavenRepository("repository.spring.milestone", "https://repo.spring.io/milestone", true, true, null, null)); - repositories.add(new MavenRepository("spring-snapshot", "https://repo.spring.io/snapshot", false, true, null, null)); - repositories.add(new MavenRepository("spring-release", "https://repo.spring.io/release", true, false, null, null)); - Pom pom = downloader.download(gav, relativePath, containingPom, repositories); - ResolvedPom resolvedPom = pom.resolve(List.of(), downloader, repositories, new InMemoryExecutionContext()); - List dependencyManagement = resolvedPom.getDependencyManagement(); + repositories.add(new MavenRepository("repository.spring.milestone", "https://repo.spring.io/milestone", "true", "true", null, null)); + repositories.add(new MavenRepository("spring-snapshot", "https://repo.spring.io/snapshot", "false", "true", null, null)); + repositories.add(new MavenRepository("spring-release", "https://repo.spring.io/release", "true", "false", null, null)); + Pom pom = null; + ResolvedPom resolvedPom = null; Map dependencyMap = new HashMap<>(); - dependencyManagement - .stream() - .filter(d -> d.getVersion() != null) - .forEach(d -> dependencyMap.put(d.getGroupId() + ":" + d.getArtifactId().toLowerCase(), d.getVersion())); + try { + pom = downloader.download(gav, relativePath, containingPom, repositories); + resolvedPom = pom.resolve(List.of(), downloader, repositories, new InMemoryExecutionContext()); + List dependencyManagement = resolvedPom.getDependencyManagement(); + dependencyManagement + .stream() + .filter(d -> d.getVersion() != null) + .forEach(d -> dependencyMap.put(d.getGroupId() + ":" + d.getArtifactId().toLowerCase(), d.getVersion())); + } catch (MavenDownloadingException e) { + log.error("Error while downloading dependency.", e); + } return dependencyMap; } } diff --git a/components/sbm-openrewrite/src/test/java/org/openrewrite/maven/MavenParserTest.java b/components/sbm-openrewrite/src/test/java/org/openrewrite/maven/MavenParserTest.java new file mode 100644 index 000000000..0335ab0d7 --- /dev/null +++ b/components/sbm-openrewrite/src/test/java/org/openrewrite/maven/MavenParserTest.java @@ -0,0 +1,423 @@ +/* + * 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.openrewrite.maven; + +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.Parser; +import org.openrewrite.maven.cache.InMemoryMavenPomCache; +import org.openrewrite.maven.tree.MavenResolutionResult; +import org.openrewrite.maven.tree.ResolvedDependency; +import org.openrewrite.maven.tree.Scope; +import org.openrewrite.xml.tree.Xml; +import org.springframework.sbm.GitHubIssue; +import org.springframework.sbm.Problem; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.*; + +/** + * @author Fabian Krüger + */ +public class MavenParserTest { + + // TODO: Proof of incorrect MavenResolutionResult for + @GitHubIssue("https://github.com/openrewrite/rewrite/issues/2601") + @Test + void mavenParserAddsMavenResolutionResultMarkerWithDuplicateDependencies() { + final String parentPom = """ + + example-project-parent + com.example + 1.0.0-SNAPSHOT + 4.0.0 + pom + + + 17 + 11 + + + + module1 + module2 + + + + + jcenter + jcenter + https://jcenter.bintray.com + + + mavencentral + mavencentral + https://repo.maven.apache.org/maven2 + + + + + """; + + final String module1Pom = """ + + + example-project-parent + com.example + 1.0.0-SNAPSHOT + + module1 + 4.0.0 + + + 11 + 11 + + + + + org.jetbrains + annotations + 23.0.0 + test + + + + + """; + + final String module2Pom = """ + + + example-project-parent + com.example + 1.0.0-SNAPSHOT + + module2 + 4.0.0 + + + 11 + 11 + + + + + org.openjfx + javafx-swing + 11.0.2 + + + + + """; + + MavenParser mavenParser = MavenParser.builder().build(); + List parsedPomFiles = mavenParser.parse(parentPom, module1Pom, module2Pom); + MavenResolutionResult parentPomMarker = parsedPomFiles.get(0).getMarkers().findFirst(MavenResolutionResult.class).get(); + assertThat(parentPomMarker.getDependencies().get(Scope.Provided)).isEmpty(); + assertThat(parentPomMarker.getDependencies().get(Scope.Runtime)).isEmpty(); + assertThat(parentPomMarker.getDependencies().get(Scope.Compile)).isEmpty(); + assertThat(parentPomMarker.getDependencies().get(Scope.Test)).isEmpty(); + + MavenResolutionResult module1PomMarker = parsedPomFiles.get(1).getMarkers().findFirst(MavenResolutionResult.class).get(); + assertThat(module1PomMarker.getDependencies().get(Scope.Provided)).isEmpty(); + assertThat(module1PomMarker.getDependencies().get(Scope.Runtime)).isEmpty(); + assertThat(module1PomMarker.getDependencies().get(Scope.Compile)).isEmpty(); + assertThat(module1PomMarker.getDependencies().get(Scope.Test)).isNotEmpty(); + assertThat(module1PomMarker.getDependencies().get(Scope.Test).get(0).getGav().toString()).isEqualTo("org.jetbrains:annotations:23.0.0"); + + MavenResolutionResult module2PomMarker = parsedPomFiles.get(2).getMarkers().findFirst(MavenResolutionResult.class).get(); + // expected +// assertThat(module2PomMarker.getDependencies().get(Scope.Provided)).hasSize(2); +// assertThat(module2PomMarker.getDependencies().get(Scope.Runtime)).hasSize(2); +// assertThat(module2PomMarker.getDependencies().get(Scope.Compile)).hasSize(2); +// assertThat(module2PomMarker.getDependencies().get(Scope.Test)).hasSize(2); + + // actual + assertThat(module2PomMarker.getDependencies().get(Scope.Provided)).hasSize(6); + assertThat(module2PomMarker.getDependencies().get(Scope.Provided).get(0).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + assertThat(module2PomMarker.getDependencies().get(Scope.Provided).get(0).getDependencies()).hasSize(2); + // "org.openjfx:javafx-swing:11.0.2" depends on "org.openjfx:javafx-swing:11.0.2" ? + assertThat(module2PomMarker.getDependencies().get(Scope.Provided).get(0).getDependencies().get(0).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + assertThat(module2PomMarker.getDependencies().get(Scope.Provided).get(0).getDependencies().get(1).getGav().toString()).isEqualTo("org.openjfx:javafx-graphics:11.0.2"); + // "org.openjfx:javafx-swing:11.0.2" twice + assertThat(module2PomMarker.getDependencies().get(Scope.Provided).get(1).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + // also without dependencies ? + assertThat(module2PomMarker.getDependencies().get(Scope.Provided).get(1).getDependencies()).isEmpty(); + + assertThat(module2PomMarker.getDependencies().get(Scope.Runtime)).hasSize(6); + assertThat(module2PomMarker.getDependencies().get(Scope.Runtime).get(0).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + assertThat(module2PomMarker.getDependencies().get(Scope.Runtime).get(0).getDependencies()).hasSize(2); + // "org.openjfx:javafx-swing:11.0.2" depends on "org.openjfx:javafx-swing:11.0.2" ? + assertThat(module2PomMarker.getDependencies().get(Scope.Runtime).get(0).getDependencies().get(0).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + assertThat(module2PomMarker.getDependencies().get(Scope.Runtime).get(0).getDependencies().get(1).getGav().toString()).isEqualTo("org.openjfx:javafx-graphics:11.0.2"); + // "org.openjfx:javafx-swing:11.0.2" twice + assertThat(module2PomMarker.getDependencies().get(Scope.Runtime).get(1).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + // also without dependencies ? + assertThat(module2PomMarker.getDependencies().get(Scope.Runtime).get(1).getDependencies()).isEmpty(); + + assertThat(module2PomMarker.getDependencies().get(Scope.Compile)).hasSize(6); + assertThat(module2PomMarker.getDependencies().get(Scope.Compile).get(0).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + assertThat(module2PomMarker.getDependencies().get(Scope.Compile).get(0).getDependencies()).hasSize(2); + // "org.openjfx:javafx-swing:11.0.2" depends on "org.openjfx:javafx-swing:11.0.2" ? + assertThat(module2PomMarker.getDependencies().get(Scope.Compile).get(0).getDependencies().get(0).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + assertThat(module2PomMarker.getDependencies().get(Scope.Compile).get(0).getDependencies().get(1).getGav().toString()).isEqualTo("org.openjfx:javafx-graphics:11.0.2"); + // "org.openjfx:javafx-swing:11.0.2" twice + assertThat(module2PomMarker.getDependencies().get(Scope.Compile).get(1).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + // also without dependencies ? + assertThat(module2PomMarker.getDependencies().get(Scope.Compile).get(1).getDependencies()).isEmpty(); + + assertThat(module2PomMarker.getDependencies().get(Scope.Test)).hasSize(6); + assertThat(module2PomMarker.getDependencies().get(Scope.Test).get(0).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + assertThat(module2PomMarker.getDependencies().get(Scope.Test).get(0).getDependencies()).hasSize(2); + // "org.openjfx:javafx-swing:11.0.2" depends on "org.openjfx:javafx-swing:11.0.2" ? + assertThat(module2PomMarker.getDependencies().get(Scope.Test).get(0).getDependencies().get(0).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + assertThat(module2PomMarker.getDependencies().get(Scope.Test).get(0).getDependencies().get(1).getGav().toString()).isEqualTo("org.openjfx:javafx-graphics:11.0.2"); + // "org.openjfx:javafx-swing:11.0.2" twice + assertThat(module2PomMarker.getDependencies().get(Scope.Test).get(1).getGav().toString()).isEqualTo("org.openjfx:javafx-swing:11.0.2"); + // also without dependencies ? + assertThat(module2PomMarker.getDependencies().get(Scope.Test).get(1).getDependencies()).isEmpty(); + } + + @Test + void newParsingShouldRefreshModel() { + Xml.Document document = MavenParser.builder().build().parse(""" + + + 4.0.0 + org.springframework.sbm.examples + artifact-id + jar + 0.0.1-SNAPSHOT + + """).get(0); + + assertThat(document.getMarkers().findFirst(MavenResolutionResult.class).get().getPom().getDependencyManagement()).isEmpty(); + + Xml.Document document1 = MavenParser.builder().build().parse(""" + + + 4.0.0 + org.springframework.sbm.examples + artifact-id + pom + 0.0.1-SNAPSHOT + + + + groupId + artifactId + version + jar + compile + + + + + """).get(0); + + assertThat(document1.getMarkers().findFirst(MavenResolutionResult.class).get().getPom().getDependencyManagement()).isNotEmpty(); + } + + @Test + void test_renameMe() { + MavenParser mavenParser = MavenParser.builder().build(); + Parser.Input parserInput = new Parser.Input( + Path.of("moduleA/pom.xml"), + null, + () -> new ByteArrayInputStream( + """ + + + 4.0.0 + com.example + parent + 0.1 + pom + + moduleA + + + """ + .getBytes(StandardCharsets.UTF_8)), + !Files.exists(Path.of("moduleA/pom.xml")) + ); + List newMavenFiles = mavenParser.parseInputs(List.of(parserInput), null, new InMemoryExecutionContext((t) -> t.printStackTrace())); +// System.out.println(newMavenFiles.get(0).printAll()); + } + + @Test + void parsePomsWithInvalidDeps() { + @Language("xml") + String parentPomXml = + """ + + + 4.0.0 + com.example + parent + 1.0.0 + pom + + module1 + + + + + javax.validation + + javax.validation-api + 2.0.0.Final + + + + + """; + + @Language("xml") + String module1PomXml = + """ + + + 4.0.0 + + com.example + parent + 1.0.0 + + + module1 + jar + + + + javax.validation + javax.validation-api + + + + """; + MavenParser mavenParser = MavenParser.builder().build(); + Xml.Document parentPom = mavenParser.parse(parentPomXml).get(0); + Optional mavenResolutionResult = parentPom.getMarkers().findFirst(MavenResolutionResult.class); + assertThat(mavenResolutionResult).isPresent(); + assertThatExceptionOfType(UncheckedMavenDownloadingException.class) + .isThrownBy(() -> mavenParser.parse(parentPomXml, module1PomXml)) + .describedAs("Maven visitors should not be visiting XML documents without a Maven marker"); + } + + @Test + void parsePomFromTextWithoutMarkers() { + Xml.Document sut = MavenParser.builder().build().parse( + new InMemoryExecutionContext((e) -> e.printStackTrace()), + """ + + + 4.0.0 + com.example + parent + 0.1 + pom + + value1 + + + moduleA + + + """ + ).get(0); + assertThat(sut).isNotNull(); + } + + + @Problem(description = "java.io.UncheckedIOException: Failed to parse pom", since = "7.18.2", fixedIn = "7.23.0") + void testParsingPomWithEmptyDependenciesSection() { + String pomXml = "\n" + + "\n" + + " 4.0.0\n" + + " com.example\n" + + " foo-bar\n" + + " 0.1.0-SNAPSHOT\n" + + " \n" + + ""; + + List parse = MavenParser.builder().build().parse(pomXml); + assertThat(parse).isNotEmpty(); + } + + @Test + void test(@TempDir Path tempDir) { + String pomXml = + "\n" + + " 4.0.0\n" + + " foo\n" + + " bar\n" + + " 0.0.1-SNAPSHOT\n" + + " foobat\n" + + " \n" + + " \n" + + " jcenter\n" + + " jcenter\n" + + " https://jcenter.bintray.com\n" + + " \n" + + " \n" + + " mavencentral\n" + + " mavencentral\n" + + " https://repo.maven.apache.org/maven2\n" + + " \n" + + " " + + " \n" + + " \n" + + " org.apache.tomee\n" + + " openejb-core-hibernate\n" + + " 8.0.5\n" + + " pom\n" + + " \n" + + " \n" + + ""; + + Xml.Document document = MavenParser.builder().build().parse(pomXml).get(0); + MavenResolutionResult r = document.getMarkers().findFirst(MavenResolutionResult.class).get(); + + InMemoryExecutionContext executionContext = new InMemoryExecutionContext((t) -> System.out.println(t.getMessage())); + MavenExecutionContextView ctx = MavenExecutionContextView.view(executionContext); + ctx.setPomCache(new InMemoryMavenPomCache()); + List resolvedDependencies = r.getDependencies().get(Scope.Provided); + assertThat(r.getDependencies()).hasSize(4); + assertThat(resolvedDependencies).hasSize(81); // FIXME: #7 was 81 before ?! + } + +} diff --git a/components/sbm-openrewrite/src/test/java/org/openrewrite/maven/UpdateMavenModelTest.java b/components/sbm-openrewrite/src/test/java/org/openrewrite/maven/UpdateMavenModelTest.java new file mode 100644 index 000000000..7c06cb851 --- /dev/null +++ b/components/sbm-openrewrite/src/test/java/org/openrewrite/maven/UpdateMavenModelTest.java @@ -0,0 +1,155 @@ +/* + * 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.openrewrite.maven; + +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.Test; +import org.openrewrite.*; +import org.openrewrite.maven.tree.MavenResolutionResult; +import org.openrewrite.xml.ChangeTagValueVisitor; +import org.openrewrite.xml.tree.Xml; +import org.springframework.sbm.GitHubIssue; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Fabian Krüger + */ +public class UpdateMavenModelTest { + + @GitHubIssue("https://github.com/openrewrite/rewrite/issues/2624") + @Test + void changesInPluginConfigurationAreNotUpdatedByUpdateMavenModel() { + // Having a pom with configured plugin + @Language("xml") + String pom = """ + + + 4.0.0 + com.example + parent + 1.0 + pom + + 17 + 17 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.target} + ${maven.compiler.source} + + + + + + """; + List pomXmls = MavenParser.builder().build().parse(pom); + + // changing a property in the configuration + Recipe setMavenCompilerPluginSourceTo17 = new Recipe() { + @Override + public String getDisplayName() { + return ""; + } + + @Override + protected TreeVisitor getVisitor() { + return new MavenIsoVisitor() { + + @Override + public Xml.Document visitDocument(Xml.Document document, ExecutionContext executionContext) { + Xml.Document d = super.visitDocument(document, executionContext); + Xml.Tag sourceTag = d + .getRoot() + .getChildren("build") + .get(0) + .getChild("plugins") + .get() + .getChild("plugin") + .get() + .getChild("configuration") + .get() + .getChild("source") + .get(); + doAfterVisit(new ChangeTagValueVisitor<>(sourceTag, "17")); + return d; + } + }; + } + }; + + RecipeRun run = setMavenCompilerPluginSourceTo17.run(pomXmls); + SourceFile after = run.getResults().get(0).getAfter(); + // The XML reflects the change + assertThat(after.printAll()).isEqualTo( + """ + + + 4.0.0 + com.example + parent + 1.0 + pom + + 17 + 17 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.target} + 17 + + + + + + """); + + // But not the model doesn't + assertThat(after.getMarkers().findFirst(MavenResolutionResult.class).get().getPom().getRequested().getPlugins().get(0).getConfiguration().toString()).isEqualTo("{\"target\":\"${maven.compiler.target}\",\"source\":\"${maven.compiler.source}\"}"); + + // Using UpdateMavenModel to update the model + SourceFile afterUpdateModel = new Recipe() { + @Override + public String getDisplayName() { + return ""; + } + + @Override + protected TreeVisitor getVisitor() { + return new UpdateMavenModel<>(); + } + }.run(List.of(after)).getResults().get(0).getAfter(); + + // But the change is not reflected in model + assertThat(afterUpdateModel.getMarkers().findFirst(MavenResolutionResult.class).get().getPom().getRequested().getPlugins().get(0).getConfiguration().toString()).isEqualTo("{\"target\":\"${maven.compiler.target}\",\"source\":\"${maven.compiler.source}\"}"); + + // When parsing the modified pom the change ois reflected + Xml.Document afterReparse = MavenParser.builder().build().parse(afterUpdateModel.printAll()).get(0); + assertThat(afterReparse.getMarkers().findFirst(MavenResolutionResult.class).get().getPom().getRequested().getPlugins().get(0).getConfiguration().toString()).isEqualTo("{\"target\":\"${maven.compiler.target}\",\"source\":\"17\"}"); + } +} diff --git a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/openrewrite/maven/MavenParserTest.java b/components/sbm-openrewrite/src/test/java/org/springframework/sbm/openrewrite/maven/MavenParserTest.java deleted file mode 100644 index 1e7fdd1f7..000000000 --- a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/openrewrite/maven/MavenParserTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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.openrewrite.maven; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.maven.MavenExecutionContextView; -import org.openrewrite.maven.MavenParser; -import org.openrewrite.maven.cache.InMemoryMavenPomCache; -import org.openrewrite.maven.cache.RocksdbMavenPomCache; -import org.openrewrite.maven.internal.MavenPomDownloader; -import org.openrewrite.maven.tree.MavenResolutionResult; -import org.openrewrite.maven.tree.Pom; -import org.openrewrite.maven.tree.ResolvedDependency; -import org.openrewrite.maven.tree.Scope; -import org.openrewrite.xml.tree.Xml; -import org.springframework.sbm.Problem; - -import java.nio.file.Path; -import java.util.HashMap; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public class MavenParserTest { - - @Problem(description = "java.io.UncheckedIOException: Failed to parse pom", since = "7.18.2", fixedIn = "7.23.0") - void testParsingPomWithEmptyDependenciesSection() { - String pomXml = "\n" + - "\n" + - " 4.0.0\n" + - " com.example\n" + - " foo-bar\n" + - " 0.1.0-SNAPSHOT\n" + - " \n" + - ""; - - List parse = MavenParser.builder().build().parse(pomXml); - assertThat(parse).isNotEmpty(); - } - - @Test - void test(@TempDir Path tempDir) { - String pomXml = - "\n" + - " 4.0.0\n" + - " foo\n" + - " bar\n" + - " 0.0.1-SNAPSHOT\n" + - " foobat\n" + - " \n" + - " \n" + - " jcenter\n" + - " jcenter\n" + - " https://jcenter.bintray.com\n" + - " \n" + - " \n" + - " mavencentral\n" + - " mavencentral\n" + - " https://repo.maven.apache.org/maven2\n" + - " \n" + - " " + - " \n" + - " \n" + - " org.apache.tomee\n" + - " openejb-core-hibernate\n" + - " 8.0.5\n" + - " pom\n" + - " \n" + - " \n" + - ""; - - Xml.Document document = MavenParser.builder().build().parse(pomXml).get(0); - MavenResolutionResult r = document.getMarkers().findFirst(MavenResolutionResult.class).get(); - - InMemoryExecutionContext executionContext = new InMemoryExecutionContext((t) -> System.out.println(t.getMessage())); - MavenExecutionContextView ctx = MavenExecutionContextView.view(executionContext); - ctx.setPomCache(new InMemoryMavenPomCache()); - List resolvedDependencies = r.getDependencies().get(Scope.Provided); - assertThat(r.getDependencies()).hasSize(4); - assertThat(resolvedDependencies).hasSize(81); // FIXME: #7 was 81 before ?! - } - -} diff --git a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/MavenDependencyDownloadTest.java b/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/MavenDependencyDownloadTest.java index 78e0cc1a5..e5e61bec2 100644 --- a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/MavenDependencyDownloadTest.java +++ b/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/MavenDependencyDownloadTest.java @@ -15,9 +15,9 @@ */ package org.springframework.sbm.support.openrewrite.api; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.io.TempDir; import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.maven.MavenDownloadingException; import org.openrewrite.maven.MavenExecutionContextView; import org.openrewrite.maven.MavenParser; import org.openrewrite.maven.cache.RocksdbMavenPomCache; @@ -32,16 +32,16 @@ import java.util.HashMap; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; + public class MavenDependencyDownloadTest { @Problem( -// description = "Some dependencies cannot be downloaded because the resolved resource path is wrong", -// version = "7.16.3" description = "Fails with containingPom being null", - since = "7.18.2" + since = "7.18.2", + fixedIn = "7.35.0" ) - @Disabled - void downloadDependencies(@TempDir Path tempDir) { + void downloadDependencies(@TempDir Path tempDir) throws MavenDownloadingException { InMemoryExecutionContext executionContext = new InMemoryExecutionContext((t) -> System.out.println(t.getMessage())); MavenExecutionContextView ctx = MavenExecutionContextView.view(executionContext); ctx.setPomCache(new RocksdbMavenPomCache(tempDir.resolve("rewrite-cache"))); @@ -52,23 +52,8 @@ void downloadDependencies(@TempDir Path tempDir) { String relativePath = ""; ResolvedPom containingPom = null; Pom download = mavenPomDownloader.download(gav, relativePath, containingPom, List.of()); -// assertThat(download).isNull(); + assertThat(download).isNotNull(); + assertThat(download.getSourcePath().toString()).isEqualTo("com.h2database/h2/1.4.200"); } - @Disabled - void downloadDependencies2(@TempDir Path tempDir) { - InMemoryExecutionContext executionContext = new InMemoryExecutionContext((t) -> System.out.println(t.getMessage())); - MavenExecutionContextView ctx = MavenExecutionContextView.view(executionContext); - ctx.setPomCache(new RocksdbMavenPomCache(tempDir.resolve("rewrite-cache"))); - - HashMap projectPoms = new HashMap<>(); - MavenPomDownloader mavenPomDownloader = new MavenPomDownloader(projectPoms, ctx); - GroupArtifactVersion gav = new GroupArtifactVersion("com.h2database", "h2", "1.4.200"); - String relativePath = ""; - ResolvedPom containingPom = null; - Xml.Document document = MavenParser.builder().build().parse("").get(0); - - Pom download = mavenPomDownloader.download(gav, relativePath, containingPom, List.of()); -// assertThat(download).isNull(); - } } diff --git a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/RemoveUnusedImportsTest.java b/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/RemoveUnusedImportsTest.java index dbcee8eab..7b81c0a58 100644 --- a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/RemoveUnusedImportsTest.java +++ b/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/RemoveUnusedImportsTest.java @@ -17,7 +17,6 @@ import org.openrewrite.RecipeRun; import org.springframework.sbm.java.OpenRewriteTestSupport; -import org.springframework.sbm.support.openrewrite.java.MavenPomDownloaderTest; import org.junit.jupiter.api.Test; import org.openrewrite.java.RemoveUnusedImports; import org.openrewrite.java.tree.J; @@ -29,7 +28,6 @@ public class RemoveUnusedImportsTest { @Test void removeUnusedImports() { - MavenPomDownloaderTest mavenPomDownloaderTest; String javaCode = "import org.springframework.transaction.annotation.Propagation;\n" + "import org.springframework.transaction.annotation.Transactional;\n" + diff --git a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/UpgradeDependencyVersionTest.java b/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/UpgradeDependencyVersionTest.java index 68aedff54..ef7564641 100644 --- a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/UpgradeDependencyVersionTest.java +++ b/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/api/UpgradeDependencyVersionTest.java @@ -15,7 +15,7 @@ */ package org.springframework.sbm.support.openrewrite.api; -import org.junit.jupiter.api.Disabled; +import org.intellij.lang.annotations.Language; import org.junit.jupiter.api.Test; import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.RecipeRun; @@ -28,75 +28,73 @@ import static org.assertj.core.api.Assertions.assertThat; -@Disabled public class UpgradeDependencyVersionTest { + @Language("xml") public static final String POM_XML = - "\n" - + "\n" - + " 4.0.0\n" -// + " \n" -// + " org.springframework.boot\n" -// + " spring-boot-starter-parent\n" -// + " 2.4.5\n" -// + " \n" -// + " \n" - + " com.example\n" - + " boot-23-app\n" - + " 0.0.1-SNAPSHOT\n" - + " boot-23-app\n" - + " Demo project for Spring Boot\n" - + " \n" - + " 11\n" - + " \n" - + " \n" - + " \n" - + " org.springframework.boot\n" - + " spring-boot-starter-data-jpa\n" - + " 2.4.5\n" - + " \n" - + " \n" - + " org.springframework.boot\n" - + " spring-boot-starter-test\n" - + " test\n" - + " 2.4.5\n" - + " \n" - + " \n" - + ""; + """ + + + 4.0.0 + com.example + boot-23-app + 0.0.1-SNAPSHOT + boot-23-app + Demo project for Spring Boot + + 11 + + + + org.springframework.boot + spring-boot-starter-data-jpa + 2.4.5 + + + org.springframework.boot + spring-boot-starter-test + test + 2.4.5 + + + + """; private final List mavens = MavenParser.builder().build().parse(POM_XML); @Test - @Disabled void testUpgradeDependency() { + @Language("xml") String expectedPomXml = - "\n" - + "\n" + - " 4.0.0\n" + - " com.example\n" + - " boot-23-app\n" + - " 0.0.1-SNAPSHOT\n" + - " boot-23-app\n" + - " Demo project for Spring Boot\n" + - " \n" + - " 11\n" + - " \n" + - " \n" + - " \n" + - " org.springframework.boot\n" + - " spring-boot-starter-data-jpa\n" + - " 2.4.5\n" + - " \n" + - " \n" + - " org.springframework.boot\n" + - " spring-boot-starter-test\n" + - " test\n" + - " 2.5.3\n" + - " \n" + - " \n" + - ""; + """ + + + 4.0.0 + com.example + boot-23-app + 0.0.1-SNAPSHOT + boot-23-app + Demo project for Spring Boot + + 11 + + + + org.springframework.boot + spring-boot-starter-data-jpa + 2.4.5 + + + org.springframework.boot + spring-boot-starter-test + test + 2.5.3 + + + + """; String groupId = "org.springframework.boot"; String artifactId = "spring-boot-starter-test"; @@ -109,44 +107,42 @@ void testUpgradeDependency() { } @Test - @Disabled void testUpgradeDependency_trustParent() { + @Language("xml") String expectedPomXml = - "\n" - + "\n" + - " 4.0.0\n" + - " \n" + - " com.example\n" + - " boot-23-app\n" + - " \n" + - " com.example\n" + - " boot-23-app\n" + - " 0.0.1-SNAPSHOT\n" + - " boot-23-app\n" + - " Demo project for Spring Boot\n" + - " \n" + - " 11\n" + - " \n" + - " \n" + - " \n" + - " org.springframework.boot\n" + - " spring-boot-starter-data-jpa\n" + - " 2.4.5\n" + - " \n" + - " \n" + - " org.springframework.boot\n" + - " spring-boot-starter-test\n" + - " test\n" + - " 2.6.1\n" + - " \n" + - " \n" + - ""; + """ + + + 4.0.0 + com.example + boot-23-app + 0.0.1-SNAPSHOT + boot-23-app + Demo project for Spring Boot + + 11 + + + + org.springframework.boot + spring-boot-starter-data-jpa + 2.4.5 + + + org.springframework.boot + spring-boot-starter-test + test + 2.5.3 + + + + """; String groupId = "org.springframework.boot"; String artifactId = "spring-boot-starter-test"; String version = "2.5.3"; - UpgradeDependencyVersion sut = new UpgradeDependencyVersion(groupId, artifactId, version, null, true); + UpgradeDependencyVersion sut = new UpgradeDependencyVersion(groupId, artifactId, version, null, true, List.of()); RecipeRun recipeRun = sut.run(mavens); @@ -154,40 +150,42 @@ void testUpgradeDependency_trustParent() { } @Test - @Disabled void testUpgradeDependency_latestReleaseVersion() { + @Language("xml") String expectedPomXml = - "\n" - + "\n" + - " 4.0.0\n" + - " com.example\n" + - " boot-23-app\n" + - " 0.0.1-SNAPSHOT\n" + - " boot-23-app\n" + - " Demo project for Spring Boot\n" + - " \n" + - " 11\n" + - " \n" + - " \n" + - " \n" + - " org.springframework.boot\n" + - " spring-boot-starter-data-jpa\n" + - " 2.4.5\n" + - " \n" + - " \n" + - " org.springframework.boot\n" + - " spring-boot-starter-test\n" + - " test\n" + - " 2.5.3\n" + - " \n" + - " \n" + - ""; + """ + + + 4.0.0 + com.example + boot-23-app + 0.0.1-SNAPSHOT + boot-23-app + Demo project for Spring Boot + + 11 + + + + org.springframework.boot + spring-boot-starter-data-jpa + 2.4.5 + + + org.springframework.boot + spring-boot-starter-test + test + 3.0.2 + + + + """; String groupId = "org.springframework.boot"; String artifactId = "spring-boot-starter-test"; String version = "latest.release"; - UpgradeDependencyVersion sut = new UpgradeDependencyVersion(groupId, artifactId, version, null, false); + UpgradeDependencyVersion sut = new UpgradeDependencyVersion(groupId, artifactId, version, null, false, List.of()); RecipeRun results = sut.run(mavens); @@ -199,7 +197,7 @@ void testUpgradeDependency_nullVersion() { String groupId = "org.springframework.boot"; String artifactId = "spring-boot-starter-test"; String version = null; - UpgradeDependencyVersion sut = new UpgradeDependencyVersion(groupId, artifactId, version, null, false); + UpgradeDependencyVersion sut = new UpgradeDependencyVersion(groupId, artifactId, version, null, false, List.of()); AtomicBoolean exceptionThrown = new AtomicBoolean(false); RecipeRun results = sut.run(mavens, new InMemoryExecutionContext((e) -> { diff --git a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/java/CodeCommentTest.java b/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/java/CodeCommentTest.java index 99d0b1b8f..b27a85247 100644 --- a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/java/CodeCommentTest.java +++ b/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/java/CodeCommentTest.java @@ -34,17 +34,24 @@ public class CodeCommentTest { @Test void markerAsComment() { - String javaCode = - "public class SomeTest {" + - " @Deprecated public void test() {}" + - "}"; + String javaCode = """ + public class SomeTest { + @Deprecated public void test() {} + } + """; J.CompilationUnit compilationUnit = OpenRewriteTestSupport.createCompilationUnitFromString(javaCode); - FindAnnotations findAnnotations = new FindAnnotations("@java.lang.Deprecated"); + FindAnnotations findAnnotations = new FindAnnotations("@java.lang.Deprecated", false); List cus = List.of(compilationUnit); RecipeRun recipeRun = findAnnotations.run(cus); - String markerText = "\n/*\n Found @Deprecated without attributes: \n - please set markedForRemoval \n - please set since \nhere --> */ "; + String markerText = """ + /* + Found @Deprecated without attributes: + - please set markedForRemoval + - please set since + here --> */ + """; J.CompilationUnit cu = (J.CompilationUnit) recipeRun.getResults().get(0).getAfter(); @@ -62,8 +69,10 @@ public M visitMarker(Marker marker, PrintOutputCapture*/@Deprecated public void test() {} + } + """.formatted(markerText)); } } diff --git a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/java/MavenPomDownloaderTest.java b/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/java/MavenPomDownloaderTest.java deleted file mode 100644 index 36dac64bb..000000000 --- a/components/sbm-openrewrite/src/test/java/org/springframework/sbm/support/openrewrite/java/MavenPomDownloaderTest.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * 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.support.openrewrite.java; - -import lombok.Getter; -import lombok.Setter; -import lombok.SneakyThrows; -import org.junit.jupiter.api.Test; -import org.openrewrite.ExecutionContext; -import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.maven.MavenParser; -import org.openrewrite.maven.cache.InMemoryMavenPomCache; -import org.openrewrite.maven.cache.MavenPomCache; -import org.openrewrite.maven.tree.MavenResolutionResult; -import org.openrewrite.xml.tree.Xml; - -import java.io.IOException; -import java.util.List; -import java.util.function.Consumer; - -public class MavenPomDownloaderTest { - @SneakyThrows - @Test - void downloadDbcp2_issue130() throws IOException { - - String pom = "\n" + - "\n" + - " 4.0.0\n" + - " org.springframework.sbm.examples\n" + - " jee-app\n" + - " jar\n" + - " 8.0.5-SNAPSHOT\n" + - " TomEE :: Examples :: JPA with Hibernate\n" + - " \n" + - " UTF-8\n" + - " \n" + - " \n" + - " \n" + - " jcenter\n" + - " jcenter\n" + - " https://jcenter.bintray.com\n" + - " \n" + - " \n" + - " mavencentral\n" + - " mavencentral\n" + - " https://repo.maven.apache.org/maven2\n" + - " \n" + - " \n" + - " \n" + - " install\n" + - " \n" + - " \n" + - " org.apache.maven.plugins\n" + - " maven-compiler-plugin\n" + - " 3.5.1\n" + - " \n" + - " 1.8\n" + - " 1.8\n" + - " \n" + - " \n" + - " \n" + - " org.tomitribe.transformer\n" + - " org.eclipse.transformer.maven\n" + - " 0.1.1a\n" + - " \n" + - " jakartaee9\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " run\n" + - " \n" + - " package\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " maven-war-plugin\n" + - " 3.2.3\n" + - " \n" + - " false\n" + - " \n" + - " \n" + - " \n" + - " org.apache.tomee.maven\n" + - " tomee-maven-plugin\n" + - " 8.0.1\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " org.apache.tomee\n" + - " javaee-api\n" + - " [8.0,)\n" + - " provided\n" + - " \n" + - " \n" + - " junit\n" + - " junit\n" + - " 4.12\n" + - " test\n" + - " \n" + - " \n" + - " \n" + -// " \n" + -// " org.apache.tomee\n" + -// " openejb-core-hibernate\n" + -// " 8.0.5\n" + -// " pom\n" + -// " \n" + - " org.hibernate\n" + - " hibernate-core\n" + - " 5.0.5.Final\n" + - " \n" + - " \n" + - " javax.ejb\n" + - " javax.ejb-api\n" + - " 3.2\n" + - " \n" + - " \n" + - " \n" + - " javax.enterprise\n" + - " cdi-api\n" + - " 1.2\n" + - " provided\n" + - " \n" + - " \n" + - " javax.enterprise.concurrent\n" + - " javax.enterprise.concurrent-api\n" + - " 1.0\n" + - " runtime\n" + - " \n" + - " \n" + - " javax.jms\n" + - " javax.jms-api\n" + - " 2.0\n" + - " runtime\n" + - " \n" + - " \n" + - " javax.json\n" + - " javax.json-api\n" + - " 1.0\n" + - " runtime\n" + - " \n" + - " \n" + - " javax.servlet\n" + - " javax.servlet-api\n" + - " 4.0.1\n" + - " \n" + - " \n" + - " javax.validation\n" + - " validation-api\n" + - " 1.1.0.Final\n" + - " runtime\n" + - " \n" + - " \n" + - " javax.ws.rs\n" + - " javax.ws.rs-api\n" + - " 2.1.1\n" + - " \n" + - " \n" + - " org.hibernate.javax.persistence\n" + - " hibernate-jpa-2.1-api\n" + - " 1.0.0.Final\n" + - " runtime\n" + - " \n" + - " \n" + - " org.jboss.spec.javax.annotation\n" + - " jboss-annotations-api_1.3_spec\n" + - " 1.0.1.Final\n" + - " runtime\n" + - " \n" + - " \n" + - " org.jboss.spec.javax.ws.rs\n" + - " jboss-jaxrs-api_2.1_spec\n" + - " 1.0.1.Final\n" + - " runtime\n" + - " \n" + - " \n" + - "\n"; - - ExceptionHolder exceptionHolder = new ExceptionHolder(); - Consumer onError = (e) -> { - e.printStackTrace(); - exceptionHolder.setException(e); - }; - ExecutionContext executionContext = new InMemoryExecutionContext(onError); - MavenPomCache cache = new InMemoryMavenPomCache(); - - List poms = MavenParser.builder().build().parse(pom); - - MavenResolutionResult model = poms.get(0).getMarkers().findFirst(MavenResolutionResult.class) - .orElseThrow(() -> new IllegalStateException("Maven visitors should not be visiting XML documents without a Maven marker")); - -// Parser.Input input = Parser.Input.fromString(pom); -// Xml.Document rawMaven = MavenParser.builder().build().parseInputs(List.of(input), null, executionContext); -// Map projectPoms = new HashMap<>(); -// Path pomPath = Path.of("./pom.xml"); -// projectPoms.put(pomPath, rawMaven); - - -// MavenPomDownloader mavenPomDownloader = new MavenPomDownloader(cache, projectPoms, executionContext); -// String groupId = "org.apache.commons"; -// String artifactId = "commons-dbcp2"; -// String version = "2.8.0"; -// @Nullable String relativePath = ""; -// @Nullable RawMaven containingPom = projectPoms.get(pomPath); -// Collection repositories = List.of(); -// mavenPomDownloader.download(groupId, artifactId, version, relativePath, containingPom, repositories, executionContext); -// -// // verify resource exists -// URL url = new URL("https://repo.maven.apache.org/maven2/org/apache/commons/commons-dbcp2/2.8.0/commons-dbcp2-2.8.0.jar"); -// HttpURLConnection huc = (HttpURLConnection) url.openConnection(); -// int responseCode = huc.getResponseCode(); -// assertThat(HttpURLConnection.HTTP_OK).isEqualTo(responseCode); - } - - @Getter - @Setter - class ExceptionHolder { - Throwable exception; - } -} diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/checks/RedeclaredDependenciesFinderTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/checks/RedeclaredDependenciesFinderTest.java index 8a7ad0724..0458494ae 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/checks/RedeclaredDependenciesFinderTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/checks/RedeclaredDependenciesFinderTest.java @@ -23,6 +23,7 @@ import org.springframework.sbm.engine.context.ProjectContext; import org.springframework.sbm.project.resource.TestProjectContext; +import java.nio.file.Path; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; @@ -41,17 +42,15 @@ void shouldFindDependencyRedefinedParentVersion() { parent 1.0.0 pom + + module1 + - com.dependency.group - artifact1 - 3.0.0 - - - com.dependency.group - artifact2 - 3.0.0 + javax.validation + validation-api + 2.0.0.Final @@ -73,25 +72,16 @@ void shouldFindDependencyRedefinedParentVersion() { jar - com.dependency.group - artifact1 - 2.0.0 - - - com.dependency.group - artifact2 - - - com.dependency.group - artifact3 - 1.0.0 + javax.validation + validation-api + 1.1.0.Final """; ProjectContext context = TestProjectContext.buildProjectContext() - .withMavenBuildFileSource("", parentPomXml) + .withMavenRootBuildFileSource(parentPomXml) .withMavenBuildFileSource("module1", module1PomXml) .build(); @@ -100,9 +90,9 @@ void shouldFindDependencyRedefinedParentVersion() { assertThat(context.getApplicationModules().list()).hasSize(2); assertThat(matches).hasSize(1); RedeclaredDependency explicitDependency = matches.iterator().next(); - String explicitVersionDependencyCoordinates = "com.dependency.group:artifact1:2.0.0"; + String explicitVersionDependencyCoordinates = "javax.validation:validation-api:1.1.0.Final"; assertThat(explicitDependency.getRedeclaredDependency().getCoordinates()).isEqualTo(explicitVersionDependencyCoordinates); - assertThat(explicitDependency.getOriginalVersion()).isEqualTo("3.0.0"); + assertThat(explicitDependency.getOriginalVersion()).isEqualTo("2.0.0.Final"); } @Test @@ -120,14 +110,9 @@ void shouldReportSameVersion() { - com.dependency.group - artifact1 - 3.0.0 - - - com.dependency.group - artifact2 - 3.0.0 + javax.validation + validation-api + 2.0.0.Final @@ -149,18 +134,9 @@ void shouldReportSameVersion() { jar - com.dependency.group - artifact1 - 3.0.0 - - - com.dependency.group - artifact2 - - - com.dependency.group - artifact3 - 3.0.0 + javax.validation + validation-api + 2.0.0.Final @@ -176,9 +152,9 @@ void shouldReportSameVersion() { assertThat(context.getApplicationModules().list()).hasSize(2); assertThat(matches).hasSize(1); RedeclaredDependency explicitDependency = matches.iterator().next(); - String explicitVersionDependencyCoordinates = "com.dependency.group:artifact1:3.0.0"; + String explicitVersionDependencyCoordinates = "javax.validation:validation-api:2.0.0.Final"; assertThat(explicitDependency.getRedeclaredDependency().getCoordinates()).isEqualTo(explicitVersionDependencyCoordinates); - assertThat(explicitDependency.getOriginalVersion()).isEqualTo("3.0.0"); + assertThat(explicitDependency.getOriginalVersion()).isEqualTo("2.0.0.Final"); } @Test @@ -196,14 +172,14 @@ void shouldFindDependencyRedefinedBomVersion() { - com.dependency.group - artifact1 + javax.el + javax.el-api 3.0.0 - com.dependency.group - artifact2 - 3.0.0 + javax.validation + validation-api + 2.0.0.Final @@ -221,30 +197,25 @@ void shouldFindDependencyRedefinedBomVersion() { 1.0.0 jar - - - com.example - bom - 1.0.0 - pom - import - - + + + com.example + bom + 1.0.0 + pom + import + + - com.dependency.group - artifact1 - 2.0.0 - - - com.dependency.group - artifact2 + javax.el + javax.el-api + 2.2.5 - com.dependency.group - artifact3 - 1.0.0 + javax.validation + validation-api @@ -255,8 +226,8 @@ void shouldFindDependencyRedefinedBomVersion() { .withMavenBuildFileSource("module1", module1PomXml) .build(); - String explicitVersionDependencyCoordinates = "com.dependency.group:artifact1:2.0.0"; - RedeclaredDependenciesFinder finder = new RedeclaredDependenciesFinder(Set.of("com.dependency.group:artifact1", "com.dependency.group:artifact2")); + String explicitVersionDependencyCoordinates = "javax.el:javax.el-api:2.2.5"; + RedeclaredDependenciesFinder finder = new RedeclaredDependenciesFinder(Set.of("javax.el:javax.el-api", "javax.validation:validation-api")); Set matches = finder.findMatches(context); assertThat(context.getApplicationModules().list()).hasSize(2); assertThat(matches).isNotEmpty(); @@ -278,19 +249,14 @@ void shouldIgnoreWithoutDependencyManagement() { jar - com.dependency.group - artifact1 - 2.0.0 - - - com.dependency.group - artifact2 - 2.0.0 + javax.el + javax.el-api + 3.0.0 - com.dependency.group - artifact3 - 1.0.0 + javax.validation + validation-api + 2.0.0.Final @@ -300,7 +266,7 @@ void shouldIgnoreWithoutDependencyManagement() { .withMavenBuildFileSource("module1", module1PomXml) .build(); - RedeclaredDependenciesFinder finder = new RedeclaredDependenciesFinder(Set.of("com.dependency.group:artifact1", "com.dependency.group:artifact2", "com.dependency.group:artifact3")); + RedeclaredDependenciesFinder finder = new RedeclaredDependenciesFinder(Set.of("javax.el:javax.el-api", "javax.validation:validation-api")); Set matches = finder.findMatches(context); assertThat(context.getApplicationModules().list()).hasSize(1); assertThat(matches).isEmpty(); @@ -318,17 +284,20 @@ void shouldFindAllRedefinedDependencies() { parent 1.0.0 pom + + module1 + - com.dependency.group - artifact1 + javax.el + javax.el-api 3.0.0 - com.dependency.group - artifact2 - 3.0.0 + javax.validation + validation-api + 2.0.1.Final @@ -345,43 +314,45 @@ void shouldFindAllRedefinedDependencies() { com.example parent 1.0.0 + module1 jar - com.dependency.group - artifact3 - 3.0.0 + javax.transaction + javax.transaction-api + 1.3 - com.dependency.group - artifact1 - 2.0.0 + javax.validation + validation-api + 1.1.0.Final - com.dependency.group - artifact2 - 1.5.0 + javax.el + javax.el-api + 2.2.5 - com.dependency.group - artifact3 - 1.0.0 - + javax.transaction + javax.transaction-api + 1.2 + """; ProjectContext context = TestProjectContext.buildProjectContext() - .withMavenBuildFileSource("", parentPomXml) + .withMavenRootBuildFileSource(parentPomXml) .withMavenBuildFileSource("module1", module1PomXml) - .build(); + .serializeProjectContext(Path.of("./target/test")); +// .build(); RedeclaredDependenciesFinder finder = new RedeclaredDependenciesFinder(Set.of()); Set matches = finder.findMatches(context); @@ -389,19 +360,19 @@ void shouldFindAllRedefinedDependencies() { assertThat(matches).hasSize(3); assertThat(matches).contains(new RedeclaredDependency( Dependency.builder() - .groupId("com.dependency.group") - .artifactId("artifact1") - .version("2.0.0").build(), "3.0.0")); + .groupId("javax.validation") + .artifactId("validation-api") + .version("1.1.0.Final").build(), "2.0.1.Final")); assertThat(matches).contains(new RedeclaredDependency( Dependency.builder() - .groupId("com.dependency.group") - .artifactId("artifact2") - .version("1.5.0").build(), "3.0.0")); + .groupId("javax.el") + .artifactId("javax.el-api") + .version("2.2.5").build(), "3.0.0")); assertThat(matches).contains(new RedeclaredDependency( Dependency.builder() - .groupId("com.dependency.group") - .artifactId("artifact3") - .version("1.0.0").build(), "3.0.0")); + .groupId("javax.transaction") + .artifactId("javax.transaction-api") + .version("1.2").build(), "1.3")); } @Test @@ -419,17 +390,20 @@ void shouldFindRedeclaredDependenciesOnlyFromList() { - com.dependency.group - artifact1 - 3.0.0 + javax.validation + validation-api + 2.0.1.Final - com.dependency.group - artifact2 - 3.0.0 + javax.annotation + javax.annotation-api + 1.3.2 + + module1 + """; @@ -448,14 +422,14 @@ void shouldFindRedeclaredDependenciesOnlyFromList() { jar - com.dependency.group - artifact1 - 2.0.0 + javax.validation + validation-api + 1.1.0.Final - com.dependency.group - artifact2 - 2.0.0 + javax.annotation + javax.annotation-api + 1.3 @@ -466,14 +440,14 @@ void shouldFindRedeclaredDependenciesOnlyFromList() { .withMavenBuildFileSource("module1", module1PomXml) .build(); - RedeclaredDependenciesFinder finder = new RedeclaredDependenciesFinder(Set.of("com.dependency.group:artifact1")); + RedeclaredDependenciesFinder finder = new RedeclaredDependenciesFinder(Set.of("javax.validation:validation-api")); Set matches = finder.findMatches(context); assertThat(context.getApplicationModules().list()).hasSize(2); assertThat(matches).hasSize(1); RedeclaredDependency explicitDependency = matches.iterator().next(); - String explicitVersionDependencyCoordinates = "com.dependency.group:artifact1:2.0.0"; + String explicitVersionDependencyCoordinates = "javax.validation:validation-api:1.1.0.Final"; assertThat(explicitDependency.getRedeclaredDependency().getCoordinates()).isEqualTo(explicitVersionDependencyCoordinates); - assertThat(explicitDependency.getOriginalVersion()).isEqualTo("3.0.0"); + assertThat(explicitDependency.getOriginalVersion()).isEqualTo("2.0.1.Final"); } } diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/UpgradeDepenenciesMigrationTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/UpgradeDepenenciesMigrationTest.java index 413f6c21e..d320dd0b9 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/UpgradeDepenenciesMigrationTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/UpgradeDepenenciesMigrationTest.java @@ -58,6 +58,7 @@ void migrateEhCacheToSpringBoot3() { 2.7.5 + com.example dummy-root 0.1.0-SNAPSHOT @@ -70,6 +71,7 @@ void migrateEhCacheToSpringBoot3() { jakarta + """ ); diff --git a/components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jaxrs/actions/ConvertJaxRsAnnotationsTest.java b/components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jaxrs/actions/ConvertJaxRsAnnotationsTest.java index bdc130fa0..db8dd9806 100644 --- a/components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jaxrs/actions/ConvertJaxRsAnnotationsTest.java +++ b/components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jaxrs/actions/ConvertJaxRsAnnotationsTest.java @@ -205,26 +205,28 @@ void replaceMethodAnnotations() throws Exception { " }\n" + "}"; + @Language("java") String expected = - "import org.springframework.web.bind.annotation.RequestMapping;\n" + - "import org.springframework.web.bind.annotation.RequestMethod;\n" + - "import org.springframework.web.bind.annotation.RestController;\n" + - "import javax.ws.rs.PathParam;\n" + - "import javax.ws.rs.core.MediaType;\n" + - "\n" + - "\n" + - "@RestController\n" + - "@RequestMapping(value = \"/hello\")\n" + - "class ControllerClass {\n" + - " @RequestMapping(value = \"/json/{name}\", produces = {\"image/jpeg\", \"image/gif\", \"image/png\", MediaType.APPLICATION_XML}, consumes = \"application/json\"," + - " method = {RequestMethod.POST, RequestMethod.GET, RequestMethod.PUT, RequestMethod.DELETE})\n" + - " public String getHelloWorldJSON(@PathParam(\"name\") String name) {\n" + - " return \"Hello\";\n" + - " }\n" + - " public String notAnEndpoint(@PathParam(\"name\") String name) {\n" + - " return \"Hello\";\n" + - " }\n" + - "}"; + """ + import org.springframework.web.bind.annotation.RequestMapping; + import org.springframework.web.bind.annotation.RequestMethod; + import org.springframework.web.bind.annotation.RestController; + + import javax.ws.rs.PathParam; + import javax.ws.rs.core.MediaType; + + + @RestController + @RequestMapping(value = "/hello") + class ControllerClass { + @RequestMapping(value = "/json/{name}", produces = {"image/jpeg", "image/gif", "image/png", MediaType.APPLICATION_XML}, consumes = "application/json", method = {RequestMethod.POST, RequestMethod.GET, RequestMethod.PUT, RequestMethod.DELETE}) + public String getHelloWorldJSON(@PathParam("name") String name) { + return "Hello"; + } + public String notAnEndpoint(@PathParam("name") String name) { + return "Hello"; + } + }"""; ProjectContext projectContext = TestProjectContext.buildProjectContext() .withJavaSources(sourceCode) diff --git a/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginProperties.java b/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginProperties.java index 53059949b..b1bfd7b14 100644 --- a/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginProperties.java +++ b/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginProperties.java @@ -17,10 +17,12 @@ import java.util.Optional; +import lombok.extern.slf4j.Slf4j; import org.springframework.sbm.build.api.Module; import org.springframework.sbm.engine.context.ProjectContext; import org.springframework.sbm.engine.recipe.AbstractAction; +@Slf4j public class RemoveRedundantMavenCompilerPluginProperties extends AbstractAction { private static final String GROUP_ID = "org.apache.maven.plugins"; @@ -51,8 +53,8 @@ public void apply(ProjectContext context) { if (sourceLookupValue.equals(targetLookupValue)) { buildFile.setProperty(JAVA_VERSION_PROPERTY, sourceLookupValue); - plugin.getConfiguration().setDeclaredStringValue("source", JAVA_VERSION_PLACEHOLDER); - plugin.getConfiguration().setDeclaredStringValue("target", JAVA_VERSION_PLACEHOLDER); + buildFile.findPlugin(GROUP_ID, ARTIFACT_ID).get().getConfiguration().setDeclaredStringValue("source", JAVA_VERSION_PLACEHOLDER); + buildFile.findPlugin(GROUP_ID, ARTIFACT_ID).get().getConfiguration().setDeclaredStringValue("target", JAVA_VERSION_PLACEHOLDER); if(source.get().startsWith("${")){ buildFile.deleteProperty(source.get().replace("${", "").replace("}", "")); } @@ -63,11 +65,12 @@ public void apply(ProjectContext context) { } - }); //Plugin exits + }); //Plugin exists String sourcePropertyValue = buildFile.getProperty(MAVEN_COMPILER_SOURCE_PROPERTY); String targetPropertyValue = buildFile.getProperty(MAVEN_COMPILER_TARGET_PROPERTY); - + log.debug("BuildFile: '%s'\n%s".formatted(buildFile.getSourcePath().toString(), buildFile.print())); + log.debug("%s: %s %s: %s".formatted(MAVEN_COMPILER_SOURCE_PROPERTY, sourcePropertyValue, MAVEN_COMPILER_TARGET_PROPERTY, targetPropertyValue)); if (sourcePropertyValue != null && sourcePropertyValue.equals(targetPropertyValue)){ buildFile.setProperty(JAVA_VERSION_PROPERTY, sourcePropertyValue); buildFile.deleteProperty(MAVEN_COMPILER_SOURCE_PROPERTY); diff --git a/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginPropertiesTest.java b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginPropertiesTest.java index e40d1cad4..4b56b685a 100644 --- a/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginPropertiesTest.java +++ b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginPropertiesTest.java @@ -18,10 +18,9 @@ import java.util.LinkedHashMap; import java.util.Map; -import com.fasterxml.jackson.core.JsonProcessingException; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.springframework.sbm.build.api.BuildFile; import org.springframework.sbm.build.api.Module; import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin; import org.springframework.sbm.build.migration.actions.OpenRewriteMavenBuildFileTestSupport; @@ -49,12 +48,12 @@ void mavenCompilerPluginNotDefined() { org.springframework.boot - spring-boot-maven-plugin + spring-boot-maven-plugin - """; + """; String expected = """ @@ -70,7 +69,7 @@ void mavenCompilerPluginNotDefined() { org.springframework.boot - spring-boot-maven-plugin + spring-boot-maven-plugin @@ -107,7 +106,7 @@ void sourceAndTargetVersionDifferent() { - """; + """; String expected = """ @@ -132,7 +131,7 @@ void sourceAndTargetVersionDifferent() { - """; + """; RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); OpenRewriteMavenBuildFileTestSupport.verifyRefactoring(pomXml, expected, sut); @@ -434,22 +433,24 @@ void multiModuleTest() { } @Test - void multiModuleWithPluginAndPropertiesDefinedInParentModule() throws JsonProcessingException { + void multiModuleWithPluginAndPropertiesDefinedInParentModule() { OpenRewriteMavenPlugin mavenPlugin = OpenRewriteMavenPlugin.builder() .groupId("org.apache.maven.plugins") .artifactId("maven-compiler-plugin") .build(); - Map configMap = new LinkedHashMap<>(); - configMap.put("source", "${maven.compiler.source}"); - configMap.put("target", "${maven.compiler.target}"); - mavenPlugin.setConfiguration(mavenPlugin.new OpenRewriteMavenPluginConfiguration(configMap)); - - String rootPom = PomBuilder.buildPom("com.example:parent:1.0").packaging("pom").plugins(mavenPlugin) - .property("maven.compiler.source", "17").property("maven.compiler.target", "17").withModules("module1") + mavenPlugin.setConfiguration(mavenPlugin.new OpenRewriteMavenPluginConfiguration(Map.of("source", "${maven.compiler.source}", + "target", "${maven.compiler.target}"))); + + String rootPom = PomBuilder.buildPom("com.example:parent:1.0") + .packaging("pom") + .plugins(mavenPlugin) + .property("maven.compiler.source", "17") + .property("maven.compiler.target", "17") + .withModules("module1") .build(); - String module1Pom = PomBuilder.buildPom("com.example:parent:1.0", "module1").packaging("jar").build(); + String module1Pom = PomBuilder.buildPom("com.example:parent:1.0", "module1").build(); ProjectContext projectContext = TestProjectContext.buildProjectContext() .withMavenBuildFileSource("pom.xml", rootPom).withMavenBuildFileSource("module1/pom.xml", module1Pom) @@ -471,50 +472,58 @@ void multiModuleWithPluginAndPropertiesDefinedInParentModule() throws JsonProces } @Test - @Disabled("To be handled ") void multiModuleWithPluginDefinedInParentModuleAndPropertiesInChildModule() { OpenRewriteMavenPlugin mavenPlugin = OpenRewriteMavenPlugin.builder() .groupId("org.apache.maven.plugins") .artifactId("maven-compiler-plugin") .build(); - Map configMap = new LinkedHashMap<>(); - configMap.put("source", "${maven.compiler.source}"); - configMap.put("target", "${maven.compiler.target}"); - mavenPlugin.setConfiguration(mavenPlugin.new OpenRewriteMavenPluginConfiguration(configMap)); - - String rootPom = PomBuilder.buildPom("com.example:parent:1.0").packaging("pom").plugins(mavenPlugin) - .property("maven.compiler.source", "17").property("maven.compiler.target", "17").withModules("module1") + mavenPlugin.setConfiguration(mavenPlugin.new OpenRewriteMavenPluginConfiguration( + Map.of( + "source", "${maven.compiler.source}", + "target", "${maven.compiler.target}" + ) + )); + + String rootPom = PomBuilder.buildPom("com.example:parent:1.0") + .packaging("pom") + .property("maven.compiler.source", "17") + .property("maven.compiler.target", "17") + .withModules("module1") + .plugins(mavenPlugin) .build(); - String module1Pom = PomBuilder.buildPom("com.example:parent:1.0", "module1").packaging("jar") - .property("maven.compiler.source", "17").property("maven.compiler.target", "17").build(); + String module1Pom = PomBuilder.buildPom("com.example:parent:1.0", "module1") + .packaging("jar") + .property("maven.compiler.source", "17") + .property("maven.compiler.target", "17") + .build(); ProjectContext projectContext = TestProjectContext.buildProjectContext() - .withMavenBuildFileSource("pom.xml", rootPom).withMavenBuildFileSource("module1/pom.xml", module1Pom) + .withMavenBuildFileSource("pom.xml", rootPom) + .withMavenBuildFileSource("module1/pom.xml", module1Pom) .build(); + + // Remove redundant plugin properties RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); sut.apply(projectContext); - Module rootModule = projectContext.getApplicationModules().getRootModule(); - assertThat(rootModule.getBuildFile().getProperty("maven.compiler.source")).isNull(); - assertThat(rootModule.getBuildFile().getProperty("maven.compiler.target")).isNull(); - assertThat(rootModule.getBuildFile().getProperty("java.version")).isEqualTo("17"); - assertThat( - rootModule.getBuildFile().getPlugins().get(0).getConfiguration().getDeclaredStringValue("source").get()) - .isEqualTo("${java.version}"); - assertThat( - rootModule.getBuildFile().getPlugins().get(0).getConfiguration().getDeclaredStringValue("target").get()) - .isEqualTo("${java.version}"); + // verify root module + BuildFile rootModule = projectContext.getApplicationModules().getRootModule().getBuildFile(); + assertThat(rootModule.getProperty("maven.compiler.source")).isNull(); + assertThat(rootModule.getProperty("maven.compiler.target")).isNull(); + assertThat(rootModule.getProperty("java.version")).isEqualTo("17"); + assertThat(rootModule.getPlugins().get(0).getConfiguration().getDeclaredStringValue("target").get()).isEqualTo("${java.version}"); + assertThat(rootModule.getPlugins().get(0).getConfiguration().getDeclaredStringValue("source").get()).isEqualTo("${java.version}"); - Module childModule = projectContext.getApplicationModules().getModule("module1"); - assertThat(childModule.getBuildFile().getProperty("java.version")).isEqualTo("17"); - assertThat(childModule.getBuildFile().getProperty("maven.compiler.source")).isNull(); - assertThat(childModule.getBuildFile().getProperty("maven.compiler.target")).isNull(); + + BuildFile childModule = projectContext.getApplicationModules().getModule("module1").getBuildFile(); + assertThat(childModule.getProperty("java.version")).isEqualTo("17"); + assertThat(childModule.getProperty("maven.compiler.source")).isNull(); + assertThat(childModule.getProperty("maven.compiler.target")).isNull(); } @Test - @Disabled("Need to implement multi module pom updates") void multiModuleWithPluginAndPropertiesDefinedInChildModule() { OpenRewriteMavenPlugin mavenPlugin = OpenRewriteMavenPlugin.builder() diff --git a/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/common/recipes/InitializeSpringBootMigrationRecipeIntegrationTest.java b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/common/recipes/InitializeSpringBootMigrationRecipeIntegrationTest.java index 68dea068a..da161568b 100644 --- a/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/common/recipes/InitializeSpringBootMigrationRecipeIntegrationTest.java +++ b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/common/recipes/InitializeSpringBootMigrationRecipeIntegrationTest.java @@ -15,6 +15,8 @@ */ package org.springframework.sbm.boot.common.recipes; +import org.assertj.core.api.Assertions; +import org.openrewrite.java.JavaParser; import org.springframework.sbm.test.RecipeIntegrationTestSupport; import org.junit.jupiter.api.Test; diff --git a/components/sbm-support-boot/testcode/multi-module-simple/expected/module1/pom.xml b/components/sbm-support-boot/testcode/multi-module-simple/expected/module1/pom.xml index dd06f5ee0..0b6f058bc 100644 --- a/components/sbm-support-boot/testcode/multi-module-simple/expected/module1/pom.xml +++ b/components/sbm-support-boot/testcode/multi-module-simple/expected/module1/pom.xml @@ -40,12 +40,10 @@ org.springframework.boot spring-boot-starter - 2.6.3 org.springframework.boot spring-boot-starter-test - 2.6.3 test diff --git a/pom.xml b/pom.xml index a3f684208..dc69fa4b4 100644 --- a/pom.xml +++ b/pom.xml @@ -17,9 +17,9 @@ 3.10.1 17 2.1.4 - 7.29.0 - 4.26.0 - 1.13.0 + 7.35.0 + 4.32.0 + 1.16.0 2.7.5 0.9.5 1.17.6 @@ -29,6 +29,7 @@ UTF-8 UTF-8 src/generated/java + 1.33 @@ -76,6 +77,12 @@ + + org.yaml + snakeyaml + ${snakeyaml.version} + + org.projectlombok lombok