From 7d816f2d2beac97a69aefd8f4f846a33f749f225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Wed, 11 Oct 2023 20:57:38 +0200 Subject: [PATCH 01/10] Remove unused member --- .../springframework/sbm/parsers/ModuleParser.java | 2 -- .../sbm/parsers/maven/MavenModuleParser.java | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java index 61d8c8121..8df55acbf 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java @@ -73,7 +73,6 @@ public UnaryOperator addProvenance( public List processMainSources( Path baseDir, List resources, - Xml.Document moduleBuildFile, JavaParser.Builder javaParserBuilder, RewriteResourceParser rp, List provenanceMarkers, @@ -159,7 +158,6 @@ private static JavaSourceSet sourceSet(String name, List dependencies, Jav */ public List processTestSources( Path baseDir, - Xml.Document moduleBuildFile, JavaParser.Builder javaParserBuilder, RewriteResourceParser rp, List provenanceMarkers, diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java index 82d2cac65..7d007a807 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java @@ -90,8 +90,8 @@ public List parseModuleSourceFiles( Path moduleBuildFilePath = baseDir.resolve(moduleBuildFile.getSourcePath()); alreadyParsed.add(moduleBuildFilePath); alreadyParsed.addAll(skipResourceScanDirs); - List mainSources = parseMainSources(baseDir, currentProject, moduleBuildFile, resources, javaParserBuilder.clone(), rp, provenanceMarkers, alreadyParsed, executionContext); - List testSources = parseTestSources(baseDir, currentProject, moduleBuildFile, javaParserBuilder.clone(), rp, provenanceMarkers, alreadyParsed, executionContext, resources); + List mainSources = parseMainSources(baseDir, currentProject, resources, javaParserBuilder.clone(), rp, provenanceMarkers, alreadyParsed, executionContext); + List testSources = parseTestSources(baseDir, currentProject, javaParserBuilder.clone(), rp, provenanceMarkers, alreadyParsed, executionContext, resources); // Collect the dirs of modules parsed in previous steps // parse other project resources @@ -124,20 +124,20 @@ private static boolean isNotExcluded(Path baseDir, List exclusions, .noneMatch(pm -> pm.matches(baseDir.resolve(s.getSourcePath()).toAbsolutePath().normalize())); } - private List parseTestSources(Path baseDir, MavenProject mavenProject, Xml.Document moduleBuildFile, JavaParser.Builder javaParserBuilder, RewriteResourceParser rp, List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext, List resources) { - return mavenMojoProjectParserPrivateMethods.processTestSources(baseDir, moduleBuildFile, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, mavenProject, resources); + private List parseTestSources(Path baseDir, MavenProject mavenProject, JavaParser.Builder javaParserBuilder, RewriteResourceParser rp, List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext, List resources) { + return mavenMojoProjectParserPrivateMethods.processTestSources(baseDir, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, mavenProject, resources); } /** */ - private List parseMainSources(Path baseDir, MavenProject mavenProject, Xml.Document moduleBuildFile, List resources, JavaParser.Builder javaParserBuilder, RewriteResourceParser rp, List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext) { + private List parseMainSources(Path baseDir, MavenProject mavenProject, List resources, JavaParser.Builder javaParserBuilder, RewriteResourceParser rp, List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext) { // MavenMojoProjectParser#processMainSources(..) takes MavenProject // it reads from it: // - mavenProject.getBuild().getDirectory() // - mavenProject.getBuild().getSourceDirectory() // - mavenProject.getCompileClasspathElements() --> The classpath of the given project/module // - mavenProject.getBasedir().toPath() - return mavenMojoProjectParserPrivateMethods.processMainSources(baseDir, resources, moduleBuildFile, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, mavenProject); + return mavenMojoProjectParserPrivateMethods.processMainSources(baseDir, resources, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, mavenProject); // return invokeProcessMethod(baseDir, moduleBuildFile, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, "processMainSources"); } From aff35d31f191915ba5338cb0090749745db40893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Fri, 13 Oct 2023 16:22:32 +0200 Subject: [PATCH 02/10] Test JavaParser and type resolution for custom types --- .../sbm/parsers/MavenModuleParserTest.java | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java new file mode 100644 index 000000000..6fc9c19b7 --- /dev/null +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java @@ -0,0 +1,178 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import org.apache.maven.model.Plugin; +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.openrewrite.ExecutionContext; +import org.openrewrite.SourceFile; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.internal.JavaTypeCache; +import org.openrewrite.java.marker.JavaSourceSet; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.marker.Marker; +import org.openrewrite.maven.cache.InMemoryMavenPomCache; +import org.openrewrite.maven.cache.LocalMavenArtifactCache; +import org.openrewrite.maven.utilities.MavenArtifactDownloader; +import org.openrewrite.style.NamedStyles; +import org.openrewrite.xml.tree.Xml; +import org.springframework.core.io.Resource; +import org.springframework.sbm.parsers.maven.BuildFileParser; +import org.springframework.sbm.parsers.maven.MavenModuleParser; +import org.springframework.sbm.parsers.maven.MavenProvenanceMarkerFactory; +import org.springframework.sbm.parsers.maven.MavenRuntimeInformation; +import org.springframework.sbm.test.util.DummyResource; + +import java.nio.file.Path; +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Fabian Krüger + */ +public class MavenModuleParserTest { + + private MavenModuleParser sut; + + @BeforeEach + void beforeEach() { + sut = new MavenModuleParser(new ParserProperties(), new ModuleParser()); + } + + /** + * Tests proving the behaviour of JavaParser in combination with JavaTypeCache + */ + @Nested + class JavaCompilerTypeResolutionTest { + + // Simple class A + String aSource = """ + package com.foo; + public class A{} + """; + + // Simple class B extending A + String bSource = """ + package com.bar; + import com.foo.A; + public class B extends A {} + """; + private JavaParser.Builder builder; + + @BeforeEach + void beforeEach() { + builder = JavaParser.fromJavaVersion(); + } + + // Parse A and B with one call to parse() on same instance + // Same parser, same call, same type cache + // -> Should resolve type A + @Test + @DisplayName("Same parser with shared type cache and one call should resolve types") + void sameParserWithSharedTypeCacheAndOneCallShouldResolveTypes() { + JavaParser javaParser = builder.build(); + + List parse = javaParser.parse(aSource, bSource).toList(); + + String fullyQualifiedName = ((JavaType.FullyQualified) ((J.CompilationUnit) parse.get(1)).getClasses().get(0).getExtends().getType()).getFullyQualifiedName(); + assertThat(fullyQualifiedName).isEqualTo("com.foo.A"); + } + + // Parse A and B with separate calls to parse() on separate instances with separate type cache + // Different parser, two calls, different type cache + // -> Should NOT resolve type A + @Test + @DisplayName("Different parsers with separate caches and separate calls should not resolve types") + void differentParsersWithSeparateCachesAndSeparateCallsShouldNotResolveTypes() { + // parser 1 with dedicated type cache + JavaTypeCache typeCache = new JavaTypeCache(); + builder.typeCache(typeCache); + JavaParser javaParser = builder.build(); + SourceFile a = javaParser.parse(aSource).toList().get(0); + + // parser 2 with dedicated type cache + JavaTypeCache typeCache2 = new JavaTypeCache(); + builder.typeCache(typeCache2); + JavaParser javaParser2 = builder.build(); + SourceFile b = javaParser2.parse(bSource).toList().get(0); + + // Type A used in B not resolved + String fullyQualifiedName2 = ((JavaType.FullyQualified) ((J.CompilationUnit) b).getClasses().get(0).getExtends().getType()).getFullyQualifiedName(); + String unknown = JavaType.Unknown.getInstance().getFullyQualifiedName(); + assertThat(fullyQualifiedName2).isEqualTo(unknown); + } + + // Parse A and B with separate calls to parse() on separate instances with SHARED type cache + // Different parser, two calls, same type cache + // -> Should NOT resolve type A + // -> Sharing the type cache is not enough! + @Test + @DisplayName("Different parsers with shared cache and separate calls should NOT resolve types") + void differentParsersWithSharedCacheAndSeparateCallsShouldNotResolveTypes() { + // Shared type cache + JavaTypeCache typeCache = new JavaTypeCache(); + builder.typeCache(typeCache); + + // parser 1 + JavaParser javaParser = builder.build(); + // parser 2 + JavaParser javaParser2 = builder.build(); + + SourceFile a = javaParser.parse(aSource).toList().get(0); + SourceFile b = javaParser2.parse(bSource).toList().get(0); + + // Type A used in B IS resolved + String fullyQualifiedName = ((JavaType.FullyQualified) ((J.CompilationUnit) b).getClasses().get(0).getExtends().getType()).getFullyQualifiedName(); + String unknown = JavaType.Unknown.getInstance().getFullyQualifiedName(); + assertThat(fullyQualifiedName).isEqualTo(unknown); + } + + // Parse A and B with separate calls to parse() on SAME instances with SHARED type cache + // Same parser, two calls, same type cache + // -> Should resolve type A + // -> Same parser, separate calls, same type cache + // --> WORKS! That's what we need. + @Test + @DisplayName("Same parser with shared cache in separate calls should resolve types") + void sameParserWithSharedCacheInSeparateCallsShouldResolveTypes() { + // One shared type cache + JavaTypeCache typeCache = new JavaTypeCache(); + builder.typeCache(typeCache); + JavaParser javaParser = builder.build(); + + // Same parser two calls + SourceFile a = javaParser.parse(aSource).toList().get(0); + SourceFile b = javaParser.parse(bSource).toList().get(0); + + J.CompilationUnit compilationUnitB = (J.CompilationUnit) b; + String fullyQualifiedName2 = ((JavaType.FullyQualified) compilationUnitB.getClasses().get(0).getExtends().getType()).getFullyQualifiedName(); + // A can be resolved + assertThat(fullyQualifiedName2).isEqualTo("com.foo.A"); + + List bTypesInUseFqNames = compilationUnitB.getTypesInUse().getTypesInUse().stream().map(fq -> ((JavaType.FullyQualified) fq).getFullyQualifiedName()).toList(); + // A is in typesInUse of B + assertThat(bTypesInUseFqNames).contains("com.foo.A"); + //No markers were set + assertThat(compilationUnitB.getMarkers().getMarkers()).isEmpty(); + } + } +} From 7910103897410d4f58acfb05363c40e5c7f8debb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Mon, 16 Oct 2023 16:03:33 +0200 Subject: [PATCH 03/10] WIP Working on a module parser JavaParserBuilder keeps state (classpath) and is passed through --- .../sbm/parsers/ClasspathExtractor.java | 53 ++++ .../sbm/parsers/MavenProject.java | 34 +-- .../sbm/parsers/ModuleParser.java | 6 +- .../sbm/parsers/ModuleParsingResult.java | 27 ++ .../parsers/RewriteParserConfiguration.java | 9 +- .../sbm/parsers/maven/MavenModuleParser.java | 63 ++++- .../parsers/maven/MavenProjectAnalyzer.java | 9 +- .../maven/MavenProvenanceMarkerFactory.java | 69 ++++- .../sbm/parsers/MavenModuleParserTest.java | 241 ++++++++++++++++++ .../sbm/parsers/RewriteProjectParserTest.java | 5 +- .../maven/MavenProjectAnalyzerTest.java | 2 +- .../maven/RewriteMavenProjectParserTest.java | 6 +- 12 files changed, 468 insertions(+), 56 deletions(-) create mode 100644 sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathExtractor.java create mode 100644 sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParsingResult.java diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathExtractor.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathExtractor.java new file mode 100644 index 000000000..27e73def0 --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathExtractor.java @@ -0,0 +1,53 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import lombok.RequiredArgsConstructor; +import org.openrewrite.maven.tree.MavenResolutionResult; +import org.openrewrite.maven.tree.ResolvedDependency; +import org.openrewrite.maven.tree.Scope; +import org.openrewrite.maven.utilities.MavenArtifactDownloader; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + + +/** + * @author Fabian Krüger + */ +@RequiredArgsConstructor +public class ClasspathExtractor { + private final MavenArtifactDownloader rewriteMavenArtifactDownloader; + + public List extractClasspath(MavenResolutionResult pom, Scope scope) { + List resolvedDependencies = pom.getDependencies().get(scope); + if (resolvedDependencies != null) { + return resolvedDependencies + // FIXME: 945 - deal with dependencies to projects in reactor + // + .stream() + .filter(rd -> rd.getRepository() != null) + .map(rd -> rewriteMavenArtifactDownloader.downloadArtifact(rd)) + .filter(Objects::nonNull) + .distinct() + .toList(); + } else { + return new ArrayList<>(); + } + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java index 725560384..dea784634 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java @@ -20,12 +20,11 @@ import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; import org.jetbrains.annotations.NotNull; -import org.openrewrite.SourceFile; import org.openrewrite.maven.tree.*; -import org.openrewrite.maven.utilities.MavenArtifactDownloader; import org.openrewrite.xml.tree.Xml; import org.springframework.core.io.Resource; import org.springframework.sbm.parsers.maven.MavenRuntimeInformation; +import org.springframework.sbm.project.resource.ProjectResourceSet; import org.springframework.sbm.utils.ResourceUtil; import java.io.File; @@ -43,19 +42,17 @@ public class MavenProject { private final Path projectRoot; private final Resource pomFile; - // FIXME: 945 temporary method, model should nopt come from Maven private final Model pomModel; + private final List resources; private List collectedProjects = new ArrayList<>(); private Xml.Document sourceFile; - private final MavenArtifactDownloader rewriteMavenArtifactDownloader; - private final List resources; private ProjectId projectId; + private Map> classpath; - public MavenProject(Path projectRoot, Resource pomFile, Model pomModel, MavenArtifactDownloader rewriteMavenArtifactDownloader, List resources) { + public MavenProject(Path projectRoot, Resource pomFile, Model pomModel, List resources) { this.projectRoot = projectRoot; this.pomFile = pomFile; this.pomModel = pomModel; - this.rewriteMavenArtifactDownloader = rewriteMavenArtifactDownloader; this.resources = resources; projectId = new ProjectId(getGroupId(), getArtifactId()); } @@ -145,32 +142,18 @@ public String getSourceDirectory() { return s == null ? ResourceUtil.getPath(pomFile).getParent().resolve("src/main/java").toAbsolutePath().normalize().toString() : s; } - public List getCompileClasspathElements() { + public Set getCompileClasspathElements() { Scope scope = Scope.Compile; return getClasspathElements(scope); } - public List getTestClasspathElements() { + public Set getTestClasspathElements() { return getClasspathElements(Scope.Test); } @NotNull - private List getClasspathElements(Scope scope) { - MavenResolutionResult pom = getSourceFile().getMarkers().findFirst(MavenResolutionResult.class).get(); - List resolvedDependencies = pom.getDependencies().get(scope); - if(resolvedDependencies != null) { - return resolvedDependencies - // FIXME: 945 - deal with dependencies to projects in reactor - // - .stream() - .filter(rd -> rd.getRepository() != null) - .map(rd -> rewriteMavenArtifactDownloader.downloadArtifact(rd)) - .filter(Objects::nonNull) - .distinct() - .toList(); - } else { - return new ArrayList<>(); - } + private Set getClasspathElements(Scope scope) { + return this.classpath.get(scope); } public String getTestSourceDirectory() { @@ -199,7 +182,6 @@ private static Predicate whenIn(Path sourceDirectory) { return r -> ResourceUtil.getPath(r).toString().startsWith(sourceDirectory.toString()); } - public List getJavaSourcesInTarget() { return listJavaSources(getResources(), getBasedir().resolve(getBuildDirectory())); } diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java index 8df55acbf..293c22467 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java @@ -104,7 +104,7 @@ public List processMainSources( // Or, the classpath must be created from the sources of the project. - List dependencies = currentProject.getCompileClasspathElements(); + Set dependencies = currentProject.getCompileClasspathElements(); javaParserBuilder.classpath(dependencies); @@ -148,7 +148,7 @@ public List processMainSources( } @NotNull - private static JavaSourceSet sourceSet(String name, List dependencies, JavaTypeCache typeCache) { + private static JavaSourceSet sourceSet(String name, Set dependencies, JavaTypeCache typeCache) { return JavaSourceSet.build(name, dependencies, typeCache, false); } @@ -168,7 +168,7 @@ public List processTestSources( ) { log.info("Processing test sources in module '%s'".formatted(currentProject.getProjectId())); - List testDependencies = currentProject.getTestClasspathElements(); + Set testDependencies = currentProject.getTestClasspathElements(); javaParserBuilder.classpath(testDependencies); JavaTypeCache typeCache = new JavaTypeCache(); diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParsingResult.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParsingResult.java new file mode 100644 index 000000000..2de23c423 --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParsingResult.java @@ -0,0 +1,27 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import org.openrewrite.SourceFile; + +import java.util.List; + +/** + * @author Fabian Krüger + */ +public record ModuleParsingResult(List sourceFiles) { + +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java index bc2c8e1e0..059716001 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java @@ -102,6 +102,11 @@ Consumer artifactDownloaderErrorConsumer() { return (t) -> {throw new RuntimeException(t);}; } + @Bean + ClasspathExtractor classpathExtractor(MavenArtifactDownloader rewriteMavenArtifactDownloader) { + return new ClasspathExtractor(rewriteMavenArtifactDownloader); + } + @Bean RewriteMavenArtifactDownloader artifactDownloader(MavenArtifactCache mavenArtifactCache, ProjectMetadata projectMetadata, Consumer artifactDownloaderErrorConsumer) { return new RewriteMavenArtifactDownloader(mavenArtifactCache, projectMetadata.getMavenSettings(), artifactDownloaderErrorConsumer); @@ -147,8 +152,8 @@ ParsingEventListener parsingEventListener(ApplicationEventPublisher eventPublish // } @Bean - MavenProjectAnalyzer mavenProjectAnalyzer(MavenArtifactDownloader artifactDownloader) { - return new MavenProjectAnalyzer(artifactDownloader); + MavenProjectAnalyzer mavenProjectAnalyzer(MavenArtifactDownloader artifactDownloader, ClasspathExtractor classpathExtractor) { + return new MavenProjectAnalyzer(artifactDownloader, classpathExtractor); } @Bean diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java index 7d007a807..6a29c85ef 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java @@ -17,6 +17,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ArrayUtils; import org.openrewrite.ExecutionContext; import org.openrewrite.SourceFile; import org.openrewrite.java.JavaParser; @@ -24,17 +25,13 @@ import org.openrewrite.style.NamedStyles; import org.openrewrite.xml.tree.Xml; import org.springframework.core.io.Resource; -import org.springframework.sbm.parsers.MavenProject; -import org.springframework.sbm.parsers.ModuleParser; -import org.springframework.sbm.parsers.ParserProperties; -import org.springframework.sbm.parsers.RewriteResourceParser; +import org.springframework.sbm.parsers.*; +import org.springframework.sbm.utils.ResourceUtil; +import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.PathMatcher; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -148,4 +145,54 @@ private Set pathsToOtherMavenProjects(MavenProject mavenProject, Path modu .collect(Collectors.toSet()); } + //------------- + + public ModuleParsingResult parseModule(Path baseDir, String modulePathSegment, Collection classpath, Collection classBytesClasspath, List resources) { + resources = filterResources(baseDir, modulePathSegment, resources); + List parsedSources = new ArrayList<>(); + List mainSources = parseMainSources(baseDir, classpath, classBytesClasspath, resources); + parsedSources.addAll(mainSources); + List testSources = parseTestSources(resources, classpath, classBytesClasspath, resources); + parsedSources.addAll(testSources); + List otherResources = parseOtherResources(resources); + parsedSources.addAll(otherResources); + ModuleParsingResult moduleParsingResult = new ModuleParsingResult(parsedSources); + return moduleParsingResult; + } + + private List parseOtherResources(List resources) { + return new ArrayList<>(); + } + + private List parseTestSources(List resources, Collection classpath, Collection classBytesClasspath, List resources1) { + return new ArrayList<>(); + } + + private List parseMainSources(Path baseDir, Collection classpath, Collection classBytesClasspath, List resources) { + List array = classBytesClasspath + .stream() + .map(b -> { + return (byte[]) b; + }) + .toList(); + + List classBytesClasspathList = new ArrayList<>(); + classBytesClasspathList.addAll(classBytesClasspath); + + byte[][] classBytesClasspathArray = new byte[classBytesClasspath.size()][]; + for(int i=0; i(); + } + + private List filterResources(Path baseDir, String modulePathSegment, List resources) { + String pattern = "glob:" + baseDir.resolve(modulePathSegment); + PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(pattern); + return resources.stream() + .filter(r -> pathMatcher.matches(ResourceUtil.getPath(r))) + .toList(); + } } diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java index 30de7eb4e..92b917b14 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java @@ -20,6 +20,7 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.openrewrite.maven.utilities.MavenArtifactDownloader; import org.springframework.core.io.Resource; +import org.springframework.sbm.parsers.ClasspathExtractor; import org.springframework.sbm.parsers.MavenProject; import org.springframework.sbm.parsers.ParserContext; import org.springframework.sbm.utils.ResourceUtil; @@ -42,9 +43,11 @@ public class MavenProjectAnalyzer { private static final String POM_XML = "pom.xml"; private static final MavenXpp3Reader XPP_3_READER = new MavenXpp3Reader(); private final MavenArtifactDownloader rewriteMavenArtifactDownloader; + private final ClasspathExtractor classpathExtractor; - public MavenProjectAnalyzer(MavenArtifactDownloader rewriteMavenArtifactDownloader) { + public MavenProjectAnalyzer(MavenArtifactDownloader rewriteMavenArtifactDownloader, ClasspathExtractor classpathExtractor) { this.rewriteMavenArtifactDownloader = rewriteMavenArtifactDownloader; + this.classpathExtractor = classpathExtractor; } public List getSortedProjects(Path baseDir, List resources) { @@ -59,7 +62,7 @@ public List getSortedProjects(Path baseDir, List resourc Model rootPomModel = new Model(rootPom); if (isSingleModuleProject(rootPomModel)) { - return List.of(new MavenProject(baseDir, rootPom, rootPomModel, rewriteMavenArtifactDownloader, resources)); + return List.of(new MavenProject(baseDir, rootPom, rootPomModel, resources)); } List reactorModels = new ArrayList<>(); recursivelyFindReactorModules(baseDir, null, reactorModels, allPomFiles, rootPomModel); @@ -75,7 +78,7 @@ private List map(Path baseDir, List resources, List { String projectDir = baseDir.resolve(m.getProjectDirectory().toString()).normalize().toString(); List filteredResources = resources.stream().filter(r -> ResourceUtil.getPath(r).toString().startsWith(projectDir)).toList(); - mavenProjects.add(new MavenProject(baseDir, m.getResource(), m, rewriteMavenArtifactDownloader, filteredResources)); + mavenProjects.add(new MavenProject(baseDir, m.getResource(), m, filteredResources)); }); // set all non parent poms as collected projects for root parent pom List collected = new ArrayList<>(mavenProjects); diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProvenanceMarkerFactory.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProvenanceMarkerFactory.java index bc23eb3b1..37c7e0d01 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProvenanceMarkerFactory.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProvenanceMarkerFactory.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.maven.model.Plugin; import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.jetbrains.annotations.NotNull; import org.openrewrite.Tree; import org.openrewrite.internal.StringUtils; import org.openrewrite.internal.lang.Nullable; @@ -31,6 +32,7 @@ import java.nio.file.Path; import java.util.List; import java.util.Objects; +import java.util.Properties; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -43,16 +45,62 @@ public class MavenProvenanceMarkerFactory { public List generateProvenance(Path baseDir, MavenProject mavenProject) { + // extract information from mavenProject MavenRuntimeInformation runtime = mavenProject.getMavenRuntimeInformation(); + Plugin compilerPlugin = mavenProject.getPlugin("org.apache.maven.plugins:maven-compiler-plugin"); + Properties properties = mavenProject.getProperties(); + String projectName = mavenProject.getName(); + String groupId = mavenProject.getGroupId(); + String artifactId = mavenProject.getArtifactId(); + String version = mavenProject.getVersion(); + + return generateProvenanceMarkers(baseDir, runtime, compilerPlugin, properties, projectName, groupId, artifactId, version); + } + + @NotNull + public List generateProvenanceMarkers(Path baseDir, MavenRuntimeInformation runtime, Plugin compilerPlugin, Properties properties, String projectName, String groupId, String artifactId, String version) { + BuildEnvironment buildEnvironment = BuildEnvironment.build(System::getenv); + GitProvenance gitProvenance = this.gitProvenance(baseDir, buildEnvironment); + OperatingSystemProvenance operatingSystemProvenance = OperatingSystemProvenance.current(); BuildTool buildTool = new BuildTool(Tree.randomId(), BuildTool.Type.Maven, runtime.getMavenVersion()); + JavaVersion javaVersion = getJavaVersion(compilerPlugin, properties); + JavaProject javaProject = getJavaProject(projectName, groupId, artifactId, version); + + List provenanceMarkers = Stream.of( + buildEnvironment, + gitProvenance, + operatingSystemProvenance, + buildTool, + javaVersion, + javaProject + ) + .filter(Objects::nonNull) + .toList(); + return provenanceMarkers; + } + + @NotNull + private static JavaProject getJavaProject(String projectName, String groupId, String artifactId, String version) { + return new JavaProject( + Tree.randomId(), + projectName, + new JavaProject.Publication( + groupId, + artifactId, + version + ) + ); + } + + @NotNull + private static JavaVersion getJavaVersion(Plugin compilerPlugin, Properties properties) { String javaRuntimeVersion = System.getProperty("java.specification.version"); String javaVendor = System.getProperty("java.vm.vendor"); String sourceCompatibility = null; String targetCompatibility = null; - Plugin compilerPlugin = mavenProject.getPlugin("org.apache.maven.plugins:maven-compiler-plugin"); if (compilerPlugin != null && compilerPlugin.getConfiguration() instanceof Xpp3Dom) { - Xpp3Dom dom = (Xpp3Dom)compilerPlugin.getConfiguration(); + Xpp3Dom dom = (Xpp3Dom) compilerPlugin.getConfiguration(); Xpp3Dom release = dom.getChild("release"); if (release != null && StringUtils.isNotEmpty(release.getValue()) && !release.getValue().contains("${")) { sourceCompatibility = release.getValue(); @@ -71,17 +119,18 @@ public List generateProvenance(Path baseDir, MavenProject mavenProject) } if (sourceCompatibility == null || targetCompatibility == null) { - String propertiesReleaseCompatibility = (String)mavenProject.getProperties().get("maven.compiler.release"); + + String propertiesReleaseCompatibility = (String) properties.get("maven.compiler.release"); if (propertiesReleaseCompatibility != null) { sourceCompatibility = propertiesReleaseCompatibility; targetCompatibility = propertiesReleaseCompatibility; } else { - String propertiesSourceCompatibility = (String)mavenProject.getProperties().get("maven.compiler.source"); + String propertiesSourceCompatibility = (String) properties.get("maven.compiler.source"); if (sourceCompatibility == null && propertiesSourceCompatibility != null) { sourceCompatibility = propertiesSourceCompatibility; } - String propertiesTargetCompatibility = (String)mavenProject.getProperties().get("maven.compiler.target"); + String propertiesTargetCompatibility = (String) properties.get("maven.compiler.target"); if (targetCompatibility == null && propertiesTargetCompatibility != null) { targetCompatibility = propertiesTargetCompatibility; } @@ -96,8 +145,14 @@ public List generateProvenance(Path baseDir, MavenProject mavenProject) targetCompatibility = sourceCompatibility; } - BuildEnvironment buildEnvironment = BuildEnvironment.build(System::getenv); - return (List) Stream.of(buildEnvironment, this.gitProvenance(baseDir, buildEnvironment), OperatingSystemProvenance.current(), buildTool, new JavaVersion(Tree.randomId(), javaRuntimeVersion, javaVendor, sourceCompatibility, targetCompatibility), new JavaProject(Tree.randomId(), mavenProject.getName(), new JavaProject.Publication(mavenProject.getGroupId(), mavenProject.getArtifactId(), mavenProject.getVersion()))).filter(Objects::nonNull).collect(Collectors.toList()); + JavaVersion javaVersion = new JavaVersion( + Tree.randomId(), + javaRuntimeVersion, + javaVendor, + sourceCompatibility, + targetCompatibility + ); + return javaVersion; } private @Nullable GitProvenance gitProvenance(Path baseDir, @Nullable BuildEnvironment buildEnvironment) { diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java index 6fc9c19b7..e82f01661 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.openrewrite.ExecutionContext; +import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.SourceFile; import org.openrewrite.java.JavaParser; import org.openrewrite.java.internal.JavaTypeCache; @@ -31,6 +32,8 @@ import org.openrewrite.marker.Marker; import org.openrewrite.maven.cache.InMemoryMavenPomCache; import org.openrewrite.maven.cache.LocalMavenArtifactCache; +import org.openrewrite.maven.tree.MavenResolutionResult; +import org.openrewrite.maven.tree.Scope; import org.openrewrite.maven.utilities.MavenArtifactDownloader; import org.openrewrite.style.NamedStyles; import org.openrewrite.xml.tree.Xml; @@ -175,4 +178,242 @@ void sameParserWithSharedCacheInSeparateCallsShouldResolveTypes() { assertThat(compilationUnitB.getMarkers().getMarkers()).isEmpty(); } } + + + @Test + @DisplayName("parse simple project") + void parseSimpleProject() { + @Language("xml") + String pomXml = """ + + + 4.0.0 + + com.example + example-1-parent + 0.1.0-SNAPSHOT + + app + + 17 + 17 + + + + org.junit.jupiter + junit-jupiter-api + 5.9.3test + test + + + javax.validation + validation-api + 2.0.1.Final + + + + """; + @Language("java") + String mainClass = """ + package com.example.app; + import javax.validation.constraints.Min; + + public class MainClass { + @Min("0") + private int number; + } + """; + @Language("java") + String testClass = """ + package com.example.app.test; + import org.junit.jupiter.api.Test; + import com.example.app.MainClass; + + public class SomeTest { + @Test + void someTest() { + MainClass m = new MainClass(); + } + } + """; + + Path baseDir = Path.of("./target").toAbsolutePath().normalize(); + + Path pomXmlPath = baseDir.resolve("pom.xml").normalize(); + List resources = List.of( + new DummyResource(pomXmlPath, pomXml), + new DummyResource(baseDir.resolve("src/main/java/com/example/app/MainClass.java"), mainClass), + new DummyResource(baseDir.resolve("src/test/java/com/example/app/test/SomeTest.java"), testClass) + ); + + MavenRuntimeInformation mavenRuntimeInfo = new MavenRuntimeInformation(); + Plugin compilerPlugin = null; + Properties properties = new Properties(); + String projectName = "app"; + String groupId = "com.example"; + String artifactId = "app"; + String version = "1.0.0-SNAPSHOT"; + + List provenanceMarkers = new MavenProvenanceMarkerFactory().generateProvenanceMarkers( + baseDir, + mavenRuntimeInfo, + compilerPlugin, + properties, + projectName, + groupId, + artifactId, + version + ); + Map> provenanceMarkersMap = Map.of(pomXmlPath, provenanceMarkers); + BuildFileParser buildFileParser = new BuildFileParser(); + List parsedBuildFiles = buildFileParser.parseBuildFiles(baseDir, List.of(resources.get(0)), List.of(), new RewriteExecutionContext(), false, provenanceMarkersMap); + Xml.Document document = parsedBuildFiles.get(0); + + + Collection classpath = new ArrayList<>(); + Collection classBytesClasspath = new ArrayList<>(); + + ModuleParsingResult moduleParsingResult = sut.parseModule(baseDir, "", classpath, classBytesClasspath, resources); + + assertThat(moduleParsingResult.sourceFiles()).hasSize(2); + assertThat(moduleParsingResult.sourceFiles().get(0).printAll()).isEqualTo(mainClass); + } + + @Test + @DisplayName("parse reactor project") + void parseReactorProject() { + @Language("xml") + String parentPom = """ + + + 4.0.0 + com.example + example-1-parent + 0.1.0-SNAPSHOT + pom + + 17 + 17 + + + module-a + module-b + module-c + + + """; + + @Language("xml") + String moduleAPom = """ + + + 4.0.0 + + com.example + example-1-parent + 0.1.0-SNAPSHOT + + module-a + + 17 + 17 + + + + com.example + module-b + ${project.version} + + + javax.validation + validation-api + 2.0.1.Final + + + + """; + + @Language("xml") + String moduleBPom = """ + + + 4.0.0 + + com.example + example-1-parent + 0.1.0-SNAPSHOT + + module-b + + 17 + 17 + + + + com.example + module-c + ${project.version} + + + + """; + + @Language("xml") + String moduleCPom = """ + + + 4.0.0 + + com.example + example-1-parent + 0.1.0-SNAPSHOT + + module-c + + 17 + 17 + + + """; + + Path baseDir = Path.of("./target").toAbsolutePath().normalize(); + List resources = List.of( + new DummyResource(baseDir.resolve("pom.xml"), parentPom), + new DummyResource(baseDir.resolve("module-a/pom.xml"), moduleAPom), + new DummyResource(baseDir.resolve("module-b/pom.xml"), moduleBPom), + new DummyResource(baseDir.resolve("module-c/pom.xml"), moduleCPom) + ); + ExecutionContext executionContext = new InMemoryExecutionContext(); +/* + // used to calculate paths to other modules. + // TODO: Remove and filter all provided resources by module path segment + MavenProject mavenProject = null; + // used to retrieve sourcePath which can be calculated having the module path segment and baseDir + Xml.Document moduleBuildFile = null; + // required, can be taken from a resource in same source dir?! + List provenanceMarkers = null; + // Make this a Spring bean + List styles = null; + // provided as bean + ExecutionContext executionContext = null; + // required + Path baseDir = null; + sut.parseModuleSourceFiles(resources, mavenProject, moduleBuildFile, provenanceMarkers, styles, executionContext, baseDir); +*/ + BuildFileParser buildFileParser = new BuildFileParser(); + List parsedBuildFiles = buildFileParser.parseBuildFiles(baseDir, resources, List.of(), executionContext, false, Map.of()); + + Path locaMavenRepo = Path.of(System.getProperty("user.home")).resolve(".m2/repository"); + MavenArtifactDownloader artifactDownloader = new RewriteMavenArtifactDownloader(new LocalMavenArtifactCache(locaMavenRepo), null, t -> {throw new RuntimeException(t);}); + ClasspathExtractor classpathExtractor = new ClasspathExtractor(artifactDownloader); + List classpath = classpathExtractor.extractClasspath(parsedBuildFiles.get(0).getMarkers().findFirst(MavenResolutionResult.class).get(), Scope.Compile); + Collection classBytesClasspath = List.of(); + String modulePathSegment = "module-c"; + ModuleParsingResult result = sut.parseModule(baseDir, modulePathSegment, classpath, classBytesClasspath, resources); + assertThat(result.sourceFiles()).hasSize(0); + } + } diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java index fe9ae4395..3aec96fdc 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java @@ -23,6 +23,7 @@ import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.Parser; import org.openrewrite.SourceFile; +import org.openrewrite.maven.cache.LocalMavenArtifactCache; import org.openrewrite.tree.ParsingEventListener; import org.openrewrite.tree.ParsingExecutionContextView; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; @@ -92,6 +93,8 @@ void parseSimpleMavenProject(@TempDir Path tempDir) { ModuleParser mavenMojoParserPrivateMethods = new ModuleParser(); ExecutionContext executionContext = new InMemoryExecutionContext(t -> {throw new RuntimeException(t);}); MavenModuleParser mavenModuleParser = new MavenModuleParser(parserProperties, mavenMojoParserPrivateMethods); + Path localMavenRepo = Path.of(System.getProperty("user.home")).resolve(".m2/repository"); + ClasspathExtractor classpathExtractor = new ClasspathExtractor(new RewriteMavenArtifactDownloader(new LocalMavenArtifactCache(localMavenRepo), null, t -> {throw new RuntimeException(t);})); RewriteProjectParser projectParser = new RewriteProjectParser( new ProvenanceMarkerFactory(new MavenProvenanceMarkerFactory()), new BuildFileParser(), @@ -104,7 +107,7 @@ void parseSimpleMavenProject(@TempDir Path tempDir) { mock(ConfigurableListableBeanFactory.class), new ProjectScanner(new DefaultResourceLoader(), parserProperties), executionContext, - new MavenProjectAnalyzer(mock(RewriteMavenArtifactDownloader.class)) + new MavenProjectAnalyzer(mock(RewriteMavenArtifactDownloader.class), classpathExtractor) ); List parsedFiles = new ArrayList<>(); diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java index b8cac286f..77272a3c0 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java @@ -50,7 +50,7 @@ class MavenProjectAnalyzerTest { @BeforeEach void beforeEach() { MavenArtifactDownloader rewriteMavenArtifactDownloader = Mockito.mock(RewriteMavenArtifactDownloader.class); - sut = new MavenProjectAnalyzer(rewriteMavenArtifactDownloader); + sut = new MavenProjectAnalyzer(rewriteMavenArtifactDownloader, classpathExtractor); } @Nested diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java index 325b683f9..96abc034a 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java @@ -16,7 +16,6 @@ package org.springframework.sbm.parsers.maven; import org.intellij.lang.annotations.Language; -import org.jetbrains.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; @@ -40,8 +39,6 @@ import org.openrewrite.maven.MavenExecutionContextView; import org.openrewrite.maven.MavenSettings; import org.openrewrite.maven.cache.*; -import org.openrewrite.maven.cache.LocalMavenArtifactCache; -import org.openrewrite.maven.cache.MavenArtifactCache; import org.openrewrite.maven.tree.MavenResolutionResult; import org.openrewrite.shaded.jgit.api.Git; import org.openrewrite.shaded.jgit.api.errors.GitAPIException; @@ -64,7 +61,6 @@ import java.io.File; import java.nio.charset.Charset; import java.nio.file.Path; -import java.nio.file.Paths; import java.time.Duration; import java.time.Instant; import java.time.ZoneId; @@ -285,7 +281,7 @@ void parseMultiModule1_WithCustomParser() { beanFactory, new ProjectScanner(new DefaultResourceLoader(), parserProperties), new RewriteExecutionContext(), - new MavenProjectAnalyzer(mock(RewriteMavenArtifactDownloader.class)) + new MavenProjectAnalyzer(mock(RewriteMavenArtifactDownloader.class), classpathExtractor) ); Set ignoredPatters = Set.of(); From 0010a0cf5c498069431653911be3f9a6d06ef60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Mon, 16 Oct 2023 23:23:03 +0200 Subject: [PATCH 04/10] Removed unused constructor arg --- .../sbm/parsers/RewriteParserConfiguration.java | 4 ++-- .../sbm/parsers/maven/MavenProjectAnalyzer.java | 4 +--- .../springframework/sbm/parsers/RewriteProjectParserTest.java | 2 +- .../sbm/parsers/maven/MavenProjectAnalyzerTest.java | 4 +++- .../sbm/parsers/maven/RewriteMavenProjectParserTest.java | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java index 059716001..57267a47f 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java @@ -152,8 +152,8 @@ ParsingEventListener parsingEventListener(ApplicationEventPublisher eventPublish // } @Bean - MavenProjectAnalyzer mavenProjectAnalyzer(MavenArtifactDownloader artifactDownloader, ClasspathExtractor classpathExtractor) { - return new MavenProjectAnalyzer(artifactDownloader, classpathExtractor); + MavenProjectAnalyzer mavenProjectAnalyzer(ClasspathExtractor classpathExtractor) { + return new MavenProjectAnalyzer(classpathExtractor); } @Bean diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java index 92b917b14..fc20685b6 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java @@ -42,11 +42,9 @@ public class MavenProjectAnalyzer { private static final String POM_XML = "pom.xml"; private static final MavenXpp3Reader XPP_3_READER = new MavenXpp3Reader(); - private final MavenArtifactDownloader rewriteMavenArtifactDownloader; private final ClasspathExtractor classpathExtractor; - public MavenProjectAnalyzer(MavenArtifactDownloader rewriteMavenArtifactDownloader, ClasspathExtractor classpathExtractor) { - this.rewriteMavenArtifactDownloader = rewriteMavenArtifactDownloader; + public MavenProjectAnalyzer(ClasspathExtractor classpathExtractor) { this.classpathExtractor = classpathExtractor; } diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java index 3aec96fdc..4cf0e2b2a 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java @@ -107,7 +107,7 @@ void parseSimpleMavenProject(@TempDir Path tempDir) { mock(ConfigurableListableBeanFactory.class), new ProjectScanner(new DefaultResourceLoader(), parserProperties), executionContext, - new MavenProjectAnalyzer(mock(RewriteMavenArtifactDownloader.class), classpathExtractor) + new MavenProjectAnalyzer(new ClasspathExtractor(mock(RewriteMavenArtifactDownloader.class))) ); List parsedFiles = new ArrayList<>(); diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java index 77272a3c0..9ea59de89 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java @@ -26,6 +26,7 @@ import org.mockito.Mockito; import org.openrewrite.maven.utilities.MavenArtifactDownloader; import org.springframework.core.io.Resource; +import org.springframework.sbm.parsers.ClasspathExtractor; import org.springframework.sbm.parsers.MavenProject; import org.springframework.sbm.parsers.RewriteMavenArtifactDownloader; import org.springframework.sbm.test.util.DummyResource; @@ -50,7 +51,8 @@ class MavenProjectAnalyzerTest { @BeforeEach void beforeEach() { MavenArtifactDownloader rewriteMavenArtifactDownloader = Mockito.mock(RewriteMavenArtifactDownloader.class); - sut = new MavenProjectAnalyzer(rewriteMavenArtifactDownloader, classpathExtractor); + ClasspathExtractor classpathExtractor = new ClasspathExtractor(rewriteMavenArtifactDownloader); + sut = new MavenProjectAnalyzer(classpathExtractor); } @Nested diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java index 96abc034a..eb174aaee 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java @@ -281,7 +281,7 @@ void parseMultiModule1_WithCustomParser() { beanFactory, new ProjectScanner(new DefaultResourceLoader(), parserProperties), new RewriteExecutionContext(), - new MavenProjectAnalyzer(mock(RewriteMavenArtifactDownloader.class), classpathExtractor) + new MavenProjectAnalyzer(new ClasspathExtractor(mock(RewriteMavenArtifactDownloader.class))) ); Set ignoredPatters = Set.of(); From 7dc1a6a09f1852ce0df33748c4e8b6e54e7bafdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Tue, 17 Oct 2023 00:20:25 +0200 Subject: [PATCH 05/10] Remove dummy code --- .../sbm/parsers/maven/MavenModuleParser.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java index 6a29c85ef..be84e914b 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java @@ -169,22 +169,6 @@ private List parseTestSources(List resources, Collection

parseMainSources(Path baseDir, Collection classpath, Collection classBytesClasspath, List resources) { - List array = classBytesClasspath - .stream() - .map(b -> { - return (byte[]) b; - }) - .toList(); - - List classBytesClasspathList = new ArrayList<>(); - classBytesClasspathList.addAll(classBytesClasspath); - - byte[][] classBytesClasspathArray = new byte[classBytesClasspath.size()][]; - for(int i=0; i(); } From 9ca1d252aa8fd73914889cd54327ed92f1e698ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Tue, 17 Oct 2023 00:20:54 +0200 Subject: [PATCH 06/10] WIP keep the used JavaParser in Marker --- .../sbm/parsers/JavaParserMarker.java | 39 +++++++++++++++++++ .../sbm/parsers/ModuleParser.java | 7 ++-- .../sbm/parsers/MavenModuleParserTest.java | 15 ++++++- 3 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/JavaParserMarker.java diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/JavaParserMarker.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/JavaParserMarker.java new file mode 100644 index 000000000..0ccc396dc --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/JavaParserMarker.java @@ -0,0 +1,39 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import lombok.Value; +import lombok.With; +import org.openrewrite.java.JavaParser; +import org.openrewrite.marker.Marker; + +import java.util.UUID; + + +/** + * Used to keep the stateful {@link JavaParser} for later parsing. + * + * This is required when (re-)parsing a submodule somewhere (non-leaf) in a reactor build tree. + * Then this module requires the JavaParser with types from the last parse where types from lower modules are cached. + * + * @author Fabian Krüger + */ +@Value +@With +public class JavaParserMarker implements Marker { + private final UUID id; + private final JavaParser javaParser; +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java index 293c22467..654afe5c9 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java @@ -115,13 +115,14 @@ public List processMainSources( .map(r -> new Parser.Input(ResourceUtil.getPath(r), () -> ResourceUtil.getInputStream(r))) .toList(); - Stream cus = Stream.of(javaParserBuilder) - .map(JavaParser.Builder::build) - .flatMap(parser -> parser.parseInputs(inputs, baseDir, executionContext)) + JavaParser javaParser = javaParserBuilder.build(); + Stream cus = javaParser.parseInputs(inputs, baseDir, executionContext) .peek(s -> alreadyParsed.add(baseDir.resolve(s.getSourcePath()))); + List mainProjectProvenance = new ArrayList<>(provenanceMarkers); mainProjectProvenance.add(sourceSet("main", dependencies, typeCache)); + mainProjectProvenance.add(new JavaParserMarker(UUID.randomUUID(), javaParser)); // FIXME: 945 Why target and not all main? List parsedJavaPaths = mainJavaSources.stream().map(ResourceUtil::getPath).toList(); diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java index e82f01661..45d60b06d 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java @@ -26,6 +26,7 @@ import org.openrewrite.SourceFile; import org.openrewrite.java.JavaParser; import org.openrewrite.java.internal.JavaTypeCache; +import org.openrewrite.java.internal.TypesInUse; import org.openrewrite.java.marker.JavaSourceSet; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; @@ -154,6 +155,10 @@ void differentParsersWithSharedCacheAndSeparateCallsShouldNotResolveTypes() { // -> Should resolve type A // -> Same parser, separate calls, same type cache // --> WORKS! That's what we need. + // BUT! It'd require keeping and parsing the parser -> Can a parser parse the same resource twice? + // Yes, but it needs to be reset + // Type A can also be resolved from B then. + // So keeping and passing the used parser (per source set) would be an option. @Test @DisplayName("Same parser with shared cache in separate calls should resolve types") void sameParserWithSharedCacheInSeparateCallsShouldResolveTypes() { @@ -164,14 +169,23 @@ void sameParserWithSharedCacheInSeparateCallsShouldResolveTypes() { // Same parser two calls SourceFile a = javaParser.parse(aSource).toList().get(0); + SourceFile b1= javaParser.parse(bSource).toList().get(0); + // fails! need to call reset() + javaParser.reset(); SourceFile b = javaParser.parse(bSource).toList().get(0); + J.CompilationUnit compilationUnitB = (J.CompilationUnit) b; String fullyQualifiedName2 = ((JavaType.FullyQualified) compilationUnitB.getClasses().get(0).getExtends().getType()).getFullyQualifiedName(); // A can be resolved assertThat(fullyQualifiedName2).isEqualTo("com.foo.A"); List bTypesInUseFqNames = compilationUnitB.getTypesInUse().getTypesInUse().stream().map(fq -> ((JavaType.FullyQualified) fq).getFullyQualifiedName()).toList(); + + TypesInUse.FindTypesInUse findTypesInUse = new TypesInUse.FindTypesInUse(); + findTypesInUse.visit(compilationUnitB, 0); + System.out.println(findTypesInUse.getTypes()); + // A is in typesInUse of B assertThat(bTypesInUseFqNames).contains("com.foo.A"); //No markers were set @@ -270,7 +284,6 @@ void someTest() { List parsedBuildFiles = buildFileParser.parseBuildFiles(baseDir, List.of(resources.get(0)), List.of(), new RewriteExecutionContext(), false, provenanceMarkersMap); Xml.Document document = parsedBuildFiles.get(0); - Collection classpath = new ArrayList<>(); Collection classBytesClasspath = new ArrayList<>(); From d4848294f4bbf37d206bb75366f82635b37a10f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Tue, 17 Oct 2023 16:02:46 +0200 Subject: [PATCH 07/10] Testing the reuse of JavaParser after parsing a module --- .../sbm/parsers/MavenProject.java | 7 +++ .../parsers/RewriteParserConfiguration.java | 4 +- .../sbm/parsers/maven/MavenModuleParser.java | 52 +++++++++++++++++-- .../sbm/parsers/MavenModuleParserTest.java | 42 ++++++++++----- .../sbm/parsers/RewriteProjectParserTest.java | 2 +- .../maven/RewriteMavenProjectParserTest.java | 8 +-- 6 files changed, 92 insertions(+), 23 deletions(-) diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java index dea784634..006ad252c 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java @@ -142,6 +142,10 @@ public String getSourceDirectory() { return s == null ? ResourceUtil.getPath(pomFile).getParent().resolve("src/main/java").toAbsolutePath().normalize().toString() : s; } + + /** + * Must be called after {@link ParserContext#setParsedBuildFiles(List)}. + */ public Set getCompileClasspathElements() { Scope scope = Scope.Compile; return getClasspathElements(scope); @@ -153,6 +157,9 @@ public Set getTestClasspathElements() { @NotNull private Set getClasspathElements(Scope scope) { + if(classpath == null) { + throw new IllegalStateException("Classpath can not be retrieved before Maven build files were parsed."); + } return this.classpath.get(scope); } diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java index 57267a47f..a5df8d76f 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java @@ -118,8 +118,8 @@ ModuleParser helperWithoutAGoodName() { } @Bean - MavenModuleParser mavenModuleParser(ParserProperties parserPropeties, ModuleParser moduleParser) { - return new MavenModuleParser(parserPropeties, moduleParser); + MavenModuleParser mavenModuleParser(ParserProperties parserProperties, ModuleParser moduleParser, ClasspathExtractor classpathExtractor, ExecutionContext executionContext) { + return new MavenModuleParser(parserProperties, moduleParser, classpathExtractor, executionContext); } @Bean diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java index be84e914b..062d56a57 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java @@ -17,11 +17,13 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.ArrayUtils; import org.openrewrite.ExecutionContext; +import org.openrewrite.Parser; import org.openrewrite.SourceFile; import org.openrewrite.java.JavaParser; import org.openrewrite.marker.Marker; +import org.openrewrite.maven.tree.MavenResolutionResult; +import org.openrewrite.maven.tree.Scope; import org.openrewrite.style.NamedStyles; import org.openrewrite.xml.tree.Xml; import org.springframework.core.io.Resource; @@ -44,6 +46,8 @@ public class MavenModuleParser { private final ParserProperties parserProperties; private final ModuleParser mavenMojoProjectParserPrivateMethods; + private final ClasspathExtractor classpathExtractor; + private final ExecutionContext executionContext; public List parseModuleSourceFiles( List resources, @@ -148,7 +152,7 @@ private Set pathsToOtherMavenProjects(MavenProject mavenProject, Path modu //------------- public ModuleParsingResult parseModule(Path baseDir, String modulePathSegment, Collection classpath, Collection classBytesClasspath, List resources) { - resources = filterResources(baseDir, modulePathSegment, resources); + resources = filterModuleResources(baseDir, modulePathSegment, resources); List parsedSources = new ArrayList<>(); List mainSources = parseMainSources(baseDir, classpath, classBytesClasspath, resources); parsedSources.addAll(mainSources); @@ -172,11 +176,51 @@ private List parseMainSources(Path baseDir, Collection classpa return new ArrayList<>(); } - private List filterResources(Path baseDir, String modulePathSegment, List resources) { - String pattern = "glob:" + baseDir.resolve(modulePathSegment); + private List filterModuleResources(Path baseDir, String modulePathSegment, List resources) { + String pattern = "glob:" + baseDir.resolve(modulePathSegment).normalize().toString() + "/**"; PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(pattern); return resources.stream() .filter(r -> pathMatcher.matches(ResourceUtil.getPath(r))) .toList(); } + + public ModuleParsingResult parseLeafModule(Path baseDir, List resources, MavenResolutionResult result) { + resources = filterModuleResources(baseDir, "", resources); + List parsedSources = new ArrayList<>(); + List compileCP = classpathExtractor.extractClasspath(result, Scope.Compile); + List mainSources = parseMainSources(baseDir, compileCP, resources); + parsedSources.addAll(mainSources); +// List testCP = classpathExtractor.extractClasspath(result, Scope.Test); +// List testSources = parseTestSources(resources, testCP, resources); +// parsedSources.addAll(testSources); + List otherResources = parseOtherResources(resources); + parsedSources.addAll(otherResources); + ModuleParsingResult moduleParsingResult = new ModuleParsingResult(parsedSources); + return moduleParsingResult; + } + +// private List parseTestSources(List resources, List testCP, List moduleResources) { +// JavaParser javaParser = JavaParser.fromJavaVersion().classpath(testCP).build(); +// List mainJavaSourcesParserInputs = moduleResources.stream() +// .filter(this::isMainJavaSource) +// .map(r -> new Parser.Input(ResourceUtil.getPath(r), () -> ResourceUtil.getInputStream(r))) +// .toList(); +// return javaParser.parseInputs(mainJavaSourcesParserInputs, null, executionContext).toList(); +// } + + private boolean isMainJavaSource(Resource resource) { + Path path = ResourceUtil.getPath(resource); + return FileSystems.getDefault().getPathMatcher("glob:**/src/main/java/**").matches(path); + } + + private List parseMainSources(Path baseDir, List compileCP, List moduleResources) { + JavaParser javaParser = JavaParser.fromJavaVersion().classpath(compileCP).build(); + List mainJavaSourcesParserInputs = moduleResources.stream() + .filter(this::isMainJavaSource) + .map(r -> new Parser.Input(ResourceUtil.getPath(r), () -> ResourceUtil.getInputStream(r))) + .toList(); + return javaParser.parseInputs(mainJavaSourcesParserInputs, null, executionContext) + .map(js -> (SourceFile)js.withMarkers(js.getMarkers().addIfAbsent(new JavaParserMarker(UUID.randomUUID(), javaParser)))) + .toList(); + } } diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java index 45d60b06d..7d6737c5b 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java @@ -27,8 +27,10 @@ import org.openrewrite.java.JavaParser; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.internal.TypesInUse; +import org.openrewrite.java.marker.JavaProject; import org.openrewrite.java.marker.JavaSourceSet; import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaSourceFile; import org.openrewrite.java.tree.JavaType; import org.openrewrite.marker.Marker; import org.openrewrite.maven.cache.InMemoryMavenPomCache; @@ -56,10 +58,13 @@ public class MavenModuleParserTest { private MavenModuleParser sut; + private ExecutionContext executionContext; @BeforeEach void beforeEach() { - sut = new MavenModuleParser(new ParserProperties(), new ModuleParser()); + executionContext = new RewriteExecutionContext(); + LocalMavenArtifactCache artifactCache = new LocalMavenArtifactCache(Path.of(System.getProperty("user.home")).resolve(".m2/repository")); + sut = new MavenModuleParser(new ParserProperties(), new ModuleParser(), new ClasspathExtractor(new RewriteMavenArtifactDownloader(artifactCache, null, t -> {new RuntimeException(t);})), executionContext); } /** @@ -194,21 +199,21 @@ void sameParserWithSharedCacheInSeparateCallsShouldResolveTypes() { } + /** + * Example of how a module could be parsed while the JavaParser gets reused by another module (here just a class). + */ @Test - @DisplayName("parse simple project") - void parseSimpleProject() { + @DisplayName("reuse JavaParser from Marker example") + void reuseJavaParserFromMarkerExample() { @Language("xml") String pomXml = """ 4.0.0 - - com.example - example-1-parent - 0.1.0-SNAPSHOT - + com.example app + 0.1.0-SNAPSHOT 17 17 @@ -284,13 +289,24 @@ void someTest() { List parsedBuildFiles = buildFileParser.parseBuildFiles(baseDir, List.of(resources.get(0)), List.of(), new RewriteExecutionContext(), false, provenanceMarkersMap); Xml.Document document = parsedBuildFiles.get(0); - Collection classpath = new ArrayList<>(); - Collection classBytesClasspath = new ArrayList<>(); + ModuleParsingResult result = sut.parseLeafModule(baseDir, resources, document.getMarkers().findFirst(MavenResolutionResult.class).get()); + + // take JavaParser from Marker + JavaParser javaParser = result.sourceFiles().get(0).getMarkers().findFirst(JavaParserMarker.class).get().getJavaParser(); + J.CompilationUnit anotherClass = (J.CompilationUnit) javaParser.parse( + """ + package a.b; + import com.example.app.MainClass; + + public class AnotherClass extends MainClass {} + """ + ).toList().get(0); + + String extendsFullyQualifiedName = ((JavaType.FullyQualified) anotherClass.getClasses().get(0).getExtends().getType()).getFullyQualifiedName(); + // A can be resolved + assertThat(extendsFullyQualifiedName).isEqualTo("com.example.app.MainClass"); - ModuleParsingResult moduleParsingResult = sut.parseModule(baseDir, "", classpath, classBytesClasspath, resources); - assertThat(moduleParsingResult.sourceFiles()).hasSize(2); - assertThat(moduleParsingResult.sourceFiles().get(0).printAll()).isEqualTo(mainClass); } @Test diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java index 4cf0e2b2a..28a6731c3 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java @@ -92,9 +92,9 @@ void parseSimpleMavenProject(@TempDir Path tempDir) { ParserProperties parserProperties = new ParserProperties(); ModuleParser mavenMojoParserPrivateMethods = new ModuleParser(); ExecutionContext executionContext = new InMemoryExecutionContext(t -> {throw new RuntimeException(t);}); - MavenModuleParser mavenModuleParser = new MavenModuleParser(parserProperties, mavenMojoParserPrivateMethods); Path localMavenRepo = Path.of(System.getProperty("user.home")).resolve(".m2/repository"); ClasspathExtractor classpathExtractor = new ClasspathExtractor(new RewriteMavenArtifactDownloader(new LocalMavenArtifactCache(localMavenRepo), null, t -> {throw new RuntimeException(t);})); + MavenModuleParser mavenModuleParser = new MavenModuleParser(parserProperties, mavenMojoParserPrivateMethods, classpathExtractor, executionContext); RewriteProjectParser projectParser = new RewriteProjectParser( new ProvenanceMarkerFactory(new MavenProvenanceMarkerFactory()), new BuildFileParser(), diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java index eb174aaee..cb3ec8b25 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java @@ -269,10 +269,12 @@ void parseMultiModule1_WithCustomParser() { Path baseDir = getMavenProject("multi-module-1"); ModuleParser moduleParser = new ModuleParser(); + ClasspathExtractor classpathExtractor = new ClasspathExtractor(mock(RewriteMavenArtifactDownloader.class)); + RewriteExecutionContext executionContext = new RewriteExecutionContext(); RewriteProjectParser rpp = new RewriteProjectParser( new ProvenanceMarkerFactory(new MavenProvenanceMarkerFactory()), new BuildFileParser(), - new SourceFileParser(new MavenModuleParser(parserProperties, moduleParser)), + new SourceFileParser(new MavenModuleParser(parserProperties, moduleParser, classpathExtractor, executionContext)), new StyleDetector(), parserProperties, mock(ParsingEventListener.class), @@ -280,8 +282,8 @@ void parseMultiModule1_WithCustomParser() { scanScope, beanFactory, new ProjectScanner(new DefaultResourceLoader(), parserProperties), - new RewriteExecutionContext(), - new MavenProjectAnalyzer(new ClasspathExtractor(mock(RewriteMavenArtifactDownloader.class))) + executionContext, + new MavenProjectAnalyzer(classpathExtractor) ); Set ignoredPatters = Set.of(); From 4413aea035e5cc5a240ba6c02657ebcdc0a67664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Tue, 17 Oct 2023 18:10:19 +0200 Subject: [PATCH 08/10] WIP: Passing and reusing parser instances --- .../sbm/parsers/MavenModuleParserTest.java | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java index 7d6737c5b..62793c5d5 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java @@ -32,6 +32,7 @@ import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaSourceFile; import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.Statement; import org.openrewrite.marker.Marker; import org.openrewrite.maven.cache.InMemoryMavenPomCache; import org.openrewrite.maven.cache.LocalMavenArtifactCache; @@ -236,12 +237,8 @@ void reuseJavaParserFromMarkerExample() { @Language("java") String mainClass = """ package com.example.app; - import javax.validation.constraints.Min; - public class MainClass { - @Min("0") - private int number; - } + public class MainClass { } """; @Language("java") String testClass = """ @@ -306,7 +303,34 @@ public class AnotherClass extends MainClass {} // A can be resolved assertThat(extendsFullyQualifiedName).isEqualTo("com.example.app.MainClass"); - + J.CompilationUnit myClass = (J.CompilationUnit) javaParser.parse(""" + package com.example.app; + import a.b.AnotherClass; + import javax.validation.constraints.Min; + + public class MyClass extends AnotherClass { + @Min("0") + private int number; + } + """) + .toList() + .get(0); + + J.ClassDeclaration myClassDecl = myClass.getClasses().get(0); + String firstExtendFqn = ((JavaType.FullyQualified) myClassDecl.getExtends().getType()).getFullyQualifiedName(); + assertThat(firstExtendFqn).isEqualTo("a.b.AnotherClass"); + + // validation-api should be transitively provided from module parsing + assertThat( + ((JavaType.FullyQualified)((J.VariableDeclarations)myClassDecl.getBody().getStatements().get(0)).getAllAnnotations().get(0).getType()).getFullyQualifiedName() + ).isEqualTo("javax.validation.constraints.Min"); + + // Now, let's see if we could add a dependency to the used classpath + Path depPath = Path.of(System.getProperty("user.home")).resolve(".m2/repository/javax/validation/validation-api/2.0.1.Final"); +// javaParser.setClasspath(List.of(depPath)); + + // PROBLEM: When using a shared parser to parse a class in lower module, the types from higher modules are cached. + // Assumption: reset(Collection) does not help, previous tests indicate that resolution is independant of state cleared in reset(). } @Test From 9316304941da73f58ba89d2365645e11316faaf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Wed, 18 Oct 2023 19:47:56 +0200 Subject: [PATCH 09/10] Introduce ClasspathRegistry --- .../sbm/parsers/ClasspathExtractor.java | 11 ++-- .../sbm/parsers/ClasspathRegistry.java | 59 +++++++++++++++++++ .../sbm/parsers/ClasspathRegistryFactory.java | 46 +++++++++++++++ .../sbm/parsers/MavenProject.java | 11 ++-- .../sbm/parsers/ModuleParser.java | 6 +- .../sbm/parsers/ParserContext.java | 6 +- .../parsers/RewriteParserConfiguration.java | 17 ++++-- .../sbm/parsers/RewriteProjectParser.java | 17 ++++++ .../sbm/parsers/SourceFileParser.java | 8 +-- .../sbm/parsers/maven/MavenModuleParser.java | 4 +- .../parsers/maven/MavenProjectAnalyzer.java | 21 ++++--- .../resource/ProjectResourceSetFactory.java | 2 + .../sbm/parsers/RewriteProjectParserTest.java | 4 +- .../maven/MavenProjectAnalyzerTest.java | 4 +- .../maven/RewriteMavenProjectParserTest.java | 4 +- 15 files changed, 180 insertions(+), 40 deletions(-) create mode 100644 sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathRegistry.java create mode 100644 sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathRegistryFactory.java diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathExtractor.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathExtractor.java index 27e73def0..955949ad8 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathExtractor.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathExtractor.java @@ -22,9 +22,8 @@ import org.openrewrite.maven.utilities.MavenArtifactDownloader; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.stream.Collectors; /** @@ -34,7 +33,7 @@ public class ClasspathExtractor { private final MavenArtifactDownloader rewriteMavenArtifactDownloader; - public List extractClasspath(MavenResolutionResult pom, Scope scope) { + public Set extractClasspath(MavenResolutionResult pom, Scope scope) { List resolvedDependencies = pom.getDependencies().get(scope); if (resolvedDependencies != null) { return resolvedDependencies @@ -45,9 +44,9 @@ public List extractClasspath(MavenResolutionResult pom, Scope scope) { .map(rd -> rewriteMavenArtifactDownloader.downloadArtifact(rd)) .filter(Objects::nonNull) .distinct() - .toList(); + .collect(Collectors.toSet()); } else { - return new ArrayList<>(); + return new HashSet<>(); } } } diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathRegistry.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathRegistry.java new file mode 100644 index 000000000..059039706 --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathRegistry.java @@ -0,0 +1,59 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import org.openrewrite.maven.tree.MavenResolutionResult; +import org.openrewrite.maven.tree.Scope; +import org.springframework.sbm.scopes.ProjectMetadata; + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Fabian Krüger + */ +public class ClasspathRegistry { + private final ClasspathExtractor classpathExtractor; + private final Map map; + + public ClasspathRegistry(ClasspathExtractor classpathExtractor) { + this.map = new HashMap<>(); + this.classpathExtractor = classpathExtractor; + } + + public void registerClasspaths(Map map) { + this.map.putAll(map); + } + + public void registerClasspath(Path buildFilePath, MavenResolutionResult mavenResolutionResult) { + this.map.put(buildFilePath, mavenResolutionResult); + } + + public void clear() { + this.map.clear(); + } + + public Set getClasspath(Path buildFileProjectPath, Scope scope) { + if(!map.containsKey(buildFileProjectPath)) { + throw new IllegalArgumentException("The given pom path '%s' does not define a classpath.".formatted(buildFileProjectPath)); + } + MavenResolutionResult mavenResolutionResult = map.get(buildFileProjectPath); + return classpathExtractor.extractClasspath(mavenResolutionResult, scope); + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathRegistryFactory.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathRegistryFactory.java new file mode 100644 index 000000000..f555218fb --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ClasspathRegistryFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import lombok.RequiredArgsConstructor; +import org.openrewrite.maven.tree.MavenResolutionResult; +import org.openrewrite.xml.tree.Xml; + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Fabian Krüger + */ +@RequiredArgsConstructor +public class ClasspathRegistryFactory { + + private final ClasspathExtractor classpathExtractor; + + public ClasspathRegistry create(Path baseDir, List parsedBuildFiles) { + Map map = new HashMap<>(); + parsedBuildFiles.stream() + .forEach(buildFile -> { + Path pomPath = baseDir.resolve(buildFile.getSourcePath()).toAbsolutePath().normalize(); + MavenResolutionResult marker = buildFile.getMarkers().findFirst(MavenResolutionResult.class).get(); + map.put(pomPath, marker); + }); + + return new ClasspathRegistry(classpathExtractor); + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java index 006ad252c..f0fe98ee9 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProject.java @@ -24,7 +24,6 @@ import org.openrewrite.xml.tree.Xml; import org.springframework.core.io.Resource; import org.springframework.sbm.parsers.maven.MavenRuntimeInformation; -import org.springframework.sbm.project.resource.ProjectResourceSet; import org.springframework.sbm.utils.ResourceUtil; import java.io.File; @@ -44,16 +43,17 @@ public class MavenProject { private final Resource pomFile; private final Model pomModel; private final List resources; + private final ClasspathRegistry classpathRegistry; private List collectedProjects = new ArrayList<>(); private Xml.Document sourceFile; private ProjectId projectId; - private Map> classpath; - public MavenProject(Path projectRoot, Resource pomFile, Model pomModel, List resources) { + public MavenProject(Path projectRoot, Resource pomFile, Model pomModel, List resources, ClasspathRegistry classpathRegistry) { this.projectRoot = projectRoot; this.pomFile = pomFile; this.pomModel = pomModel; this.resources = resources; + this.classpathRegistry = classpathRegistry; projectId = new ProjectId(getGroupId(), getArtifactId()); } @@ -157,10 +157,7 @@ public Set getTestClasspathElements() { @NotNull private Set getClasspathElements(Scope scope) { - if(classpath == null) { - throw new IllegalStateException("Classpath can not be retrieved before Maven build files were parsed."); - } - return this.classpath.get(scope); + return classpathRegistry.getClasspath(getPomFilePath(), scope); } public String getTestSourceDirectory() { diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java index 654afe5c9..8b9f7f523 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ModuleParser.java @@ -104,9 +104,9 @@ public List processMainSources( // Or, the classpath must be created from the sources of the project. - Set dependencies = currentProject.getCompileClasspathElements(); + Set jarDependencies = currentProject.getCompileClasspathElements(); - javaParserBuilder.classpath(dependencies); + javaParserBuilder.classpath(jarDependencies); JavaTypeCache typeCache = new JavaTypeCache(); javaParserBuilder.typeCache(typeCache); @@ -121,7 +121,7 @@ public List processMainSources( List mainProjectProvenance = new ArrayList<>(provenanceMarkers); - mainProjectProvenance.add(sourceSet("main", dependencies, typeCache)); + mainProjectProvenance.add(sourceSet("main", jarDependencies, typeCache)); mainProjectProvenance.add(new JavaParserMarker(UUID.randomUUID(), javaParser)); // FIXME: 945 Why target and not all main? diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ParserContext.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ParserContext.java index 81d5f55a9..e5b5eae0f 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ParserContext.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ParserContext.java @@ -40,7 +40,7 @@ public class ParserContext { private final List sortedProjects; @Getter private Map pathDocumentMap; - + private ClasspathRegistry classpathRegistry; public List getActiveProfiles() { @@ -80,4 +80,8 @@ private void addSourceFileToModel(Path baseDir, List sortedProject .filter(p -> ResourceUtil.getPath(p.getPomFile()).toString().equals(baseDir.resolve(s.getSourcePath()).toString())) .forEach(p -> p.setSourceFile(s)); } + + public void setClasspathRegistry(ClasspathRegistry classpathRegistry) { + this.classpathRegistry = classpathRegistry; + } } diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java index a5df8d76f..095587ed8 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java @@ -40,6 +40,7 @@ import java.io.StringWriter; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.HashMap; import java.util.function.Consumer; @@ -152,8 +153,13 @@ ParsingEventListener parsingEventListener(ApplicationEventPublisher eventPublish // } @Bean - MavenProjectAnalyzer mavenProjectAnalyzer(ClasspathExtractor classpathExtractor) { - return new MavenProjectAnalyzer(classpathExtractor); + ClasspathRegistry classpathRegistry(ClasspathExtractor classpathExtractor) { + return new ClasspathRegistry(classpathExtractor); + } + + @Bean + MavenProjectAnalyzer mavenProjectAnalyzer(ClasspathRegistry classpathRegistry) { + return new MavenProjectAnalyzer(classpathRegistry); } @Bean @@ -169,7 +175,8 @@ RewriteProjectParser rewriteProjectParser( ConfigurableListableBeanFactory beanFactory, ProjectScanner projectScanner, ExecutionContext executionContext, - MavenProjectAnalyzer mavenProjectAnalyzer) { + MavenProjectAnalyzer mavenProjectAnalyzer, + ClasspathRegistry classpathRegistry) { return new RewriteProjectParser( provenanceMarkerFactory, buildFileParser, @@ -182,7 +189,9 @@ RewriteProjectParser rewriteProjectParser( beanFactory, projectScanner, executionContext, - mavenProjectAnalyzer); + mavenProjectAnalyzer, + classpathRegistry + ); } @Bean diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteProjectParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteProjectParser.java index a343179aa..10eeb939d 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteProjectParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteProjectParser.java @@ -21,6 +21,7 @@ import org.openrewrite.ExecutionContext; import org.openrewrite.SourceFile; import org.openrewrite.marker.Marker; +import org.openrewrite.maven.tree.MavenResolutionResult; import org.openrewrite.style.NamedStyles; import org.openrewrite.tree.ParsingEventListener; import org.openrewrite.tree.ParsingExecutionContextView; @@ -33,6 +34,7 @@ import org.springframework.sbm.parsers.maven.BuildFileParser; import org.springframework.sbm.parsers.maven.MavenProjectAnalyzer; import org.springframework.sbm.parsers.maven.ProvenanceMarkerFactory; +import org.springframework.sbm.project.resource.ProjectResourceSetFactory; import org.springframework.sbm.scopes.ScanScope; import java.nio.file.Path; @@ -77,6 +79,7 @@ public class RewriteProjectParser { private final ProjectScanner scanner; private final ExecutionContext executionContext; private final MavenProjectAnalyzer mavenProjectAnalyzer; + private final ClasspathRegistry classpathRegistry; /** @@ -114,6 +117,7 @@ public RewriteProjectParsingResult parse(Path givenBaseDir, List resou List parsedBuildFiles = buildFileParser.parseBuildFiles(baseDir, parserContext.getBuildFileResources(), parserContext.getActiveProfiles(), executionContext, parserProperties.isSkipMavenParsing(), provenanceMarkers); parserContext.setParsedBuildFiles(parsedBuildFiles); + registerClasspaths(baseDir, parsedBuildFiles); log.trace("Start to parse %d source files in %d modules".formatted(resources.size() + parsedBuildFiles.size(), parsedBuildFiles.size())); List otherSourceFiles = sourceFileParser.parseOtherSourceFiles(baseDir, parserContext, resources, provenanceMarkers, styles, executionContext); @@ -130,6 +134,19 @@ public RewriteProjectParsingResult parse(Path givenBaseDir, List resou return new RewriteProjectParsingResult(sourceFiles, executionContext); } + private void registerClasspaths(Path baseDir, List parsedBuildFiles) { + // The classpath must be passed down to the module parsing + // The ClasspathInfo must provide the classpath for all source sets for all modules + // E.g.: + // List mainModuleCp = classpathInfo.getClasspath(moduleName, "main"); + parsedBuildFiles.stream() + .forEach(buildFile -> { + Path pomPath = baseDir.resolve(buildFile.getSourcePath()).toAbsolutePath().normalize(); + MavenResolutionResult mavenResolutionResult = buildFile.getMarkers().findFirst(MavenResolutionResult.class).get(); + classpathRegistry.registerClasspath(pomPath, mavenResolutionResult); + }); + } + @NotNull private static Path normalizePath(Path givenBaseDir) { if (!givenBaseDir.isAbsolute()) { diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SourceFileParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SourceFileParser.java index dfe725d8d..4c42ae987 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SourceFileParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SourceFileParser.java @@ -19,19 +19,14 @@ import lombok.extern.slf4j.Slf4j; import org.openrewrite.ExecutionContext; import org.openrewrite.SourceFile; -import org.openrewrite.java.JavaParser; import org.openrewrite.marker.Marker; import org.openrewrite.style.NamedStyles; import org.openrewrite.xml.tree.Xml; import org.springframework.core.io.Resource; import org.springframework.sbm.parsers.maven.MavenModuleParser; -import org.springframework.sbm.utils.ResourceUtil; import java.nio.file.Path; -import java.nio.file.PathMatcher; import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * @author Fabian Krüger @@ -49,7 +44,8 @@ public List parseOtherSourceFiles( List resources, Map> provenanceMarkers, List styles, - ExecutionContext executionContext) { + ExecutionContext executionContext + ) { Set parsedSourceFiles = new LinkedHashSet<>(); diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java index 062d56a57..298470f77 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenModuleParser.java @@ -187,7 +187,7 @@ private List filterModuleResources(Path baseDir, String modulePathSegm public ModuleParsingResult parseLeafModule(Path baseDir, List resources, MavenResolutionResult result) { resources = filterModuleResources(baseDir, "", resources); List parsedSources = new ArrayList<>(); - List compileCP = classpathExtractor.extractClasspath(result, Scope.Compile); + Set compileCP = classpathExtractor.extractClasspath(result, Scope.Compile); List mainSources = parseMainSources(baseDir, compileCP, resources); parsedSources.addAll(mainSources); // List testCP = classpathExtractor.extractClasspath(result, Scope.Test); @@ -213,7 +213,7 @@ private boolean isMainJavaSource(Resource resource) { return FileSystems.getDefault().getPathMatcher("glob:**/src/main/java/**").matches(path); } - private List parseMainSources(Path baseDir, List compileCP, List moduleResources) { + private List parseMainSources(Path baseDir, Set compileCP, List moduleResources) { JavaParser javaParser = JavaParser.fromJavaVersion().classpath(compileCP).build(); List mainJavaSourcesParserInputs = moduleResources.stream() .filter(this::isMainJavaSource) diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java index fc20685b6..3dc220f21 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzer.java @@ -18,9 +18,8 @@ import org.apache.maven.model.*; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; -import org.openrewrite.maven.utilities.MavenArtifactDownloader; import org.springframework.core.io.Resource; -import org.springframework.sbm.parsers.ClasspathExtractor; +import org.springframework.sbm.parsers.ClasspathRegistry; import org.springframework.sbm.parsers.MavenProject; import org.springframework.sbm.parsers.ParserContext; import org.springframework.sbm.utils.ResourceUtil; @@ -42,10 +41,10 @@ public class MavenProjectAnalyzer { private static final String POM_XML = "pom.xml"; private static final MavenXpp3Reader XPP_3_READER = new MavenXpp3Reader(); - private final ClasspathExtractor classpathExtractor; + private final ClasspathRegistry classpathRegistry; - public MavenProjectAnalyzer(ClasspathExtractor classpathExtractor) { - this.classpathExtractor = classpathExtractor; + public MavenProjectAnalyzer(ClasspathRegistry classpathRegistry) { + this.classpathRegistry = classpathRegistry; } public List getSortedProjects(Path baseDir, List resources) { @@ -56,11 +55,17 @@ public List getSortedProjects(Path baseDir, List resourc throw new IllegalArgumentException("The provided resources did not contain any 'pom.xml' file."); } - Resource rootPom = allPomFiles.stream().filter(r -> ResourceUtil.getPath(r).toString().equals(baseDir.resolve(POM_XML).normalize().toString())).findFirst().orElseThrow(() -> new IllegalArgumentException("The provided resources do not contain a root 'pom.xml' file.")); + Resource rootPom = allPomFiles.stream() + .filter(r -> { + String string = baseDir.resolve(POM_XML).normalize().toString(); + return ResourceUtil.getPath(r).toString().equals(string); + }) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("The provided resources do not contain a root 'pom.xml' file.")); Model rootPomModel = new Model(rootPom); if (isSingleModuleProject(rootPomModel)) { - return List.of(new MavenProject(baseDir, rootPom, rootPomModel, resources)); + return List.of(new MavenProject(baseDir, rootPom, rootPomModel, resources, classpathRegistry)); } List reactorModels = new ArrayList<>(); recursivelyFindReactorModules(baseDir, null, reactorModels, allPomFiles, rootPomModel); @@ -76,7 +81,7 @@ private List map(Path baseDir, List resources, List { String projectDir = baseDir.resolve(m.getProjectDirectory().toString()).normalize().toString(); List filteredResources = resources.stream().filter(r -> ResourceUtil.getPath(r).toString().startsWith(projectDir)).toList(); - mavenProjects.add(new MavenProject(baseDir, m.getResource(), m, filteredResources)); + mavenProjects.add(new MavenProject(baseDir, m.getResource(), m, filteredResources, classpathRegistry)); }); // set all non parent poms as collected projects for root parent pom List collected = new ArrayList<>(mavenProjects); diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/project/resource/ProjectResourceSetFactory.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/project/resource/ProjectResourceSetFactory.java index 27c65cabb..0ec191acd 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/project/resource/ProjectResourceSetFactory.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/project/resource/ProjectResourceSetFactory.java @@ -18,6 +18,7 @@ import lombok.RequiredArgsConstructor; import org.openrewrite.ExecutionContext; import org.openrewrite.SourceFile; +import org.openrewrite.xml.tree.Xml; import org.springframework.sbm.project.RewriteSourceFileWrapper; import java.nio.file.Path; @@ -41,4 +42,5 @@ public ProjectResourceSet create(Path baseDir, List sourceFiles) { public ProjectResourceSet createFromSourceFileHolders(List> rewriteSourceFileHolders) { return new ProjectResourceSet(rewriteSourceFileHolders, executionContext, rewriteMigrationResultMerger); } + } diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java index 28a6731c3..8b5d19600 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java @@ -95,6 +95,7 @@ void parseSimpleMavenProject(@TempDir Path tempDir) { Path localMavenRepo = Path.of(System.getProperty("user.home")).resolve(".m2/repository"); ClasspathExtractor classpathExtractor = new ClasspathExtractor(new RewriteMavenArtifactDownloader(new LocalMavenArtifactCache(localMavenRepo), null, t -> {throw new RuntimeException(t);})); MavenModuleParser mavenModuleParser = new MavenModuleParser(parserProperties, mavenMojoParserPrivateMethods, classpathExtractor, executionContext); + ClasspathRegistry classpathRegistry = mock(ClasspathRegistry.class); RewriteProjectParser projectParser = new RewriteProjectParser( new ProvenanceMarkerFactory(new MavenProvenanceMarkerFactory()), new BuildFileParser(), @@ -107,7 +108,8 @@ void parseSimpleMavenProject(@TempDir Path tempDir) { mock(ConfigurableListableBeanFactory.class), new ProjectScanner(new DefaultResourceLoader(), parserProperties), executionContext, - new MavenProjectAnalyzer(new ClasspathExtractor(mock(RewriteMavenArtifactDownloader.class))) + new MavenProjectAnalyzer(classpathRegistry), + classpathRegistry ); List parsedFiles = new ArrayList<>(); diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java index 9ea59de89..0fe2e3671 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/MavenProjectAnalyzerTest.java @@ -27,6 +27,7 @@ import org.openrewrite.maven.utilities.MavenArtifactDownloader; import org.springframework.core.io.Resource; import org.springframework.sbm.parsers.ClasspathExtractor; +import org.springframework.sbm.parsers.ClasspathRegistry; import org.springframework.sbm.parsers.MavenProject; import org.springframework.sbm.parsers.RewriteMavenArtifactDownloader; import org.springframework.sbm.test.util.DummyResource; @@ -52,7 +53,8 @@ class MavenProjectAnalyzerTest { void beforeEach() { MavenArtifactDownloader rewriteMavenArtifactDownloader = Mockito.mock(RewriteMavenArtifactDownloader.class); ClasspathExtractor classpathExtractor = new ClasspathExtractor(rewriteMavenArtifactDownloader); - sut = new MavenProjectAnalyzer(classpathExtractor); + ClasspathRegistry classpathRegistry = new ClasspathRegistry(classpathExtractor); + sut = new MavenProjectAnalyzer(classpathRegistry); } @Nested diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java index cb3ec8b25..1759e999f 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/maven/RewriteMavenProjectParserTest.java @@ -271,6 +271,7 @@ void parseMultiModule1_WithCustomParser() { ClasspathExtractor classpathExtractor = new ClasspathExtractor(mock(RewriteMavenArtifactDownloader.class)); RewriteExecutionContext executionContext = new RewriteExecutionContext(); + ClasspathRegistry classpathRegistry = new ClasspathRegistry(classpathExtractor); RewriteProjectParser rpp = new RewriteProjectParser( new ProvenanceMarkerFactory(new MavenProvenanceMarkerFactory()), new BuildFileParser(), @@ -283,7 +284,8 @@ void parseMultiModule1_WithCustomParser() { beanFactory, new ProjectScanner(new DefaultResourceLoader(), parserProperties), executionContext, - new MavenProjectAnalyzer(classpathExtractor) + new MavenProjectAnalyzer(classpathRegistry), + classpathRegistry ); Set ignoredPatters = Set.of(); From f45d696b919cf9adbfd14a039922b5c12fb518d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Wed, 18 Oct 2023 19:48:09 +0200 Subject: [PATCH 10/10] Testing options --- ...> JavaParserTypeCacheExaminationTest.java} | 152 +---------- .../MavenPartialProjectParsingTest.java | 237 ++++++++++++++++++ 2 files changed, 242 insertions(+), 147 deletions(-) rename sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/{MavenModuleParserTest.java => JavaParserTypeCacheExaminationTest.java} (65%) create mode 100644 sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenPartialProjectParsingTest.java diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/JavaParserTypeCacheExaminationTest.java similarity index 65% rename from sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java rename to sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/JavaParserTypeCacheExaminationTest.java index 62793c5d5..1eff76801 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenModuleParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/JavaParserTypeCacheExaminationTest.java @@ -22,24 +22,17 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.openrewrite.ExecutionContext; -import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.SourceFile; import org.openrewrite.java.JavaParser; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.internal.TypesInUse; -import org.openrewrite.java.marker.JavaProject; -import org.openrewrite.java.marker.JavaSourceSet; import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaSourceFile; import org.openrewrite.java.tree.JavaType; -import org.openrewrite.java.tree.Statement; import org.openrewrite.marker.Marker; -import org.openrewrite.maven.cache.InMemoryMavenPomCache; import org.openrewrite.maven.cache.LocalMavenArtifactCache; import org.openrewrite.maven.tree.MavenResolutionResult; import org.openrewrite.maven.tree.Scope; import org.openrewrite.maven.utilities.MavenArtifactDownloader; -import org.openrewrite.style.NamedStyles; import org.openrewrite.xml.tree.Xml; import org.springframework.core.io.Resource; import org.springframework.sbm.parsers.maven.BuildFileParser; @@ -56,7 +49,7 @@ /** * @author Fabian Krüger */ -public class MavenModuleParserTest { +public class JavaParserTypeCacheExaminationTest { private MavenModuleParser sut; private ExecutionContext executionContext; @@ -326,147 +319,12 @@ public class MyClass extends AnotherClass { ).isEqualTo("javax.validation.constraints.Min"); // Now, let's see if we could add a dependency to the used classpath - Path depPath = Path.of(System.getProperty("user.home")).resolve(".m2/repository/javax/validation/validation-api/2.0.1.Final"); -// javaParser.setClasspath(List.of(depPath)); + Path depPath = Path.of(System.getProperty("user.home")).resolve(".m2/repository/org/jetbrains/annotations/24.0.1/annotations-24.0.1.jar"); + javaParser.setClasspath(List.of(depPath)); // Here we'd need to add the dependencies from lower modules, if any - // PROBLEM: When using a shared parser to parse a class in lower module, the types from higher modules are cached. - // Assumption: reset(Collection) does not help, previous tests indicate that resolution is independant of state cleared in reset(). - } - @Test - @DisplayName("parse reactor project") - void parseReactorProject() { - @Language("xml") - String parentPom = """ - - - 4.0.0 - com.example - example-1-parent - 0.1.0-SNAPSHOT - pom - - 17 - 17 - - - module-a - module-b - module-c - - - """; - - @Language("xml") - String moduleAPom = """ - - - 4.0.0 - - com.example - example-1-parent - 0.1.0-SNAPSHOT - - module-a - - 17 - 17 - - - - com.example - module-b - ${project.version} - - - javax.validation - validation-api - 2.0.1.Final - - - - """; - @Language("xml") - String moduleBPom = """ - - - 4.0.0 - - com.example - example-1-parent - 0.1.0-SNAPSHOT - - module-b - - 17 - 17 - - - - com.example - module-c - ${project.version} - - - - """; - - @Language("xml") - String moduleCPom = """ - - - 4.0.0 - - com.example - example-1-parent - 0.1.0-SNAPSHOT - - module-c - - 17 - 17 - - - """; - - Path baseDir = Path.of("./target").toAbsolutePath().normalize(); - List resources = List.of( - new DummyResource(baseDir.resolve("pom.xml"), parentPom), - new DummyResource(baseDir.resolve("module-a/pom.xml"), moduleAPom), - new DummyResource(baseDir.resolve("module-b/pom.xml"), moduleBPom), - new DummyResource(baseDir.resolve("module-c/pom.xml"), moduleCPom) - ); - ExecutionContext executionContext = new InMemoryExecutionContext(); -/* - // used to calculate paths to other modules. - // TODO: Remove and filter all provided resources by module path segment - MavenProject mavenProject = null; - // used to retrieve sourcePath which can be calculated having the module path segment and baseDir - Xml.Document moduleBuildFile = null; - // required, can be taken from a resource in same source dir?! - List provenanceMarkers = null; - // Make this a Spring bean - List styles = null; - // provided as bean - ExecutionContext executionContext = null; - // required - Path baseDir = null; - sut.parseModuleSourceFiles(resources, mavenProject, moduleBuildFile, provenanceMarkers, styles, executionContext, baseDir); -*/ - BuildFileParser buildFileParser = new BuildFileParser(); - List parsedBuildFiles = buildFileParser.parseBuildFiles(baseDir, resources, List.of(), executionContext, false, Map.of()); - - Path locaMavenRepo = Path.of(System.getProperty("user.home")).resolve(".m2/repository"); - MavenArtifactDownloader artifactDownloader = new RewriteMavenArtifactDownloader(new LocalMavenArtifactCache(locaMavenRepo), null, t -> {throw new RuntimeException(t);}); - ClasspathExtractor classpathExtractor = new ClasspathExtractor(artifactDownloader); - List classpath = classpathExtractor.extractClasspath(parsedBuildFiles.get(0).getMarkers().findFirst(MavenResolutionResult.class).get(), Scope.Compile); - Collection classBytesClasspath = List.of(); - String modulePathSegment = "module-c"; - ModuleParsingResult result = sut.parseModule(baseDir, modulePathSegment, classpath, classBytesClasspath, resources); - assertThat(result.sourceFiles()).hasSize(0); + // PROBLEM: When using a shared parser to parse a class in lower module, the types from higher modules are cached. + // Assumption: reset(Collection) does not help, previous tests indicate that resolution is independant of state cleared in reset(). } - } diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenPartialProjectParsingTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenPartialProjectParsingTest.java new file mode 100644 index 000000000..07f4e9434 --- /dev/null +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenPartialProjectParsingTest.java @@ -0,0 +1,237 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import org.checkerframework.checker.units.qual.A; +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.io.TempDir; +import org.openrewrite.ExecutionContext; +import org.openrewrite.internal.InMemoryLargeSourceSet; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.tree.J; +import org.openrewrite.maven.AddDependencyVisitor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.Resource; +import org.springframework.sbm.boot.autoconfigure.SbmSupportRewriteConfiguration; +import org.springframework.sbm.project.resource.ProjectResourceSet; +import org.springframework.sbm.project.resource.ProjectResourceSetFactory; +import org.springframework.sbm.support.openrewrite.GenericOpenRewriteRecipe; +import org.springframework.sbm.test.util.DummyResource; + +import java.nio.file.Path; +import java.util.List; + +/** + * @author Fabian Krüger + */ +@SpringBootTest(classes = SbmSupportRewriteConfiguration.class) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class MavenPartialProjectParsingTest { + + @Autowired + RewriteProjectParser rewriteProjectParser; + + @Autowired + ProjectResourceSetFactory resourceSetFactory; + + @Autowired + private ExecutionContext executionContext; + + @TempDir Path baseDir; + + private static RewriteProjectParsingResult parsingResult; + + @Language("xml") + String parentPom = """ + + + 4.0.0 + com.example + example-1-parent + 0.1.0-SNAPSHOT + pom + + 17 + 17 + + + module-a + module-b + module-c + + + """; + + @Language("xml") + String moduleAPom = """ + + + 4.0.0 + + com.example + example-1-parent + 0.1.0-SNAPSHOT + + module-a + + 17 + 17 + + + + com.example + module-b + ${project.version} + + + javax.validation + validation-api + 2.0.1.Final + + + + """; + + @Language("xml") + String moduleBPom = """ + + + 4.0.0 + + com.example + example-1-parent + 0.1.0-SNAPSHOT + + module-b + + 17 + 17 + + + + com.example + module-c + ${project.version} + + + + """; + + @Language("xml") + String moduleCPom = """ + + + 4.0.0 + + com.example + example-1-parent + 0.1.0-SNAPSHOT + + module-c + + 17 + 17 + + + """; + + @Test + @Order(1) + @DisplayName("parse reactor project") + void parseReactorProject() { + List resources = List.of( + new DummyResource(baseDir.resolve("pom.xml"), parentPom), + new DummyResource(baseDir.resolve("module-a/pom.xml"), moduleAPom), + new DummyResource(baseDir.resolve("module-b/pom.xml"), moduleBPom), + new DummyResource(baseDir.resolve("module-b/src/main/java/MainB.java"), """ + public class MainB { + String name; + } + """), + new DummyResource(baseDir.resolve("module-c/pom.xml"), moduleCPom) + ); + + + parsingResult = rewriteProjectParser.parse(baseDir, resources); + // TODO: verify initial parsing result here + } + + @Test + @Order(2) + @DisplayName("adding dependency to B") + void addingDependencyToB() { + GenericOpenRewriteRecipe recipe = new GenericOpenRewriteRecipe<>(() -> new AddDependencyVisitor("com.example", "module-b", "0.1.0-SNAPSHOT", null, null, null, null, null, null, null)); + ProjectResourceSet resourceSet = resourceSetFactory.create(baseDir, parsingResult.sourceFiles()); + resourceSet.apply(recipe); + // TODO: assertion the classpath change + } + + @Test + @Order(3) + @DisplayName("add code using the new types") + void addCodeUsingTheNewTypes() { + JavaIsoVisitor visitor = new JavaIsoVisitor<>() { + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext executionContext) { + J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, executionContext); +// cd.getBody().getStatements().get(0); +// ((J.VariableDeclarations)cd.getBody().getStatements().get(0)) + JavaTemplate.builder("@Nullable").javaParser() + return cd; + } + }; + + GenericOpenRewriteRecipe> recipe = new GenericOpenRewriteRecipe<>(() -> visitor); + ProjectResourceSet resourceSet = resourceSetFactory.create(baseDir, parsingResult.sourceFiles()); + resourceSet.apply(recipe); + } + + + + +/* + // used to calculate paths to other modules. + // TODO: Remove and filter all provided resources by module path segment + MavenProject mavenProject = null; + // used to retrieve sourcePath which can be calculated having the module path segment and baseDir + Xml.Document moduleBuildFile = null; + // required, can be taken from a resource in same source dir?! + List provenanceMarkers = null; + // Make this a Spring bean + List styles = null; + // provided as bean + ExecutionContext executionContext = null; + // required + Path baseDir = null; + sut.parseModuleSourceFiles(resources, mavenProject, moduleBuildFile, provenanceMarkers, styles, executionContext, baseDir); +*/ +// BuildFileParser buildFileParser = new BuildFileParser(); +// List parsedBuildFiles = buildFileParser.parseBuildFiles(baseDir, resources, List.of(), executionContext, false, Map.of()); +// +// Path locaMavenRepo = Path.of(System.getProperty("user.home")).resolve(".m2/repository"); +// MavenArtifactDownloader artifactDownloader = new RewriteMavenArtifactDownloader(new LocalMavenArtifactCache(locaMavenRepo), null, t -> {throw new RuntimeException(t);}); +// ClasspathExtractor classpathExtractor = new ClasspathExtractor(artifactDownloader); +// List classpath = classpathExtractor.extractClasspath(parsedBuildFiles.get(0).getMarkers().findFirst(MavenResolutionResult.class).get(), Scope.Compile); +// Collection classBytesClasspath = List.of(); +// String modulePathSegment = "module-c"; +// ModuleParsingResult result = sut.parseModule(baseDir, modulePathSegment, classpath, classBytesClasspath, resources); +// assertThat(result.sourceFiles()).hasSize(0); +// } + +}