diff --git a/rewrite-core/src/main/java/org/openrewrite/ParseError.java b/rewrite-core/src/main/java/org/openrewrite/ParseError.java new file mode 100644 index 00000000000..68b461f5106 --- /dev/null +++ b/rewrite-core/src/main/java/org/openrewrite/ParseError.java @@ -0,0 +1,100 @@ +/* + * Copyright 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.openrewrite; + +import lombok.*; +import org.openrewrite.internal.EncodingDetectingInputStream; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.marker.Markers; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.Collections; +import java.util.UUID; + +import static java.util.Collections.singletonList; + +@Value +public class ParseError implements SourceFile { + @With + @EqualsAndHashCode.Include + @Getter + UUID id; + + @With + @Getter + Markers markers; + + @With + @Getter + Path sourcePath; + + @With + @Getter + @Nullable + FileAttributes fileAttributes; + + @Nullable // for backwards compatibility + @With(AccessLevel.PRIVATE) + String charsetName; + + @Override + public Charset getCharset() { + return charsetName == null ? StandardCharsets.UTF_8 : Charset.forName(charsetName); + } + + @SuppressWarnings("unchecked") + @Override + public SourceFile withCharset(Charset charset) { + return withCharsetName(charset.name()); + } + + @With + @Getter + boolean charsetBomMarked; + + @With + @Getter + @Nullable + Checksum checksum; + + @With + String text; + + @Override + public

boolean isAcceptable(TreeVisitor v, P p) { + return true; + } + + public static ParseError build(Parser parser, + Parser.Input input, + @Nullable Path relativeTo, + ExecutionContext ctx, + Throwable t) { + EncodingDetectingInputStream is = input.getSource(ctx); + return new ParseError( + Tree.randomId(), + new Markers(Tree.randomId(), singletonList(ParseExceptionResult.build(parser, t))), + input.getRelativePath(relativeTo), + input.getFileAttributes(), + parser.getCharset(ctx).name(), + is.isCharsetBomMarked(), + null, + is.readFully() + ); + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/ParseExceptionResult.java b/rewrite-core/src/main/java/org/openrewrite/ParseExceptionResult.java index 6fbbd2ec0e0..01620bf27b8 100644 --- a/rewrite-core/src/main/java/org/openrewrite/ParseExceptionResult.java +++ b/rewrite-core/src/main/java/org/openrewrite/ParseExceptionResult.java @@ -30,7 +30,7 @@ public class ParseExceptionResult implements Marker { UUID id; String message; - public static ParseExceptionResult build(Parser parser, Throwable t) { + public static ParseExceptionResult build(Parser parser, Throwable t) { return new ParseExceptionResult(randomId(), ExceptionUtils.sanitizeStackTrace(t, parser.getClass())); } } diff --git a/rewrite-core/src/main/java/org/openrewrite/ParseWarning.java b/rewrite-core/src/main/java/org/openrewrite/ParseWarning.java index 36ff87581f8..c1359a0d478 100644 --- a/rewrite-core/src/main/java/org/openrewrite/ParseWarning.java +++ b/rewrite-core/src/main/java/org/openrewrite/ParseWarning.java @@ -30,7 +30,7 @@ public class ParseWarning implements Marker { UUID id; String message; - public static ParseWarning build(Parser parser, Throwable t) { + public static ParseWarning build(Parser parser, Throwable t) { return new ParseWarning(randomId(), ExceptionUtils.sanitizeStackTrace(t, parser.getClass())); } } diff --git a/rewrite-core/src/main/java/org/openrewrite/Parser.java b/rewrite-core/src/main/java/org/openrewrite/Parser.java index 2ffdd0da77a..bb922ac454d 100644 --- a/rewrite-core/src/main/java/org/openrewrite/Parser.java +++ b/rewrite-core/src/main/java/org/openrewrite/Parser.java @@ -37,8 +37,8 @@ import static java.util.stream.Collectors.toList; -public interface Parser { - default Stream parse(Iterable sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { +public interface Parser { + default Stream parse(Iterable sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { return parseInputs(StreamSupport .stream(sourceFiles.spliterator(), false) .map(sourceFile -> new Input(sourceFile, () -> { @@ -54,11 +54,11 @@ default Stream parse(Iterable sourceFiles, @Nullable Path relativeTo, E ); } - default Stream parse(String... sources) { + default Stream parse(String... sources) { return parse(new InMemoryExecutionContext(), sources); } - default Stream parse(ExecutionContext ctx, String... sources) { + default Stream parse(ExecutionContext ctx, String... sources) { return parseInputs( Arrays.stream(sources).map(source -> new Input( @@ -79,7 +79,7 @@ default Stream parse(ExecutionContext ctx, String... sources) { * @param ctx The execution context * @return A stream of {@link SourceFile}. */ - Stream parseInputs(Iterable sources, @Nullable Path relativeTo, ExecutionContext ctx); + Stream parseInputs(Iterable sources, @Nullable Path relativeTo, ExecutionContext ctx); boolean accept(Path path); @@ -87,13 +87,12 @@ default boolean accept(Input input) { return input.isSynthetic() || accept(input.getPath()); } - default List acceptedInputs(Iterable input) { + default Stream acceptedInputs(Iterable input) { return StreamSupport.stream(input.spliterator(), false) - .filter(this::accept) - .collect(toList()); + .filter(this::accept); } - default Parser reset() { + default Parser reset() { return this; } @@ -218,7 +217,7 @@ abstract class Builder implements Cloneable { @Getter private final Class sourceFileType; - public abstract Parser build(); + public abstract Parser build(); /** * The name of the domain specific language this parser builder produces a parser for. diff --git a/rewrite-core/src/main/java/org/openrewrite/binary/BinaryParser.java b/rewrite-core/src/main/java/org/openrewrite/binary/BinaryParser.java index 64013a97f05..aea6815fe5a 100755 --- a/rewrite-core/src/main/java/org/openrewrite/binary/BinaryParser.java +++ b/rewrite-core/src/main/java/org/openrewrite/binary/BinaryParser.java @@ -16,13 +16,13 @@ package org.openrewrite.binary; import org.openrewrite.ExecutionContext; +import org.openrewrite.ParseError; import org.openrewrite.Parser; +import org.openrewrite.SourceFile; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.marker.Markers; -import org.openrewrite.tree.ParsingExecutionContextView; import java.nio.file.Path; -import java.util.Objects; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -32,10 +32,10 @@ /** * Doesn't actually _parse_ anything, but if you want to wrap binary data into a SourceFile, this will do the trick */ -public class BinaryParser implements Parser { +public class BinaryParser implements Parser { @Override - public Stream parseInputs(Iterable sources, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream parseInputs(Iterable sources, @Nullable Path relativeTo, ExecutionContext ctx) { return StreamSupport.stream(sources.spliterator(), false) .map(source -> { Path path = source.getRelativePath(relativeTo); @@ -46,13 +46,11 @@ public Stream parseInputs(Iterable sources, @Nullable Path relati source.getFileAttributes(), null, readAllBytes(source.getSource(ctx))); - } catch (Exception e) { - ParsingExecutionContextView.view(ctx).parseFailure(source, relativeTo, this, e); - ctx.getOnError().accept(e); + } catch (Throwable t) { + ctx.getOnError().accept(t); + return ParseError.build(this, source, relativeTo, ctx, t); } - return null; - }) - .filter(Objects::nonNull); + }); } @Override diff --git a/rewrite-core/src/main/java/org/openrewrite/quark/QuarkParser.java b/rewrite-core/src/main/java/org/openrewrite/quark/QuarkParser.java index 9768abf6ca7..7a626a1785b 100644 --- a/rewrite-core/src/main/java/org/openrewrite/quark/QuarkParser.java +++ b/rewrite-core/src/main/java/org/openrewrite/quark/QuarkParser.java @@ -27,15 +27,14 @@ import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.*; -import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; import static org.openrewrite.Tree.randomId; -public class QuarkParser implements Parser { +public class QuarkParser implements Parser { - public static List parseAllOtherFiles(Path rootDir, List sourceFiles) throws IOException { + public static Stream parseAllOtherFiles(Path rootDir, List sourceFiles) throws IOException { Stack> gitignores = new Stack<>(); parseGitignore(new File(System.getProperty("user.home") + "/.gitignore"), gitignores); @@ -85,8 +84,7 @@ private boolean isIgnored(Path path) { } }); - return new QuarkParser().parse(quarks, rootDir, new InMemoryExecutionContext()) - .collect(Collectors.toList()); + return new QuarkParser().parse(quarks, rootDir, new InMemoryExecutionContext()); } private static void parseGitignore(File gitignore, Stack> gitignores) throws IOException { @@ -107,7 +105,7 @@ private static void parseGitignore(File gitignore, Stack> giti } @Override - public Stream parseInputs(Iterable sources, @Nullable Path relativeTo, + public Stream parseInputs(Iterable sources, @Nullable Path relativeTo, ExecutionContext ctx) { return StreamSupport.stream(sources.spliterator(), false).map(source -> new Quark(randomId(), @@ -138,7 +136,7 @@ public Builder() { } @Override - public Parser build() { + public QuarkParser build() { return new QuarkParser(); } @@ -146,6 +144,5 @@ public Parser build() { public String getDslName() { return "other"; } - } } diff --git a/rewrite-core/src/main/java/org/openrewrite/text/CreateTextFile.java b/rewrite-core/src/main/java/org/openrewrite/text/CreateTextFile.java index 0a99919deb1..93c3224da36 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/CreateTextFile.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/CreateTextFile.java @@ -80,10 +80,10 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { } @Override - public Collection

generate(AtomicBoolean shouldCreate, ExecutionContext ctx) { + public Collection<SourceFile> generate(AtomicBoolean shouldCreate, ExecutionContext ctx) { if(shouldCreate.get()) { return new PlainTextParser().parse(fileContents) - .map(brandNewFile -> brandNewFile.withSourcePath(Paths.get(relativeFileName))) + .map(brandNewFile -> (SourceFile) brandNewFile.withSourcePath(Paths.get(relativeFileName))) .collect(Collectors.toList()); } return emptyList(); diff --git a/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java b/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java index 236e03c427b..b49206a40d0 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java @@ -16,6 +16,7 @@ package org.openrewrite.text; import org.openrewrite.ExecutionContext; +import org.openrewrite.ParseError; import org.openrewrite.Parser; import org.openrewrite.SourceFile; import org.openrewrite.internal.EncodingDetectingInputStream; @@ -25,13 +26,12 @@ import org.openrewrite.tree.ParsingExecutionContextView; import java.nio.file.Path; -import java.util.Objects; import java.util.stream.Stream; import java.util.stream.StreamSupport; import static org.openrewrite.Tree.randomId; -public class PlainTextParser implements Parser<PlainText> { +public class PlainTextParser implements Parser { /** * Downcast a {@link SourceFile} to a {@link PlainText} if it isn't already one. @@ -59,33 +59,32 @@ public static PlainText convert(SourceFile sourceFile) { } @Override - public Stream<PlainText> parseInputs(Iterable<Input> sources, @Nullable Path relativeTo, - ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sources, @Nullable Path relativeTo, + ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); - return StreamSupport.stream(sources.spliterator(), false) - .map(source -> { - Path path = source.getRelativePath(relativeTo); - try { - EncodingDetectingInputStream is = source.getSource(ctx); - String sourceStr = is.readFully(); - PlainText plainText = new PlainText(randomId(), - path, - Markers.EMPTY, - is.getCharset().name(), - is.isCharsetBomMarked(), - source.getFileAttributes(), - null, - sourceStr, - null); - parsingListener.parsed(source, plainText); - return plainText; - } catch (Throwable t) { - ParsingExecutionContextView.view(ctx).parseFailure(source, relativeTo, this, t); - ctx.getOnError().accept(t); - } - return null; - }) - .filter(Objects::nonNull); + return StreamSupport.stream(sources.spliterator(), false).map(source -> { + Path path = source.getRelativePath(relativeTo); + try { + EncodingDetectingInputStream is = source.getSource(ctx); + String sourceStr = is.readFully(); + PlainText plainText = new PlainText( + randomId(), + path, + Markers.EMPTY, + is.getCharset().name(), + is.isCharsetBomMarked(), + source.getFileAttributes(), + null, + sourceStr, + null + ); + parsingListener.parsed(source, plainText); + return plainText; + } catch (Throwable t) { + ctx.getOnError().accept(t); + return ParseError.build(this, source, relativeTo, ctx, t); + } + }); } @Override @@ -108,7 +107,7 @@ public Builder() { } @Override - public Parser<?> build() { + public PlainTextParser build() { return new PlainTextParser(); } diff --git a/rewrite-core/src/main/java/org/openrewrite/tree/ParsingExecutionContextView.java b/rewrite-core/src/main/java/org/openrewrite/tree/ParsingExecutionContextView.java index 3c65d5d5b98..9bc680ada98 100644 --- a/rewrite-core/src/main/java/org/openrewrite/tree/ParsingExecutionContextView.java +++ b/rewrite-core/src/main/java/org/openrewrite/tree/ParsingExecutionContextView.java @@ -17,24 +17,15 @@ import org.openrewrite.DelegatingExecutionContext; import org.openrewrite.ExecutionContext; -import org.openrewrite.ParseExceptionResult; -import org.openrewrite.Parser; import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.text.PlainText; import java.nio.charset.Charset; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; public class ParsingExecutionContextView extends DelegatingExecutionContext { private static final String PARSING_LISTENER = "org.openrewrite.core.parsingListener"; private static final String CHARSET = "org.openrewrite.parser.charset"; - private static final String PARSING_FAILURES = "org.openrewrite.core.parsingFailures"; - public ParsingExecutionContextView(ExecutionContext delegate) { super(delegate); } @@ -55,31 +46,6 @@ public ParsingEventListener getParsingListener() { return getMessage(PARSING_LISTENER, ParsingEventListener.NOOP); } - public ParsingExecutionContextView parseFailure(Parser.Input input, @Nullable Path relativeTo, Parser<?> parser, Throwable t) { - PlainText pt = PlainText.builder() - .sourcePath(input.getRelativePath(relativeTo)) - .text(input.getSource(this).readFully()) - .build(); - return parseFailure(pt, parser, t); - } - - public ParsingExecutionContextView parseFailure(PlainText raw, Parser<?> parser, Throwable t) { - putMessageInCollection(PARSING_FAILURES, - raw.withMarkers(raw.getMarkers().addIfAbsent(ParseExceptionResult.build(parser, t))), - ArrayList::new); - return this; - } - - @SuppressWarnings("unused") - public List<PlainText> getParseFailures() { - return getMessage(PARSING_FAILURES, Collections.emptyList()); - } - - @SuppressWarnings("unused") - public List<PlainText> pollParseFailures() { - return pollMessage(PARSING_FAILURES, Collections.emptyList()); - } - public ParsingExecutionContextView setCharset(@Nullable Charset charset) { putMessage(CHARSET, charset); return this; diff --git a/rewrite-core/src/test/java/org/openrewrite/quark/QuarkParserTest.java b/rewrite-core/src/test/java/org/openrewrite/quark/QuarkParserTest.java index 0cbd60ffcd8..9f67ca42737 100644 --- a/rewrite-core/src/test/java/org/openrewrite/quark/QuarkParserTest.java +++ b/rewrite-core/src/test/java/org/openrewrite/quark/QuarkParserTest.java @@ -44,9 +44,9 @@ void allOthers() { rewriteRun( spec -> spec.beforeRecipe(sources -> { try { - List<Quark> quarks = QuarkParser.parseAllOtherFiles(Paths.get("../"), sources); + List<SourceFile> quarks = QuarkParser.parseAllOtherFiles(Paths.get("../"), sources).toList(); assertThat(quarks).isNotEmpty(); - assertThat(quarks.stream().map(Quark::getSourcePath)) + assertThat(quarks.stream().map(SourceFile::getSourcePath)) .doesNotContain(Paths.get("build.gradle.kts")); } catch (IOException e) { throw new RuntimeException(e); diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependencyVisitor.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependencyVisitor.java index 4634181712c..a494fc7e882 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependencyVisitor.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependencyVisitor.java @@ -107,6 +107,7 @@ public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionCon if (dependenciesBlockMissing) { Statement dependenciesInvocation = GRADLE_PARSER.parse("dependencies {}") .findFirst() + .map(G.CompilationUnit.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as Gradle")) .getStatements().get(0); dependenciesInvocation = autoFormat(dependenciesInvocation, ctx, new Cursor(getCursor(), cu)); @@ -261,6 +262,7 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu } J.MethodInvocation addDependencyInvocation = requireNonNull((J.MethodInvocation) ((J.Return) (((J.Block) ((J.Lambda) ((J.MethodInvocation) GRADLE_PARSER.parse(codeTemplate) .findFirst() + .map(G.CompilationUnit.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as Gradle")) .getStatements().get(0)).getArguments().get(0)).getBody()).getStatements().get(0))).getExpression()); addDependencyInvocation = autoFormat(addDependencyInvocation, ctx, new Cursor(getCursor(), body)); diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddProperty.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddProperty.java index db7c67d724e..dc022b10b25 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddProperty.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddProperty.java @@ -21,7 +21,6 @@ import org.openrewrite.internal.lang.Nullable; import org.openrewrite.properties.ChangePropertyValue; import org.openrewrite.properties.PropertiesParser; -import org.openrewrite.properties.tree.Properties; import java.nio.file.Paths; import java.util.Collection; @@ -87,7 +86,7 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { } @Override - public Collection<Properties.File> generate(NeedsProperty acc, ExecutionContext ctx) { + public Collection<? extends SourceFile> generate(NeedsProperty acc, ExecutionContext ctx) { if (!acc.hasGradleProperties) { return PropertiesParser.builder().build() .parseInputs(singletonList(Parser.Input.fromString(Paths.get("gradle.properties"), diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/GradleParser.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/GradleParser.java index c4517d64665..5af96a2260f 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/GradleParser.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/GradleParser.java @@ -18,6 +18,7 @@ import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.Parser; +import org.openrewrite.SourceFile; import org.openrewrite.gradle.internal.DefaultImportsCustomizer; import org.openrewrite.groovy.GroovyParser; import org.openrewrite.groovy.tree.G; @@ -31,7 +32,7 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -public class GradleParser implements Parser<G.CompilationUnit> { +public class GradleParser implements Parser { private final GroovyParser buildParser; private final GroovyParser settingsParser; @@ -54,7 +55,7 @@ private GradleParser(Builder builder) { } @Override - public Stream<G.CompilationUnit> parseInputs(Iterable<Input> sources, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sources, @Nullable Path relativeTo, ExecutionContext ctx) { return StreamSupport.stream(sources.spliterator(), false) .flatMap(source -> { if (source.getPath().endsWith("settings.gradle")) { diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddGradleEnterprise.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddGradleEnterprise.java index 8676c2f4263..0068c3992b3 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddGradleEnterprise.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddGradleEnterprise.java @@ -227,6 +227,7 @@ private J.MethodInvocation gradleEnterpriseDsl(String newVersion, VersionCompara G.CompilationUnit cu = GradleParser.builder().build() .parseInputs(singletonList( Parser.Input.fromString(Paths.get("settings.gradle"), ge.toString())), null, ctx) + .map(G.CompilationUnit.class::cast) .findFirst() .orElseThrow(() -> new IllegalArgumentException("Could not parse as Gradle")); diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddPluginVisitor.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddPluginVisitor.java index 5eb41316fc1..700eca3adac 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddPluginVisitor.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddPluginVisitor.java @@ -113,7 +113,8 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Integ ctx ) .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")) + .map(G.CompilationUnit.class::cast) + .orElseThrow(() -> new IllegalArgumentException("Could not parse")) .getStatements(); if (FindMethods.find(cu, "RewriteGradleProject plugins(..)").isEmpty() && FindMethods.find(cu, "RewriteSettings plugins(..)").isEmpty()) { diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddSettingsPluginRepository.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddSettingsPluginRepository.java index 691f18c6c69..f0c45f7dcc2 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddSettingsPluginRepository.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/AddSettingsPluginRepository.java @@ -132,6 +132,7 @@ private J.MethodInvocation generatePluginManagementBlock(ExecutionContext ctx) { } return (J.MethodInvocation) GradleParser.builder().build().parseInputs(Collections.singletonList(Parser.Input.fromString(Paths.get("settings.gradle"), code)), null, ctx) + .map(G.CompilationUnit.class::cast) .collect(Collectors.toList()).get(0).getStatements().get(0); } diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParser.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParser.java index 3d0d7a12e77..80ea716b18d 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParser.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParser.java @@ -18,7 +18,6 @@ import groovy.lang.GroovyClassLoader; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; -import lombok.Value; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.ModuleNode; import org.codehaus.groovy.control.*; @@ -26,10 +25,7 @@ import org.codehaus.groovy.control.messages.WarningMessage; import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor; import org.intellij.lang.annotations.Language; -import org.openrewrite.ExecutionContext; -import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.ParseWarning; -import org.openrewrite.Parser; +import org.openrewrite.*; import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.JavaParser; @@ -38,7 +34,10 @@ import org.openrewrite.style.NamedStyles; import org.openrewrite.tree.ParsingExecutionContextView; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; @@ -54,7 +53,7 @@ import static java.util.stream.Collectors.toList; @RequiredArgsConstructor(access = AccessLevel.PRIVATE) -public class GroovyParser implements Parser<G.CompilationUnit> { +public class GroovyParser implements Parser { @Nullable private final Collection<Path> classpath; @@ -64,7 +63,7 @@ public class GroovyParser implements Parser<G.CompilationUnit> { private final List<Consumer<CompilerConfiguration>> compilerCustomizers; @Override - public Stream<G.CompilationUnit> parse(@Language("groovy") String... sources) { + public Stream<SourceFile> parse(@Language("groovy") String... sources) { Pattern packagePattern = Pattern.compile("^package\\s+([^;]+);"); Pattern classPattern = Pattern.compile("(class|interface|enum)\\s*(<[^>]*>)?\\s+(\\w+)"); @@ -96,46 +95,7 @@ public Stream<G.CompilationUnit> parse(@Language("groovy") String... sources) { } @Override - public Stream<G.CompilationUnit> parseInputs(Iterable<Input> sources, @Nullable Path relativeTo, ExecutionContext ctx) { - ParsingExecutionContextView pctx = ParsingExecutionContextView.view(ctx); - return parseInputsToCompilerAst(sources, relativeTo, pctx) - .map(entry -> { - CompiledGroovySource compiled = entry.getCompiledGroovySource(); - List<ParseWarning> warnings = entry.getWarnings(); - try { - GroovyParserVisitor mappingVisitor = new GroovyParserVisitor( - compiled.getInput().getRelativePath(relativeTo), - compiled.getInput().getFileAttributes(), - compiled.getInput().getSource(ctx), - typeCache, - ctx - ); - G.CompilationUnit gcu = mappingVisitor.visit(compiled.getSourceUnit(), compiled.getModule()); - if (warnings.size() > 0) { - Markers m = gcu.getMarkers(); - for (ParseWarning warning : warnings) { - m = m.add(warning); - } - gcu = gcu.withMarkers(m); - } - pctx.getParsingListener().parsed(compiled.getInput(), gcu); - return gcu; - } catch (Throwable t) { - pctx.parseFailure(compiled.getInput(), relativeTo, this, t); - ctx.getOnError().accept(t); - } - return null; - }) - .filter(Objects::nonNull); - } - - @Value - static class Intermediate { - CompiledGroovySource compiledGroovySource; - List<ParseWarning> warnings; - } - - Stream<Intermediate> parseInputsToCompilerAst(Iterable<Input> sources, @Nullable Path relativeTo, ParsingExecutionContextView ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sources, @Nullable Path relativeTo, ExecutionContext ctx) { CompilerConfiguration configuration = new CompilerConfiguration(); configuration.setTolerance(Integer.MAX_VALUE); configuration.setWarningLevel(WarningMessage.NONE); @@ -152,6 +112,8 @@ Stream<Intermediate> parseInputsToCompilerAst(Iterable<Input> sources, @Nullable for (Consumer<CompilerConfiguration> compilerCustomizer : compilerCustomizers) { compilerCustomizer.accept(configuration); } + + ParsingExecutionContextView pctx = ParsingExecutionContextView.view(ctx); return StreamSupport.stream(sources.spliterator(), false) .map(input -> { ParseWarningCollector errorCollector = new ParseWarningCollector(configuration, this); @@ -178,10 +140,28 @@ Stream<Intermediate> parseInputsToCompilerAst(Iterable<Input> sources, @Nullable } } - return new Intermediate(new CompiledGroovySource(input, unit, ast), errorCollector.getWarningMarkers()); + CompiledGroovySource compiled = new CompiledGroovySource(input, unit, ast); + List<ParseWarning> warnings = errorCollector.getWarningMarkers(); + GroovyParserVisitor mappingVisitor = new GroovyParserVisitor( + compiled.getInput().getRelativePath(relativeTo), + compiled.getInput().getFileAttributes(), + compiled.getInput().getSource(ctx), + typeCache, + ctx + ); + G.CompilationUnit gcu = mappingVisitor.visit(compiled.getSourceUnit(), compiled.getModule()); + if (warnings.size() > 0) { + Markers m = gcu.getMarkers(); + for (ParseWarning warning : warnings) { + m = m.add(warning); + } + gcu = gcu.withMarkers(m); + } + pctx.getParsingListener().parsed(compiled.getInput(), gcu); + return gcu; } catch (Throwable t) { - ctx.parseFailure(input, relativeTo, this, t); ctx.getOnError().accept(t); + return ParseError.build(this, input, relativeTo, ctx, t); } finally { if (logCompilationWarningsAndErrors && (errorCollector.hasErrors() || errorCollector.hasWarnings())) { try (StringWriter sw = new StringWriter(); @@ -193,7 +173,6 @@ Stream<Intermediate> parseInputsToCompilerAst(Iterable<Input> sources, @Nullable } } } - return null; }); } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/GroovyTypeMappingTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/GroovyTypeMappingTest.java index f7d398f5b89..cd634d65a5a 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/GroovyTypeMappingTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/GroovyTypeMappingTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.StringUtils; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.JavaTypeMappingTest; @@ -47,6 +48,7 @@ public JavaType.Parameterized goatType() { .build() .parse(new InMemoryExecutionContext(), goat) .findFirst() + .map(G.CompilationUnit.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")) .getClasses() .get(0) @@ -64,6 +66,7 @@ void noDuplicateSignatures() { """ ) .findFirst() + .map(G.CompilationUnit.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")) .getStatements() .get(0); diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/GroovyTypeSignatureBuilderTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/GroovyTypeSignatureBuilderTest.java deleted file mode 100644 index a41eaf0a97c..00000000000 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/GroovyTypeSignatureBuilderTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2021 the original author or authors. - * <p> - * 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 - * <p> - * https://www.apache.org/licenses/LICENSE-2.0 - * <p> - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.openrewrite.groovy; - -import org.codehaus.groovy.ast.GenericsType; -import org.codehaus.groovy.ast.InnerClassNode; -import org.junit.jupiter.api.Disabled; -import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.Parser; -import org.openrewrite.internal.StringUtils; -import org.openrewrite.java.JavaTypeSignatureBuilderTest; -import org.openrewrite.tree.ParsingExecutionContextView; - -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; -import java.util.Iterator; - -import static java.util.Collections.singletonList; - -@Disabled -public class GroovyTypeSignatureBuilderTest implements JavaTypeSignatureBuilderTest { - private static final String goat = StringUtils.readFully(GroovyTypeSignatureBuilderTest.class.getResourceAsStream("/GroovyTypeGoat.groovy")); - - private static final CompiledGroovySource cu = GroovyParser.builder() - .logCompilationWarningsAndErrors(true) - .build() - .parseInputsToCompilerAst( - singletonList(new Parser.Input(Paths.get("GroovyTypeGoat.groovy"), () -> new ByteArrayInputStream(goat.getBytes(StandardCharsets.UTF_8)))), - null, - new ParsingExecutionContextView(new InMemoryExecutionContext(Throwable::printStackTrace))) - .map(GroovyParser.Intermediate::getCompiledGroovySource) - .iterator() - .next(); - - @Override - public String fieldSignature(String field) { - return signatureBuilder().variableSignature(cu.getModule().getClasses().get(0).getDeclaredField(field)); - } - - @Override - public String methodSignature(String methodName) { - return signatureBuilder().methodSignature(cu.getModule().getClasses().get(0).getDeclaredMethods(methodName).get(0)); - } - - @Override - public String constructorSignature() { - return signatureBuilder().methodSignature(cu.getModule().getClasses().get(0).getDeclaredConstructors().get(0)); - } - - @Override - public Object firstMethodParameter(String methodName) { - return cu.getModule().getClasses().get(0).getDeclaredMethods(methodName).get(0).getParameters()[0].getType(); - } - - @Override - public GenericsType lastClassTypeParameter() { - return cu.getModule().getClasses().get(0).getGenericsTypes()[1]; - } - - @Override - public GroovyAstTypeSignatureBuilder signatureBuilder() { - return new GroovyAstTypeSignatureBuilder(); - } - - @Override - public Object innerClassSignature(String innerClassSimpleName) { - Iterator<InnerClassNode> innerClasses = cu.getModule().getClasses().get(0).getInnerClasses(); - while(innerClasses.hasNext()) { - InnerClassNode clazz = innerClasses.next(); - if(clazz.getNameWithoutPackage().equals(innerClassSimpleName)) { - return clazz.getGenericsTypes()[0]; - } - } - throw new IllegalArgumentException("Unable to find inner class of name " + innerClassSimpleName); - } -} diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclParser.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclParser.java index b9b244ebb46..fafcf80c508 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclParser.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclParser.java @@ -15,17 +15,16 @@ */ package org.openrewrite.hcl; -import io.micrometer.core.instrument.Metrics; -import io.micrometer.core.instrument.Timer; import org.antlr.v4.runtime.*; import org.openrewrite.ExecutionContext; +import org.openrewrite.ParseError; import org.openrewrite.Parser; +import org.openrewrite.SourceFile; import org.openrewrite.hcl.internal.HclParserVisitor; import org.openrewrite.hcl.internal.grammar.HCLLexer; import org.openrewrite.hcl.internal.grammar.HCLParser; import org.openrewrite.hcl.tree.Hcl; import org.openrewrite.internal.EncodingDetectingInputStream; -import org.openrewrite.internal.MetricsHelper; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.marker.Markers; import org.openrewrite.style.NamedStyles; @@ -35,10 +34,9 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.stream.Stream; -public class HclParser implements Parser<Hcl.ConfigFile> { +public class HclParser implements Parser { private final List<NamedStyles> styles; private HclParser(List<NamedStyles> styles) { @@ -46,47 +44,38 @@ private HclParser(List<NamedStyles> styles) { } @Override - public Stream<Hcl.ConfigFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); - return acceptedInputs(sourceFiles).stream() - .map(sourceFile -> { - Timer.Builder timer = Timer.builder("rewrite.parse") - .description("The time spent parsing an HCL file") - .tag("file.type", "HCL"); - Timer.Sample sample = Timer.start(); - try { - EncodingDetectingInputStream is = sourceFile.getSource(ctx); - String sourceStr = is.readFully(); - - HCLLexer lexer = new HCLLexer(CharStreams.fromString(sourceStr)); - lexer.removeErrorListeners(); - lexer.addErrorListener(new ForwardingErrorListener(sourceFile.getPath(), ctx)); - - HCLParser parser = new HCLParser(new CommonTokenStream(lexer)); - parser.removeErrorListeners(); - parser.addErrorListener(new ForwardingErrorListener(sourceFile.getPath(), ctx)); - - Hcl.ConfigFile configFile = (Hcl.ConfigFile) new HclParserVisitor( - sourceFile.getRelativePath(relativeTo), - sourceStr, - is.getCharset(), - is.isCharsetBomMarked(), - sourceFile.getFileAttributes() - ).visitConfigFile(parser.configFile()); - - configFile = configFile.withMarkers(Markers.build(styles)); - - sample.stop(MetricsHelper.successTags(timer).register(Metrics.globalRegistry)); - parsingListener.parsed(sourceFile, configFile); - return configFile; - } catch (Throwable t) { - sample.stop(MetricsHelper.errorTags(timer, t).register(Metrics.globalRegistry)); - ParsingExecutionContextView.view(ctx).parseFailure(sourceFile, relativeTo, this, t); - ctx.getOnError().accept(t); - return null; - } - }) - .filter(Objects::nonNull); + return acceptedInputs(sourceFiles).map(sourceFile -> { + try { + EncodingDetectingInputStream is = sourceFile.getSource(ctx); + String sourceStr = is.readFully(); + + HCLLexer lexer = new HCLLexer(CharStreams.fromString(sourceStr)); + lexer.removeErrorListeners(); + lexer.addErrorListener(new ForwardingErrorListener(sourceFile.getPath(), ctx)); + + HCLParser parser = new HCLParser(new CommonTokenStream(lexer)); + parser.removeErrorListeners(); + parser.addErrorListener(new ForwardingErrorListener(sourceFile.getPath(), ctx)); + + Hcl.ConfigFile configFile = (Hcl.ConfigFile) new HclParserVisitor( + sourceFile.getRelativePath(relativeTo), + sourceStr, + is.getCharset(), + is.isCharsetBomMarked(), + sourceFile.getFileAttributes() + ).visitConfigFile(parser.configFile()); + + configFile = configFile.withMarkers(Markers.build(styles)); + + parsingListener.parsed(sourceFile, configFile); + return (SourceFile) configFile; + } catch (Throwable t) { + ctx.getOnError().accept(t); + return ParseError.build(this, sourceFile, relativeTo, ctx, t); + } + }); } @Override diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/MoveContentToFile.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/MoveContentToFile.java index eb7b340fbd4..bc3d3f28d47 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/MoveContentToFile.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/MoveContentToFile.java @@ -104,6 +104,7 @@ public Collection<Hcl.ConfigFile> generate(Scanned acc, ExecutionContext ctx) { } Hcl.ConfigFile configFile = HclParser.builder().build().parse("") .findFirst() + .map(Hcl.ConfigFile.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as HCL")); configFile = configFile.withBody(Collections.singletonList(acc.toMove.withPrefix(Space.EMPTY))) .withSourcePath(Paths.get(destinationPath)); diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/template/HclTemplateParser.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/template/HclTemplateParser.java index c8402c2b592..bc8cee6b8d5 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/template/HclTemplateParser.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/template/HclTemplateParser.java @@ -72,6 +72,7 @@ public Expression parseExpression(String template) { private Hcl.ConfigFile compileTemplate(String stub) { return parser.parse(stub) .findFirst() + .map(Hcl.ConfigFile.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as HCL")); } @@ -86,7 +87,7 @@ private <H extends Hcl> List<H> cache(String stub, Supplier<List<? extends Hcl>> List<H> hs; synchronized (templateCacheLock) { hs = (List<H>) templateCache.get(stub); - if(hs == null) { + if (hs == null) { hs = (List<H>) ifAbsent.get(); templateCache.put(stub, hs); } diff --git a/rewrite-hcl/src/test/java/org/openrewrite/hcl/JsonPathMatcherTest.java b/rewrite-hcl/src/test/java/org/openrewrite/hcl/JsonPathMatcherTest.java index 0cd8f971135..acb800071f2 100644 --- a/rewrite-hcl/src/test/java/org/openrewrite/hcl/JsonPathMatcherTest.java +++ b/rewrite-hcl/src/test/java/org/openrewrite/hcl/JsonPathMatcherTest.java @@ -251,7 +251,9 @@ private void assertMatched(List<String> before, List<String> after, String jsonP private List<String> visit(List<String> before, String jsonPath, boolean printMatches) { var ctx = new InMemoryExecutionContext(); - var documents = HclParser.builder().build().parse(ctx, before.toArray(new String[0])).toList(); + var documents = HclParser.builder().build().parse(ctx, before.toArray(new String[0])) + .map(Hcl.ConfigFile.class::cast) + .toList(); if (documents.isEmpty()) { return emptyList(); } diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/Java11Parser.java b/rewrite-java-11/src/main/java/org/openrewrite/java/Java11Parser.java index 818bf6193c9..22b4b675d20 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/Java11Parser.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/Java11Parser.java @@ -16,6 +16,7 @@ package org.openrewrite.java; import org.openrewrite.ExecutionContext; +import org.openrewrite.SourceFile; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.tree.J; @@ -35,7 +36,7 @@ public class Java11Parser implements JavaParser { } @Override - public Stream<J.CompilationUnit> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { return delegate.parseInputs(sourceFiles, relativeTo, ctx); } diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java index a849e2a3ad0..cc764c4ac37 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java @@ -29,6 +29,8 @@ import org.objectweb.asm.Opcodes; import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.ParseError; +import org.openrewrite.SourceFile; import org.openrewrite.internal.MetricsHelper; import org.openrewrite.internal.StringUtils; import org.openrewrite.internal.lang.NonNullApi; @@ -147,47 +149,32 @@ public static Builder builder() { } @Override - public Stream<J.CompilationUnit> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); LinkedHashMap<Input, JCTree.JCCompilationUnit> cus = parseInputsToCompilerAst(sourceFiles, ctx); - return cus.entrySet().stream() - .map(cuByPath -> { - Timer.Sample sample = Timer.start(); - Input input = cuByPath.getKey(); - try { - ReloadableJava11ParserVisitor parser = new ReloadableJava11ParserVisitor( - input.getRelativePath(relativeTo), - input.getFileAttributes(), - input.getSource(ctx), - styles, - typeCache, - ctx, - context - ); - - J.CompilationUnit cu = (J.CompilationUnit) parser.scan(cuByPath.getValue(), Space.EMPTY); - sample.stop(MetricsHelper.successTags( - Timer.builder("rewrite.parse") - .description("The time spent mapping the OpenJDK AST to Rewrite's AST") - .tag("file.type", "Java") - .tag("step", "(3) Map to Rewrite AST")) - .register(Metrics.globalRegistry)); - parsingListener.parsed(input, cu); - return cu; - } catch (Throwable t) { - sample.stop(MetricsHelper.errorTags( - Timer.builder("rewrite.parse") - .description("The time spent mapping the OpenJDK AST to Rewrite's AST") - .tag("file.type", "Java") - .tag("step", "(3) Map to Rewrite AST"), t) - .register(Metrics.globalRegistry)); - ParsingExecutionContextView.view(ctx).parseFailure(input, relativeTo, this, t); - ctx.getOnError().accept(t); - return null; - } - }) - .filter(Objects::nonNull); + return cus.entrySet().stream().map(cuByPath -> { + Input input = cuByPath.getKey(); + try { + ReloadableJava11ParserVisitor parser = new ReloadableJava11ParserVisitor( + input.getRelativePath(relativeTo), + input.getFileAttributes(), + input.getSource(ctx), + styles, + typeCache, + ctx, + context + ); + + J.CompilationUnit cu = (J.CompilationUnit) parser.scan(cuByPath.getValue(), Space.EMPTY); + cuByPath.setValue(null); // allow memory used by this JCCompilationUnit to be released + parsingListener.parsed(input, cu); + return cu; + } catch (Throwable t) { + ctx.getOnError().accept(t); + return ParseError.build(this, input, relativeTo, ctx, t); + } + }); } LinkedHashMap<Input, JCTree.JCCompilationUnit> parseInputsToCompilerAst(Iterable<Input> sourceFiles, ExecutionContext ctx) { @@ -204,27 +191,20 @@ LinkedHashMap<Input, JCTree.JCCompilationUnit> parseInputsToCompilerAst(Iterable } LinkedHashMap<Input, JCTree.JCCompilationUnit> cus = new LinkedHashMap<>(); - for (Input input1 : acceptedInputs(sourceFiles)) { - cus.put(input1, MetricsHelper.successTags( - Timer.builder("rewrite.parse") - .description("The time spent by the JDK in parsing and tokenizing the source file") - .tag("file.type", "Java") - .tag("step", "(1) JDK parsing")) - .register(Metrics.globalRegistry) - .record(() -> { - try { - return compiler.parse(new ReloadableJava11ParserInputFileObject(input1, ctx)); - } catch (IllegalStateException e) { - if ("endPosTable already set".equals(e.getMessage())) { - throw new IllegalStateException( - "Call reset() on JavaParser before parsing another set of source files that " + - "have some of the same fully qualified names. Source file [" + - input1.getPath() + "]\n[\n" + StringUtils.readFully(input1.getSource(ctx), getCharset(ctx)) + "\n]", e); - } - throw e; - } - })); - } + acceptedInputs(sourceFiles).forEach(input1 -> { + try { + JCTree.JCCompilationUnit jcCompilationUnit = compiler.parse(new ReloadableJava11ParserInputFileObject(input1, ctx)); + cus.put(input1, jcCompilationUnit); + } catch (IllegalStateException e) { + if ("endPosTable already set".equals(e.getMessage())) { + throw new IllegalStateException( + "Call reset() on JavaParser before parsing another set of source files that " + + "have some of the same fully qualified names. Source file [" + + input1.getPath() + "]\n[\n" + StringUtils.readFully(input1.getSource(ctx), getCharset(ctx)) + "\n]", e); + } + throw e; + } + }); try { initModules(cus.values()); @@ -316,12 +296,7 @@ public void reset() { } public void reset(Collection<URI> uris) { - for (Iterator<JavaFileObject> itr = sourceMap.keySet().iterator(); itr.hasNext();) { - JavaFileObject f = itr.next(); - if (uris.contains(f.toUri())) { - itr.remove(); - } - } + sourceMap.keySet().removeIf(f -> uris.contains(f.toUri())); } } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/Java17Parser.java b/rewrite-java-17/src/main/java/org/openrewrite/java/Java17Parser.java index c519690d0fe..5837e33ad4d 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/Java17Parser.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/Java17Parser.java @@ -16,9 +16,9 @@ package org.openrewrite.java; import org.openrewrite.ExecutionContext; +import org.openrewrite.SourceFile; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.internal.JavaTypeCache; -import org.openrewrite.java.tree.J; import java.lang.reflect.Constructor; import java.net.URI; @@ -35,7 +35,7 @@ public class Java17Parser implements JavaParser { } @Override - public Stream<J.CompilationUnit> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { return delegate.parseInputs(sourceFiles, relativeTo, ctx); } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17Parser.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17Parser.java index 2fa2efdc100..e5fcfcc12d2 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17Parser.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17Parser.java @@ -15,21 +15,23 @@ */ package org.openrewrite.java.isolated; -import com.sun.tools.javac.comp.*; +import com.sun.tools.javac.comp.Annotate; +import com.sun.tools.javac.comp.Check; +import com.sun.tools.javac.comp.Enter; +import com.sun.tools.javac.comp.Modules; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Options; -import io.micrometer.core.instrument.Metrics; -import io.micrometer.core.instrument.Timer; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Opcodes; import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.internal.MetricsHelper; +import org.openrewrite.ParseError; +import org.openrewrite.SourceFile; import org.openrewrite.internal.StringUtils; import org.openrewrite.internal.lang.NonNullApi; import org.openrewrite.internal.lang.Nullable; @@ -104,9 +106,6 @@ private ReloadableJava17Parser(boolean logCompilationWarningsAndErrors, Options.instance(context).put("-g", "-g"); Options.instance(context).put("-proc", "none"); - // MUST be created ahead of compiler construction - new TimedTodo(context); - // MUST be created (registered with the context) after pfm and compilerLog compiler = new JavaCompiler(context); @@ -147,46 +146,31 @@ public static Builder builder() { } @Override - public Stream<J.CompilationUnit> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); LinkedHashMap<Input, JCTree.JCCompilationUnit> cus = parseInputsToCompilerAst(sourceFiles, ctx); - return cus.entrySet().stream() - .map(cuByPath -> { - Timer.Sample sample = Timer.start(); - Input input = cuByPath.getKey(); - try { - ReloadableJava17ParserVisitor parser = new ReloadableJava17ParserVisitor( - input.getRelativePath(relativeTo), - input.getFileAttributes(), - input.getSource(ctx), - styles, - typeCache, - ctx, - context - ); - - J.CompilationUnit cu = (J.CompilationUnit) parser.scan(cuByPath.getValue(), Space.EMPTY); - sample.stop(MetricsHelper.successTags( - Timer.builder("rewrite.parse") - .description("The time spent mapping the OpenJDK AST to Rewrite's AST") - .tag("file.type", "Java") - .tag("step", "(3) Map to Rewrite AST")) - .register(Metrics.globalRegistry)); - parsingListener.parsed(input, cu); - return cu; - } catch (Throwable t) { - sample.stop(MetricsHelper.errorTags( - Timer.builder("rewrite.parse") - .description("The time spent mapping the OpenJDK AST to Rewrite's AST") - .tag("file.type", "Java") - .tag("step", "(3) Map to Rewrite AST"), t) - .register(Metrics.globalRegistry)); - ParsingExecutionContextView.view(ctx).parseFailure(input, relativeTo, this, t); - ctx.getOnError().accept(t); - return null; - } - }) - .filter(Objects::nonNull); + return cus.entrySet().stream().map(cuByPath -> { + Input input = cuByPath.getKey(); + try { + ReloadableJava17ParserVisitor parser = new ReloadableJava17ParserVisitor( + input.getRelativePath(relativeTo), + input.getFileAttributes(), + input.getSource(ctx), + styles, + typeCache, + ctx, + context + ); + + J.CompilationUnit cu = (J.CompilationUnit) parser.scan(cuByPath.getValue(), Space.EMPTY); + cuByPath.setValue(null); // allow memory used by this JCCompilationUnit to be released + parsingListener.parsed(input, cu); + return cu; + } catch (Throwable t) { + ctx.getOnError().accept(t); + return ParseError.build(this, input, relativeTo, ctx, t); + } + }); } LinkedHashMap<Input, JCTree.JCCompilationUnit> parseInputsToCompilerAst(Iterable<Input> sourceFiles, ExecutionContext ctx) { @@ -203,27 +187,20 @@ LinkedHashMap<Input, JCTree.JCCompilationUnit> parseInputsToCompilerAst(Iterable } LinkedHashMap<Input, JCTree.JCCompilationUnit> cus = new LinkedHashMap<>(); - for (Input input1 : acceptedInputs(sourceFiles)) { - cus.put(input1, MetricsHelper.successTags( - Timer.builder("rewrite.parse") - .description("The time spent by the JDK in parsing and tokenizing the source file") - .tag("file.type", "Java") - .tag("step", "(1) JDK parsing")) - .register(Metrics.globalRegistry) - .record(() -> { - try { - return compiler.parse(new ReloadableJava17ParserInputFileObject(input1, ctx)); - } catch (IllegalStateException e) { - if ("endPosTable already set".equals(e.getMessage())) { - throw new IllegalStateException( - "Call reset() on JavaParser before parsing another set of source files that " + - "have some of the same fully qualified names. Source file [" + - input1.getPath() + "]\n[\n" + StringUtils.readFully(input1.getSource(ctx), getCharset(ctx)) + "\n]", e); - } - throw e; - } - })); - } + acceptedInputs(sourceFiles).forEach(input1 -> { + try { + JCTree.JCCompilationUnit jcCompilationUnit = compiler.parse(new ReloadableJava17ParserInputFileObject(input1, ctx)); + cus.put(input1, jcCompilationUnit); + } catch (IllegalStateException e) { + if ("endPosTable already set".equals(e.getMessage())) { + throw new IllegalStateException( + "Call reset() on JavaParser before parsing another set of source files that " + + "have some of the same fully qualified names. Source file [" + + input1.getPath() + "]\n[\n" + StringUtils.readFully(input1.getSource(ctx), getCharset(ctx)) + "\n]", e); + } + throw e; + } + }); try { initModules(cus.values()); @@ -237,9 +214,10 @@ LinkedHashMap<Input, JCTree.JCCompilationUnit> parseInputsToCompilerAst(Iterable } compiler.attribute(compiler.todo); - } catch (Throwable t) { + } catch ( + Throwable t) { // when symbol entering fails on problems like missing types, attribution can often times proceed - // unhindered, but it sometimes cannot (so attribution is always a BEST EFFORT in the presence of errors) + // unhindered, but it sometimes cannot (so attribution is always best-effort in the presence of errors) ctx.getOnError().accept(new JavaParsingException("Failed symbol entering or attribution", t)); } return cus; @@ -319,34 +297,6 @@ public void reset(Collection<URI> uris) { } } - private static class TimedTodo extends Todo { - @Nullable - private Timer.Sample sample; - - private TimedTodo(Context context) { - super(context); - } - - @Override - public boolean isEmpty() { - if (sample != null) { - sample.stop(MetricsHelper.successTags( - Timer.builder("rewrite.parse") - .description("The time spent by the JDK in type attributing the source file") - .tag("file.type", "Java") - .tag("step", "(2) Type attribution")) - .register(Metrics.globalRegistry)); - } - return super.isEmpty(); - } - - @Override - public Env<AttrContext> remove() { - this.sample = Timer.start(); - return super.remove(); - } - } - public static class Builder extends JavaParser.Builder<ReloadableJava17Parser, Builder> { @Override public ReloadableJava17Parser build() { diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/Java8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/Java8Parser.java index 4244ac708a2..81c9abb13c8 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/Java8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/Java8Parser.java @@ -16,9 +16,9 @@ package org.openrewrite.java; import org.openrewrite.ExecutionContext; +import org.openrewrite.SourceFile; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.internal.JavaTypeCache; -import org.openrewrite.java.tree.J; import java.io.File; import java.lang.reflect.Constructor; @@ -40,7 +40,7 @@ public class Java8Parser implements JavaParser { } @Override - public Stream<J.CompilationUnit> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { return delegate.parseInputs(sourceFiles, relativeTo, ctx); } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java index c4aacd41611..b6fbea7d2ef 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java @@ -29,6 +29,8 @@ import org.objectweb.asm.Opcodes; import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.ParseError; +import org.openrewrite.SourceFile; import org.openrewrite.internal.MetricsHelper; import org.openrewrite.internal.StringUtils; import org.openrewrite.internal.lang.Nullable; @@ -134,7 +136,7 @@ public void close() { } @Override - public Stream<J.CompilationUnit> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); if (classpath != null) { // override classpath @@ -149,28 +151,22 @@ public Stream<J.CompilationUnit> parseInputs(Iterable<Input> sourceFiles, @Nulla } } - @SuppressWarnings("ConstantConditions") LinkedHashMap<Input, JCTree.JCCompilationUnit> cus = acceptedInputs(sourceFiles).stream() + @SuppressWarnings("ConstantConditions") LinkedHashMap<Input, JCTree.JCCompilationUnit> cus = acceptedInputs(sourceFiles) .collect(Collectors.toMap( Function.identity(), - input -> MetricsHelper.successTags( - Timer.builder("rewrite.parse") - .description("The time spent by the JDK in parsing and tokenizing the source file") - .tag("file.type", "Java") - .tag("step", "(1) JDK parsing")) - .register(Metrics.globalRegistry) - .record(() -> { - try { - return compiler.parse(new Java8ParserInputFileObject(input, ctx)); - } catch (IllegalStateException e) { - if ("endPosTable already set".equals(e.getMessage())) { - throw new IllegalStateException( - "Call reset() on JavaParser before parsing another set of source files that " + - "have some of the same fully qualified names. Source file [" + - input.getPath() + "]\n[\n" + StringUtils.readFully(input.getSource(ctx), getCharset(ctx)) + "\n]", e); - } - throw e; - } - }), + input -> { + try { + return compiler.parse(new Java8ParserInputFileObject(input, ctx)); + } catch (IllegalStateException e) { + if ("endPosTable already set".equals(e.getMessage())) { + throw new IllegalStateException( + "Call reset() on JavaParser before parsing another set of source files that " + + "have some of the same fully qualified names. Source file [" + + input.getPath() + "]\n[\n" + StringUtils.readFully(input.getSource(ctx), getCharset(ctx)) + "\n]", e); + } + throw e; + } + }, (e2, e1) -> e1, LinkedHashMap::new)); try { @@ -182,41 +178,26 @@ public Stream<J.CompilationUnit> parseInputs(Iterable<Input> sourceFiles, @Nulla ctx.getOnError().accept(new JavaParsingException("Failed symbol entering or attribution", t)); } - return cus.entrySet().stream() - .map(cuByPath -> { - Timer.Sample sample = Timer.start(); - Input input = cuByPath.getKey(); - try { - ReloadableJava8ParserVisitor parser = new ReloadableJava8ParserVisitor( - input.getRelativePath(relativeTo), - input.getFileAttributes(), - input.getSource(ctx), - styles, - typeCache, - ctx, - context); - J.CompilationUnit cu = (J.CompilationUnit) parser.scan(cuByPath.getValue(), Space.EMPTY); - sample.stop(MetricsHelper.successTags( - Timer.builder("rewrite.parse") - .description("The time spent mapping the OpenJDK AST to Rewrite's AST") - .tag("file.type", "Java") - .tag("step", "(3) Map to Rewrite AST")) - .register(Metrics.globalRegistry)); - parsingListener.parsed(input, cu); - return cu; - } catch (Throwable t) { - sample.stop(MetricsHelper.errorTags( - Timer.builder("rewrite.parse") - .description("The time spent mapping the OpenJDK AST to Rewrite's AST") - .tag("file.type", "Java") - .tag("step", "(3) Map to Rewrite AST"), t) - .register(Metrics.globalRegistry)); - ParsingExecutionContextView.view(ctx).parseFailure(input, relativeTo, this, t); - ctx.getOnError().accept(t); - return null; - } - }) - .filter(Objects::nonNull); + return cus.entrySet().stream().map(cuByPath -> { + Input input = cuByPath.getKey(); + try { + ReloadableJava8ParserVisitor parser = new ReloadableJava8ParserVisitor( + input.getRelativePath(relativeTo), + input.getFileAttributes(), + input.getSource(ctx), + styles, + typeCache, + ctx, + context); + J.CompilationUnit cu = (J.CompilationUnit) parser.scan(cuByPath.getValue(), Space.EMPTY); + cuByPath.setValue(null); // allow memory used by this JCCompilationUnit to be released + parsingListener.parsed(input, cu); + return (SourceFile) cu; + } catch (Throwable t) { + ctx.getOnError().accept(t); + return ParseError.build(this, input, relativeTo, ctx, t); + } + }); } @Override @@ -271,7 +252,7 @@ public void reset() { } public void reset(Collection<URI> uris) { - for (Iterator<JavaFileObject> itr = sourceMap.keySet().iterator(); itr.hasNext();) { + for (Iterator<JavaFileObject> itr = sourceMap.keySet().iterator(); itr.hasNext(); ) { JavaFileObject f = itr.next(); if (uris.contains(f.toUri())) { itr.remove(); diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/JavaParserTypeMappingTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/JavaParserTypeMappingTest.java index ac875b997f1..d5712c1a9dc 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/JavaParserTypeMappingTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/JavaParserTypeMappingTest.java @@ -43,6 +43,7 @@ public class JavaParserTypeMappingTest implements JavaTypeMappingTest, RewriteTe private final J.CompilationUnit goatCu = JavaParser.fromJavaVersion().build() .parse(goat) .findFirst() + .map(J.CompilationUnit.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); @Override diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java index 107f5896804..df35ab67a72 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java @@ -16,26 +16,18 @@ package org.openrewrite.java; import io.github.classgraph.ClassGraph; -import io.github.classgraph.Resource; -import io.github.classgraph.ResourceList; import io.github.classgraph.ScanResult; import org.intellij.lang.annotations.Language; -import org.intellij.lang.annotations.Language; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.Issue; +import org.openrewrite.SourceFile; import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaType; -import org.openrewrite.java.tree.TypeUtils; import org.openrewrite.test.RewriteTest; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; @@ -100,40 +92,6 @@ void dependenciesFromResources(@TempDir Path temp) { assertThat(JavaParser.dependenciesFromResources(ctx, "guava-31.0-jre")).isNotEmpty(); } - @Test - void resetParserTest() throws Exception { - JavaParser parser = JavaParser.fromJavaVersion().build(); - String source = """ - import java.util.List; - import java.util.ArrayList; - - class Something { - List<Integer> getList() { - System.out.println("hello"); - return new ArrayList<>(); - } - } - """; - List<J.CompilationUnit> cus = parser.parse(source).collect(Collectors.toList()); - - J.CompilationUnit c = cus.get(0); - J.MethodDeclaration m = c.getClasses().get(0).getBody().getStatements().stream().filter(J.MethodDeclaration.class::isInstance).map(J.MethodDeclaration.class::cast).findFirst().orElseThrow(); - JavaType.Method methodType = m.getMethodType(); - assertThat(TypeUtils.asFullyQualified(methodType.getReturnType()).getFullyQualifiedName()).isEqualTo("java.util.List"); - - parser.reset(cus.stream().map(cu -> cu.getSourcePath().toUri()).collect(Collectors.toList())); -// parser.reset(); - - cus = parser.parse(source).collect(Collectors.toList()); - assertThat(cus.size()).isEqualTo(1); - assertThat(cus.get(0).getClasses().size()).isEqualTo(1); - - c = cus.get(0); - m = c.getClasses().get(0).getBody().getStatements().stream().filter(J.MethodDeclaration.class::isInstance).map(J.MethodDeclaration.class::cast).findFirst().orElseThrow(); - methodType = m.getMethodType(); - assertThat(TypeUtils.asFullyQualified(methodType.getReturnType()).getFullyQualifiedName()).isEqualTo("java.util.List"); - } - @Test @Issue("https://github.com/openrewrite/rewrite/issues/3222") void parseFromByteArray() { @@ -163,8 +121,8 @@ public void methodA() {} public void methodB() {} } """; - List<J.CompilationUnit> compilationUnits = parser.parse(new InMemoryExecutionContext(Throwable::printStackTrace), source).toList(); - assertThat(compilationUnits).singleElement() + Stream<SourceFile> compilationUnits = parser.parse(new InMemoryExecutionContext(Throwable::printStackTrace), source); + assertThat(compilationUnits.map(J.CompilationUnit.class::cast)).singleElement() .satisfies(cu -> assertThat(cu.getClasses()).singleElement() .satisfies(cd -> assertThat(cd.getImplements()).satisfiesExactly( i -> assertThat(i.getType()).hasToString("example.InterfaceA"), diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/MethodMatcherTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/MethodMatcherTest.java index fdd5ee8512d..15979a2a0cd 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/MethodMatcherTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/MethodMatcherTest.java @@ -391,14 +391,17 @@ void matchUnknownTypesSingleWildcardArgument() { static J.MethodInvocation asMethodInvocation(String code) { var cu = JavaParser.fromJavaVersion().build().parse( - String.format(""" - class MyTest { - void test() { - %s - } - } - """, code) - ).findFirst().orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); + String.format(""" + class MyTest { + void test() { + %s + } + } + """, code) + ) + .findFirst() + .map(J.CompilationUnit.class::cast) + .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); var classDecl = cu.getClasses().get(0); J.MethodDeclaration testMethod = (J.MethodDeclaration) classDecl.getBody().getStatements().get(0); return (J.MethodInvocation) testMethod.getBody().getStatements().get(0); diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/TreeVisitorAdapterTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/TreeVisitorAdapterTest.java index c49f55a8616..9c27764bf18 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/TreeVisitorAdapterTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/TreeVisitorAdapterTest.java @@ -40,6 +40,7 @@ void adapter() { JavaVisitor<Integer> jv = TreeVisitorAdapter.adapt(new Adaptable(n), JavaVisitor.class); J.CompilationUnit cu = JavaParser.fromJavaVersion().build().parse("class Test {}") .findFirst() + .map(J.CompilationUnit.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); jv.visit(cu, 0); assertThat(n.get()).isEqualTo(4); @@ -69,6 +70,7 @@ public J preVisit(J tree, Integer integer) { ); J.CompilationUnit cu = JavaParser.fromJavaVersion().build().parse("class Test {}") .findFirst() + .map(J.CompilationUnit.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); jv.visit(cu, 0); assertThat(n.get()).isEqualTo( @@ -81,6 +83,7 @@ public J preVisit(J tree, Integer integer) { void findUncaught() { J.CompilationUnit cu = JavaParser.fromJavaVersion().build().parse("class Test {}") .findFirst() + .map(J.CompilationUnit.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); AtomicReference<RecipeRunException> e = new AtomicReference<>(); diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/internal/DefaultJavaTypeSignatureBuilderTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/internal/DefaultJavaTypeSignatureBuilderTest.java index 678dd7fbe5e..4fc32aa09f2 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/internal/DefaultJavaTypeSignatureBuilderTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/internal/DefaultJavaTypeSignatureBuilderTest.java @@ -32,62 +32,63 @@ class DefaultJavaTypeSignatureBuilderTest implements JavaTypeSignatureBuilderTes @Language("java") private final String goat = StringUtils.readFully( - requireNonNull(DefaultJavaTypeSignatureBuilderTest.class.getResourceAsStream("/JavaTypeGoat.java")), StandardCharsets.UTF_8); + requireNonNull(DefaultJavaTypeSignatureBuilderTest.class.getResourceAsStream("/JavaTypeGoat.java")), StandardCharsets.UTF_8); private final J.CompilationUnit goatCu = JavaParser.fromJavaVersion() - .build() - .parse(goat) + .build() + .parse(goat) .findFirst() + .map(J.CompilationUnit.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); private final JavaType.Parameterized goatCuType = requireNonNull(TypeUtils.asParameterized(goatCu - .getClasses() - .get(0) - .getType())); + .getClasses() + .get(0) + .getType())); @Override public String fieldSignature(String field) { return signatureBuilder().variableSignature(goatCuType.getType().getMembers().stream() - .filter(m -> m.getName().equals(field)) - .findAny() - .orElseThrow()); + .filter(m -> m.getName().equals(field)) + .findAny() + .orElseThrow()); } @Override public String methodSignature(String methodName) { return signatureBuilder().methodSignature(goatCuType.getType().getMethods().stream() - .filter(m -> m.getName().equals(methodName)) - .findAny() - .orElseThrow()); + .filter(m -> m.getName().equals(methodName)) + .findAny() + .orElseThrow()); } @Override public String constructorSignature() { return signatureBuilder().methodSignature(goatCuType.getType().getMethods().stream() - .filter(m -> m.getName().equals("<constructor>")) - .findAny() - .orElseThrow()); + .filter(m -> m.getName().equals("<constructor>")) + .findAny() + .orElseThrow()); } @Override public JavaType firstMethodParameter(String methodName) { return goatCuType.getType().getMethods().stream() - .filter(m -> m.getName().equals(methodName)) - .map(m -> m.getParameterTypes().get(0)) - .findAny() - .orElseThrow(); + .filter(m -> m.getName().equals(methodName)) + .map(m -> m.getParameterTypes().get(0)) + .findAny() + .orElseThrow(); } @Override public JavaType innerClassSignature(String innerClassSimpleName) { return requireNonNull(goatCu.getClasses().get(0).getBody().getStatements() - .stream() - .filter(it -> it instanceof J.ClassDeclaration) - .map(it -> (J.ClassDeclaration) it) - .filter(cd -> requireNonNull(cd.getType()).getFullyQualifiedName().endsWith("$" + innerClassSimpleName)) - .findAny() - .orElseThrow() - .getType()); + .stream() + .filter(it -> it instanceof J.ClassDeclaration) + .map(it -> (J.ClassDeclaration) it) + .filter(cd -> requireNonNull(cd.getType()).getFullyQualifiedName().endsWith("$" + innerClassSimpleName)) + .findAny() + .orElseThrow() + .getType()); } @Override diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/search/SemanticallyEqualTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/search/SemanticallyEqualTest.java index dd2ff360a72..13d22ad3289 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/search/SemanticallyEqualTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/search/SemanticallyEqualTest.java @@ -52,9 +52,9 @@ private void assertEqualToSelf(@Language("java") String a) { @SuppressWarnings("OptionalGetWithoutIsPresent") private void assertEqual(@Language("java") String a, @Language("java") String b) { - J.CompilationUnit cua = javaParser.parse(a).findFirst().get(); + J.CompilationUnit cua = (J.CompilationUnit) javaParser.parse(a).findFirst().get(); javaParser.reset(); - J.CompilationUnit cub = javaParser.parse(b).findFirst().get(); + J.CompilationUnit cub = (J.CompilationUnit) javaParser.parse(b).findFirst().get(); assertEqual(cua, cub); } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaParser.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaParser.java index 343f43d54d6..d228221047e 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaParser.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaParser.java @@ -23,6 +23,7 @@ import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.Parser; +import org.openrewrite.SourceFile; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.JavaSourceSet; @@ -48,7 +49,7 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; -public interface JavaParser extends Parser<J.CompilationUnit> { +public interface JavaParser extends Parser { /** * Set to <code>true</code> on an {@link ExecutionContext} supplied to parsing to skip generation of @@ -246,7 +247,7 @@ static List<Path> dependenciesFromResources(ExecutionContext ctx, String... arti } @Override - default Stream<J.CompilationUnit> parse(ExecutionContext ctx, @Language("java") String... sources) { + default Stream<SourceFile> parse(ExecutionContext ctx, @Language("java") String... sources) { return parseInputs( Arrays.stream(sources) .map(sourceFile -> new Input( @@ -260,7 +261,7 @@ default Stream<J.CompilationUnit> parse(ExecutionContext ctx, @Language("java") } @Override - default Stream<J.CompilationUnit> parse(@Language("java") String... sources) { + default Stream<SourceFile> parse(@Language("java") String... sources) { InMemoryExecutionContext ctx = new InMemoryExecutionContext(); return parse(ctx, sources); } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/PartProvider.java b/rewrite-java/src/main/java/org/openrewrite/java/PartProvider.java index d19294a59d2..77ff0948d6f 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/PartProvider.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/PartProvider.java @@ -17,6 +17,7 @@ import org.intellij.lang.annotations.Language; import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.SourceFile; import org.openrewrite.Tree; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.tree.J; @@ -55,7 +56,7 @@ public static <J2 extends J> J2 buildPart(@Language("java") String codeToProvide private static <J2 extends J> J2 buildPart(@Language("java") String codeToProvideAPart, Class<J2> expected, JavaParser parser) { - J.CompilationUnit cu = parser + SourceFile cu = parser .parse(codeToProvideAPart) .findFirst() .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ReplaceConstant.java b/rewrite-java/src/main/java/org/openrewrite/java/ReplaceConstant.java index 96a8e246dcf..2aeef773a18 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/ReplaceConstant.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/ReplaceConstant.java @@ -23,9 +23,6 @@ import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.TypeUtils; -import java.util.List; -import java.util.stream.Collectors; - @Value @EqualsAndHashCode(callSuper = false) public class ReplaceConstant extends Recipe { @@ -105,10 +102,12 @@ private boolean isVariableDeclaration() { private J.Literal buildLiteral() { if (literal == null) { JavaParser parser = JavaParser.fromJavaVersion().build(); - List<J.CompilationUnit> result = parser.parse("class $ { Object o = " + literalValue + "; }") - .collect(Collectors.toList()); + J.CompilationUnit result = parser.parse("class $ { Object o = " + literalValue + "; }") + .findFirst() + .map(J.CompilationUnit.class::cast) + .orElseThrow(() -> new IllegalStateException("Expected to have one parsed compilation unit.")); - J j = ((J.VariableDeclarations) result.get(0).getClasses().get(0).getBody().getStatements().get(0)).getVariables().get(0).getInitializer(); + J j = ((J.VariableDeclarations) result.getClasses().get(0).getBody().getStatements().get(0)).getVariables().get(0).getInitializer(); if (!(j instanceof J.Literal)) { throw new IllegalArgumentException("Unknown literal type for literal value: " + literalValue); } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateParser.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateParser.java index b8b290f52f8..72321855a7a 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateParser.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateParser.java @@ -235,7 +235,7 @@ private JavaSourceFile compileTemplate(@Language("java") String stub) { ExecutionContext ctx = new InMemoryExecutionContext(); ctx.putMessage(JavaParser.SKIP_SOURCE_SET_TYPE_GENERATION, true); JavaParser jp = parser.clone().build(); - return (stub.contains("@SubAnnotation") ? + return (JavaSourceFile) (stub.contains("@SubAnnotation") ? jp.reset().parse(ctx, stub, SUBSTITUTED_ANNOTATION) : jp.reset().parse(ctx, stub) ).findFirst().orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/marker/JavaSourceSet.java b/rewrite-java/src/main/java/org/openrewrite/java/marker/JavaSourceSet.java index f1d66fbbfc6..1e7c6622ee4 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/marker/JavaSourceSet.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/marker/JavaSourceSet.java @@ -121,7 +121,6 @@ private static List<JavaType.FullyQualified> typesFrom( ) { List<JavaType.FullyQualified> types = new ArrayList<>(); if (fullTypeInformation) { - @Language("java") String[] typeStubs = typeStubsFor(packagesToTypes); @@ -133,7 +132,8 @@ private static List<JavaType.FullyQualified> typesFrom( .classpath(classpath) .build(); - jp.parse(noRecursiveJavaSourceSet, typeStubs).forEach(cu -> { + jp.parse(noRecursiveJavaSourceSet, typeStubs).forEach(sourceFile -> { + J.CompilationUnit cu = (J.CompilationUnit) sourceFile; if (!cu.getClasses().isEmpty()) { J.Block body = cu.getClasses().get(0).getBody(); for (Statement s : body.getStatements()) { diff --git a/rewrite-java/src/main/java/org/openrewrite/java/recipes/MigrateRecipeToRewrite8.java b/rewrite-java/src/main/java/org/openrewrite/java/recipes/MigrateRecipeToRewrite8.java index bb59be81158..3317afc390a 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/recipes/MigrateRecipeToRewrite8.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/recipes/MigrateRecipeToRewrite8.java @@ -46,10 +46,6 @@ public class MigrateRecipeToRewrite8 extends Recipe { private static final AnnotationMatcher OVERRIDE_ANNOTATION_MATCHER = new AnnotationMatcher("@java.lang.Override"); private static final MethodMatcher VISIT_JAVA_SOURCE_FILE_METHOD_MATCHER = new MethodMatcher("org.openrewrite.java.JavaVisitor visitJavaSourceFile(..)", true); private static final MethodMatcher TREE_VISITOR_VISIT_METHOD_MATCHER = new MethodMatcher("org.openrewrite.TreeVisitor visit(..)", true); - private static final MethodMatcher APPLICABILITY_AND_METHOD_MATCHER = new MethodMatcher("org.openrewrite.Applicability and(..)"); - private static final MethodMatcher APPLICABILITY_OR_METHOD_MATCHER = new MethodMatcher("org.openrewrite.Applicability or(..)"); - private static final MethodMatcher APPLICABILITY_NOT_METHOD_MATCHER = new MethodMatcher("org.openrewrite.Applicability not(..)"); - private static final MethodMatcher DO_NEXT_METHOD_MATCHER = new MethodMatcher("org.openrewrite.Recipe doNext(..)"); @Nullable private static J.ParameterizedType getVisitorReturnTypeTemplate; @@ -586,7 +582,7 @@ private static <J2 extends J> J2 parseAndBuild(@Language("java") String code, Collection<Path> classpath) { JavaParser.Builder<? extends JavaParser, ?> builder = JavaParser.fromJavaVersion().classpath(classpath); - J.CompilationUnit cu = builder.build() + SourceFile cu = builder.build() .parse(code) .findFirst() .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); diff --git a/rewrite-java/src/test/java/org/openrewrite/java/internal/template/PatternVariablesTest.java b/rewrite-java/src/test/java/org/openrewrite/java/internal/template/PatternVariablesTest.java index 30fa7916249..de77661a935 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/internal/template/PatternVariablesTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/internal/template/PatternVariablesTest.java @@ -83,6 +83,7 @@ void test(Object o) { """.replace("$condition", condition); J.CompilationUnit cu = parser.parse(source) .findFirst() + .map(J.CompilationUnit.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); J.MethodDeclaration method = (J.MethodDeclaration) cu.getClasses().get(0).getBody().getStatements().get(0); @SuppressWarnings("DataFlowIssue") J.If ifStatement = (J.If) method.getBody().getStatements().get(0); @@ -146,6 +147,7 @@ void test(Object o) { """.replace("$statement", statement); J.CompilationUnit cu = parser.parse(source) .findFirst() + .map(J.CompilationUnit.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as Java")); J.MethodDeclaration method = (J.MethodDeclaration) cu.getClasses().get(0).getBody().getStatements().get(0); //noinspection DataFlowIssue diff --git a/rewrite-json/src/main/java/org/openrewrite/json/JsonParser.java b/rewrite-json/src/main/java/org/openrewrite/json/JsonParser.java index 1f44ead05ee..8371cae31b5 100755 --- a/rewrite-json/src/main/java/org/openrewrite/json/JsonParser.java +++ b/rewrite-json/src/main/java/org/openrewrite/json/JsonParser.java @@ -15,14 +15,10 @@ */ package org.openrewrite.json; -import io.micrometer.core.instrument.Metrics; -import io.micrometer.core.instrument.Timer; import org.antlr.v4.runtime.*; import org.intellij.lang.annotations.Language; -import org.openrewrite.ExecutionContext; -import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.Parser; -import org.openrewrite.internal.MetricsHelper; +import org.openrewrite.*; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.json.internal.JsonParserVisitor; import org.openrewrite.json.internal.grammar.JSON5Lexer; @@ -33,46 +29,36 @@ import java.io.InputStream; import java.nio.file.Path; -import java.util.Objects; import java.util.stream.Stream; -public class JsonParser implements Parser<Json.Document> { +public class JsonParser implements Parser { @Override - public Stream<Json.Document> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); - return acceptedInputs(sourceFiles).stream() - .map(sourceFile -> { - Timer.Builder timer = Timer.builder("rewrite.parse") - .description("The time spent parsing an Json file") - .tag("file.type", "Json"); - Timer.Sample sample = Timer.start(); - try (InputStream sourceStream = sourceFile.getSource(ctx)) { - JSON5Parser parser = new JSON5Parser(new CommonTokenStream(new JSON5Lexer( - CharStreams.fromStream(sourceStream)))); - - parser.removeErrorListeners(); - parser.addErrorListener(new ForwardingErrorListener(sourceFile.getPath(), ctx)); - - Json.Document document = new JsonParserVisitor( - sourceFile.getRelativePath(relativeTo), - sourceFile.getFileAttributes(), - sourceFile.getSource(ctx) - ).visitJson5(parser.json5()); - sample.stop(MetricsHelper.successTags(timer).register(Metrics.globalRegistry)); - parsingListener.parsed(sourceFile, document); - return document; - } catch (Throwable t) { - sample.stop(MetricsHelper.errorTags(timer, t).register(Metrics.globalRegistry)); - ParsingExecutionContextView.view(ctx).parseFailure(sourceFile, relativeTo, this, t); - ctx.getOnError().accept(new IllegalStateException(sourceFile.getPath() + " " + t.getMessage(), t)); - return null; - } - }) - .filter(Objects::nonNull); + return acceptedInputs(sourceFiles).map(sourceFile -> { + try (InputStream sourceStream = sourceFile.getSource(ctx)) { + JSON5Parser parser = new JSON5Parser(new CommonTokenStream(new JSON5Lexer( + CharStreams.fromStream(sourceStream)))); + + parser.removeErrorListeners(); + parser.addErrorListener(new ForwardingErrorListener(sourceFile.getPath(), ctx)); + + Json.Document document = new JsonParserVisitor( + sourceFile.getRelativePath(relativeTo), + sourceFile.getFileAttributes(), + sourceFile.getSource(ctx) + ).visitJson5(parser.json5()); + parsingListener.parsed(sourceFile, document); + return document; + } catch (Throwable t) { + ctx.getOnError().accept(t); + return ParseError.build(this, sourceFile, relativeTo, ctx, t); + } + }); } @Override - public Stream<Json.Document> parse(@Language("Json") String... sources) { + public Stream<SourceFile> parse(@Language("Json") String... sources) { return parse(new InMemoryExecutionContext(), sources); } @@ -106,6 +92,7 @@ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, public static Builder builder() { return new Builder(); } + public static class Builder extends org.openrewrite.Parser.Builder { public Builder() { diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtension.java b/rewrite-maven/src/main/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtension.java index 86a20dd82c6..d9d342e5a5f 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtension.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/AddGradleEnterpriseMavenExtension.java @@ -291,6 +291,7 @@ private BuildScanConfiguration buildScanConfiguration() { private static Xml.Document createNewXml(String filePath, @Language("xml") String fileContents) { XmlParser parser = new XmlParser(); Xml.Document brandNewFile = parser.parse(fileContents).findFirst() + .map(Xml.Document.class::cast) .orElseThrow(() -> new IllegalArgumentException("Unable to parse XML contents")); return brandNewFile.withSourcePath(Paths.get(filePath)); } diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/MavenParser.java b/rewrite-maven/src/main/java/org/openrewrite/maven/MavenParser.java index 17ef6b13c10..a35809e7999 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/MavenParser.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/MavenParser.java @@ -17,10 +17,7 @@ import lombok.RequiredArgsConstructor; import org.intellij.lang.annotations.Language; -import org.openrewrite.ExecutionContext; -import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.ParseExceptionResult; -import org.openrewrite.Parser; +import org.openrewrite.*; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.maven.internal.MavenPomDownloader; import org.openrewrite.maven.internal.RawPom; @@ -45,16 +42,16 @@ import static org.openrewrite.Tree.randomId; @RequiredArgsConstructor -public class MavenParser implements Parser<Xml.Document> { +public class MavenParser implements Parser { private final Collection<String> activeProfiles; @Override - public Stream<Xml.Document> parse(@Language("xml") String... sources) { + public Stream<SourceFile> parse(@Language("xml") String... sources) { return parse(new InMemoryExecutionContext(), sources); } @Override - public Stream<Xml.Document> parse(ExecutionContext ctx, @Language("xml") String... sources) { + public Stream<SourceFile> parse(ExecutionContext ctx, @Language("xml") String... sources) { return Parser.super.parse(ctx, sources); } @@ -66,8 +63,10 @@ public boolean accept(Path path) { } @Override - public Stream<Xml.Document> parseInputs(Iterable<Input> sources, @Nullable Path relativeTo, + public Stream<SourceFile> parseInputs(Iterable<Input> sources, @Nullable Path relativeTo, ExecutionContext ctx) { + List<SourceFile> parsed = new ArrayList<>(); + Map<Xml.Document, Pom> projectPoms = new LinkedHashMap<>(); Map<Path, Pom> projectPomsByPath = new HashMap<>(); for (Input source : sources) { @@ -83,19 +82,18 @@ public Stream<Xml.Document> parseInputs(Iterable<Input> sources, @Nullable Path pom.getProperties().put("project.basedir", baseDir); pom.getProperties().put("basedir", baseDir); - Xml.Document xml = new MavenXmlParser() + Xml.Document xml = (Xml.Document) new MavenXmlParser() .parseInputs(singletonList(source), relativeTo, ctx) .iterator().next(); projectPoms.put(xml, pom); projectPomsByPath.put(pomPath, pom); } catch (Throwable t) { - ParsingExecutionContextView.view(ctx).parseFailure(source, relativeTo, this, t); ctx.getOnError().accept(t); + parsed.add(ParseError.build(this, source, relativeTo, ctx, t)); } } - List<Xml.Document> parsed = new ArrayList<>(); MavenPomDownloader downloader = new MavenPomDownloader(projectPomsByPath, ctx); MavenExecutionContextView mavenCtx = MavenExecutionContextView.view(ctx); @@ -115,14 +113,14 @@ public Stream<Xml.Document> parseInputs(Iterable<Input> sources, @Nullable Path } for (int i = 0; i < parsed.size(); i++) { - Xml.Document maven = parsed.get(i); + SourceFile maven = parsed.get(i); Optional<MavenResolutionResult> maybeResolutionResult = maven.getMarkers().findFirst(MavenResolutionResult.class); if(!maybeResolutionResult.isPresent()) { continue; } MavenResolutionResult resolutionResult = maybeResolutionResult.get(); List<MavenResolutionResult> modules = new ArrayList<>(0); - for (Xml.Document possibleModule : parsed) { + for (SourceFile possibleModule : parsed) { if (possibleModule == maven) { continue; } diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/utilities/MavenArtifactDownloaderTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/utilities/MavenArtifactDownloaderTest.java index d0389067f43..d46316b6fda 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/utilities/MavenArtifactDownloaderTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/utilities/MavenArtifactDownloaderTest.java @@ -19,6 +19,7 @@ import org.junit.jupiter.api.io.TempDir; import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.SourceFile; import org.openrewrite.maven.MavenParser; import org.openrewrite.maven.cache.LocalMavenArtifactCache; import org.openrewrite.maven.cache.MavenArtifactCache; @@ -26,7 +27,6 @@ import org.openrewrite.maven.tree.ResolvedDependency; import org.openrewrite.maven.tree.ResolvedGroupArtifactVersion; import org.openrewrite.maven.tree.Scope; -import org.openrewrite.xml.tree.Xml; import java.nio.file.Path; import java.util.List; @@ -48,7 +48,7 @@ void downloadDependencies(@TempDir Path tempDir) { "1.6.0", null); MavenParser mavenParser = MavenParser.builder().build(); - Xml.Document parsed = mavenParser.parse(ctx, + SourceFile parsed = mavenParser.parse(ctx, String.format( //language=xml """ diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/utilities/PrintMavenAsCycloneDxBomTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/utilities/PrintMavenAsCycloneDxBomTest.java index f17229bec5c..66aaf0de6f3 100755 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/utilities/PrintMavenAsCycloneDxBomTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/utilities/PrintMavenAsCycloneDxBomTest.java @@ -16,6 +16,7 @@ package org.openrewrite.maven.utilities; import org.junit.jupiter.api.Test; +import org.openrewrite.SourceFile; import org.openrewrite.maven.MavenParser; import org.openrewrite.test.RewriteTest; import org.openrewrite.xml.tree.Xml; @@ -26,39 +27,39 @@ class PrintMavenAsCycloneDxBomTest implements RewriteTest { @Test void cycloneDxBom() { - Xml.Document pom = MavenParser.builder() + Xml.Document pom = (Xml.Document) MavenParser.builder() .build() .parse( - """ - <project> - <modelVersion>4.0.0</modelVersion> - \s - <groupId>com.mycompany.app</groupId> - <artifactId>my-app</artifactId> - <version>1</version> - \s - <dependencies> - <dependency> - <groupId>org.yaml</groupId> - <artifactId>snakeyaml</artifactId> - <version>1.27</version> - </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter</artifactId> - <version>5.7.0</version> - <scope>test</scope> - </dependency> - </dependencies> - </project> - """ - ).findFirst().orElseThrow(() -> new IllegalArgumentException("Could not parse as XML")); + """ + <project> + <modelVersion>4.0.0</modelVersion> + \s + <groupId>com.mycompany.app</groupId> + <artifactId>my-app</artifactId> + <version>1</version> + \s + <dependencies> + <dependency> + <groupId>org.yaml</groupId> + <artifactId>snakeyaml</artifactId> + <version>1.27</version> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter</artifactId> + <version>5.7.0</version> + <scope>test</scope> + </dependency> + </dependencies> + </project> + """ + ).toList().get(0); String bom = PrintMavenAsCycloneDxBom.print(pom) .replaceAll("<timestamp>.*</timestamp>", "<timestamp>TODAY</timestamp>"); assertThat(bom).isEqualTo(String.format( - """ + """ <?xml version="1.0" encoding="UTF-8"?> <bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:%s" version="1"> <metadata> @@ -105,44 +106,44 @@ void cycloneDxBom() { @Test void pomPackaging_cycloneDxBom() { - Xml.Document pom = MavenParser.builder() + Xml.Document pom = (Xml.Document) MavenParser.builder() .build() .parse( """ - <?xml version="1.0" encoding="UTF-8"?> - <project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <groupId>org.example</groupId> - <artifactId>pom_packaging</artifactId> - <version>1.0</version> - <packaging>pom</packaging> - - <properties> - <maven.compiler.source>11</maven.compiler.source> - <maven.compiler.target>11</maven.compiler.target> - </properties> - - - <dependencies> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-api</artifactId> - <version>5.9.3</version> - <scope>test</scope> - </dependency> - </dependencies> - </project> - """ - ).findFirst().orElseThrow(() -> new IllegalArgumentException("Could not parse as XML")); + <?xml version="1.0" encoding="UTF-8"?> + <project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.example</groupId> + <artifactId>pom_packaging</artifactId> + <version>1.0</version> + <packaging>pom</packaging> + + <properties> + <maven.compiler.source>11</maven.compiler.source> + <maven.compiler.target>11</maven.compiler.target> + </properties> + + + <dependencies> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <version>5.9.3</version> + <scope>test</scope> + </dependency> + </dependencies> + </project> + """ + ).toList().get(0); String bom = PrintMavenAsCycloneDxBom.print(pom) .replaceAll("<timestamp>.*</timestamp>", "<timestamp>TODAY</timestamp>"); assertThat(bom).isEqualTo(String.format( - """ + """ <?xml version="1.0" encoding="UTF-8"?> <bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:%s" version="1"> <metadata> diff --git a/rewrite-properties/src/main/java/org/openrewrite/properties/PropertiesParser.java b/rewrite-properties/src/main/java/org/openrewrite/properties/PropertiesParser.java index 92122bd5d4d..944184eaac3 100755 --- a/rewrite-properties/src/main/java/org/openrewrite/properties/PropertiesParser.java +++ b/rewrite-properties/src/main/java/org/openrewrite/properties/PropertiesParser.java @@ -15,15 +15,9 @@ */ package org.openrewrite.properties; -import io.micrometer.core.instrument.Metrics; -import io.micrometer.core.instrument.Timer; import org.intellij.lang.annotations.Language; -import org.openrewrite.ExecutionContext; -import org.openrewrite.FileAttributes; -import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.Parser; +import org.openrewrite.*; import org.openrewrite.internal.EncodingDetectingInputStream; -import org.openrewrite.internal.MetricsHelper; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.marker.Markers; import org.openrewrite.properties.tree.Properties; @@ -33,41 +27,31 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.stream.Stream; import static org.openrewrite.Tree.randomId; -public class PropertiesParser implements Parser<Properties.File> { +public class PropertiesParser implements Parser { @Override - public Stream<Properties.File> parse(@Language("properties") String... sources) { + public Stream<SourceFile> parse(@Language("properties") String... sources) { return parse(new InMemoryExecutionContext(), sources); } @Override - public Stream<Properties.File> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); - return acceptedInputs(sourceFiles).stream() - .map(sourceFile -> { - Path path = sourceFile.getRelativePath(relativeTo); - Timer.Builder timer = Timer.builder("rewrite.parse") - .description("The time spent parsing a properties file") - .tag("file.type", "Properties"); - Timer.Sample sample = Timer.start(); - try (EncodingDetectingInputStream is = sourceFile.getSource(ctx)) { - Properties.File file = parseFromInput(path, is) - .withFileAttributes(sourceFile.getFileAttributes()); - sample.stop(MetricsHelper.successTags(timer).register(Metrics.globalRegistry)); - parsingListener.parsed(sourceFile, file); - return file; - } catch (Throwable t) { - sample.stop(MetricsHelper.errorTags(timer, t).register(Metrics.globalRegistry)); - ParsingExecutionContextView.view(ctx).parseFailure(sourceFile, relativeTo, this, t); - ctx.getOnError().accept(new IllegalStateException(sourceFile.getPath() + " " + t.getMessage(), t)); - return null; - } - }) - .filter(Objects::nonNull); + return acceptedInputs(sourceFiles).map(sourceFile -> { + Path path = sourceFile.getRelativePath(relativeTo); + try (EncodingDetectingInputStream is = sourceFile.getSource(ctx)) { + Properties.File file = parseFromInput(path, is) + .withFileAttributes(sourceFile.getFileAttributes()); + parsingListener.parsed(sourceFile, file); + return file; + } catch (Throwable t) { + ctx.getOnError().accept(t); + return ParseError.build(this, sourceFile, relativeTo, ctx, t); + } + }); } private Properties.File parseFromInput(Path sourceFile, EncodingDetectingInputStream source) { @@ -122,7 +106,7 @@ private Properties.File parseFromInput(Path sourceFile, EncodingDetectingInputSt source.isCharsetBomMarked(), FileAttributes.fromPath(sourceFile), null - ); + ); } @Nullable @@ -145,7 +129,7 @@ private Properties.Content extractContent(String line, StringBuilder prefix) { } private boolean isDelimitedByWhitespace(String line) { - return line.length() >=3 && !Character.isWhitespace(line.charAt(0)) && !Character.isWhitespace(line.length() - 1) && line.contains(" "); + return line.length() >= 3 && !Character.isWhitespace(line.charAt(0)) && !Character.isWhitespace(line.length() - 1) && line.contains(" "); } private Properties.Comment commentFromLine(String line, String prefix, Properties.Comment.Delimiter delimiter) { @@ -286,6 +270,7 @@ public Path sourcePathFromSourceText(Path prefix, String sourceCode) { public static Builder builder() { return new Builder(); } + public static class Builder extends org.openrewrite.Parser.Builder { public Builder() { diff --git a/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java b/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java index dd14d86b01d..f7559ea54e5 100644 --- a/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java +++ b/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java @@ -15,15 +15,11 @@ */ package org.openrewrite.protobuf; -import io.micrometer.core.instrument.Metrics; -import io.micrometer.core.instrument.Timer; import org.antlr.v4.runtime.*; import org.intellij.lang.annotations.Language; -import org.openrewrite.ExecutionContext; -import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.Parser; +import org.openrewrite.*; import org.openrewrite.internal.EncodingDetectingInputStream; -import org.openrewrite.internal.MetricsHelper; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.protobuf.internal.ProtoParserVisitor; import org.openrewrite.protobuf.internal.grammar.Protobuf2Lexer; @@ -33,56 +29,46 @@ import org.openrewrite.tree.ParsingExecutionContextView; import java.nio.file.Path; -import java.util.Objects; import java.util.stream.Stream; -public class ProtoParser implements Parser<Proto.Document> { +public class ProtoParser implements Parser { @Override - public Stream<Proto.Document> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); - return acceptedInputs(sourceFiles).stream() - .map(sourceFile -> { - Timer.Builder timer = Timer.builder("rewrite.parse") - .description("The time spent parsing a Protobuf file") - .tag("file.type", "Proto"); - Timer.Sample sample = Timer.start(); - Path path = sourceFile.getRelativePath(relativeTo); - try { - EncodingDetectingInputStream is = sourceFile.getSource(ctx); - String sourceStr = is.readFully(); - Protobuf2Parser parser = new Protobuf2Parser(new CommonTokenStream(new Protobuf2Lexer( - CharStreams.fromString(sourceStr)))); - - parser.removeErrorListeners(); - parser.addErrorListener(new ForwardingErrorListener(sourceFile.getPath(), ctx)); - - if (sourceStr.contains("proto3")) { - return null; - } - - Proto.Document document = new ProtoParserVisitor( - path, - sourceFile.getFileAttributes(), - sourceStr, - is.getCharset(), - is.isCharsetBomMarked() - ).visitProto(parser.proto()); - sample.stop(MetricsHelper.successTags(timer).register(Metrics.globalRegistry)); - parsingListener.parsed(sourceFile, document); - return document; - } catch (Throwable t) { - sample.stop(MetricsHelper.errorTags(timer, t).register(Metrics.globalRegistry)); - ParsingExecutionContextView.view(ctx).parseFailure(sourceFile, relativeTo, this, t); - ctx.getOnError().accept(new IllegalStateException(path + " " + t.getMessage(), t)); - return null; - } - }) - .filter(Objects::nonNull); + return acceptedInputs(sourceFiles).map(sourceFile -> { + Path path = sourceFile.getRelativePath(relativeTo); + try { + EncodingDetectingInputStream is = sourceFile.getSource(ctx); + String sourceStr = is.readFully(); + Protobuf2Parser parser = new Protobuf2Parser(new CommonTokenStream(new Protobuf2Lexer( + CharStreams.fromString(sourceStr)))); + + parser.removeErrorListeners(); + parser.addErrorListener(new ForwardingErrorListener(sourceFile.getPath(), ctx)); + + if (sourceStr.contains("proto3")) { + return null; + } + + Proto.Document document = new ProtoParserVisitor( + path, + sourceFile.getFileAttributes(), + sourceStr, + is.getCharset(), + is.isCharsetBomMarked() + ).visitProto(parser.proto()); + parsingListener.parsed(sourceFile, document); + return document; + } catch (Throwable t) { + ctx.getOnError().accept(t); + return ParseError.build(this, sourceFile, relativeTo, ctx, t); + } + }); } @Override - public Stream<Proto.Document> parse(@Language("protobuf") String... sources) { + public Stream<SourceFile> parse(@Language("protobuf") String... sources) { return parse(new InMemoryExecutionContext(), sources); } @@ -117,6 +103,7 @@ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, public static Builder builder() { return new Builder(); } + public static class Builder extends Parser.Builder { public Builder() { diff --git a/rewrite-test/src/main/java/org/openrewrite/test/ParserType.java b/rewrite-test/src/main/java/org/openrewrite/test/ParserType.java index c0d77fb7fbb..f850edc0c2b 100644 --- a/rewrite-test/src/main/java/org/openrewrite/test/ParserType.java +++ b/rewrite-test/src/main/java/org/openrewrite/test/ParserType.java @@ -25,7 +25,7 @@ class ParserTypeUtils { private ParserTypeUtils() { } - public static Class<SourceFile> parserType(Parser<?> parser) { + public static Class<SourceFile> parserType(Parser parser) { return parserType(parser.getClass()); } diff --git a/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java b/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java index 06fe30ffa09..e677deda31e 100644 --- a/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java +++ b/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java @@ -224,7 +224,7 @@ default void rewriteRun(Consumer<RecipeSpec> spec, SourceSpec<?>... sourceSpecs) Map<SourceFile, SourceSpec<?>> specBySourceFile = new LinkedHashMap<>(sourceSpecs.length); for (Map.Entry<Parser.Builder, List<SourceSpec<?>>> sourceSpecsForParser : sourceSpecsByParser.entrySet()) { Map<SourceSpec<?>, Parser.Input> inputs = new LinkedHashMap<>(sourceSpecsForParser.getValue().size()); - Parser<?> parser = sourceSpecsForParser.getKey().build(); + Parser parser = sourceSpecsForParser.getKey().build(); for (SourceSpec<?> sourceSpec : sourceSpecsForParser.getValue()) { if (sourceSpec.before == null) { continue; diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/XmlParser.java b/rewrite-xml/src/main/java/org/openrewrite/xml/XmlParser.java index 1e4ece63bc8..00a5a15a529 100755 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/XmlParser.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/XmlParser.java @@ -15,15 +15,11 @@ */ package org.openrewrite.xml; -import io.micrometer.core.instrument.Metrics; -import io.micrometer.core.instrument.Timer; import org.antlr.v4.runtime.*; import org.intellij.lang.annotations.Language; -import org.openrewrite.ExecutionContext; -import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.Parser; +import org.openrewrite.*; import org.openrewrite.internal.EncodingDetectingInputStream; -import org.openrewrite.internal.MetricsHelper; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.tree.ParsingEventListener; import org.openrewrite.tree.ParsingExecutionContextView; @@ -33,53 +29,42 @@ import org.openrewrite.xml.tree.Xml; import java.nio.file.Path; -import java.util.Objects; import java.util.stream.Stream; -public class XmlParser implements Parser<Xml.Document> { +public class XmlParser implements Parser { @Override - public Stream<Xml.Document> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); - return acceptedInputs(sourceFiles).stream() - .map(sourceFile -> { - Timer.Builder timer = Timer.builder("rewrite.parse") - .description("The time spent parsing an XML file") - .tag("file.type", "XML"); - Timer.Sample sample = Timer.start(); - Path path = sourceFile.getRelativePath(relativeTo); - try { - EncodingDetectingInputStream is = sourceFile.getSource(ctx); - String sourceStr = is.readFully(); - - XMLParser parser = new XMLParser(new CommonTokenStream(new XMLLexer( - CharStreams.fromString(sourceStr)))); - - parser.removeErrorListeners(); - parser.addErrorListener(new ForwardingErrorListener(sourceFile.getPath(), ctx)); - - Xml.Document document = new XmlParserVisitor( - path, - sourceFile.getFileAttributes(), - sourceStr, - is.getCharset(), - is.isCharsetBomMarked() - ).visitDocument(parser.document()); - - sample.stop(MetricsHelper.successTags(timer).register(Metrics.globalRegistry)); - parsingListener.parsed(sourceFile, document); - return document; - } catch (Throwable t) { - sample.stop(MetricsHelper.errorTags(timer, t).register(Metrics.globalRegistry)); - ParsingExecutionContextView.view(ctx).parseFailure(sourceFile, relativeTo, this, t); - ctx.getOnError().accept(new IllegalStateException(path + " " + t.getMessage(), t)); - return null; - } - }) - .filter(Objects::nonNull); + return acceptedInputs(sourceFiles).map(sourceFile -> { + Path path = sourceFile.getRelativePath(relativeTo); + try { + EncodingDetectingInputStream is = sourceFile.getSource(ctx); + String sourceStr = is.readFully(); + + XMLParser parser = new XMLParser(new CommonTokenStream(new XMLLexer( + CharStreams.fromString(sourceStr)))); + + parser.removeErrorListeners(); + parser.addErrorListener(new ForwardingErrorListener(sourceFile.getPath(), ctx)); + + Xml.Document document = new XmlParserVisitor( + path, + sourceFile.getFileAttributes(), + sourceStr, + is.getCharset(), + is.isCharsetBomMarked() + ).visitDocument(parser.document()); + parsingListener.parsed(sourceFile, document); + return document; + } catch (Throwable t) { + ctx.getOnError().accept(t); + return ParseError.build(this, sourceFile, relativeTo, ctx, t); + } + }); } @Override - public Stream<Xml.Document> parse(@Language("xml") String... sources) { + public Stream<SourceFile> parse(@Language("xml") String... sources) { return parse(new InMemoryExecutionContext(), sources); } @@ -120,6 +105,7 @@ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, public static Builder builder() { return new Builder(); } + public static class Builder extends org.openrewrite.Parser.Builder { public Builder() { diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java b/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java index a9fab664737..63f45d29e7f 100755 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java @@ -279,6 +279,7 @@ public String getPrefix() { public static Xml.Tag build(@Language("xml") String tagSource) { return new XmlParser().parse(tagSource) .findFirst() + .map(Xml.Document.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as XML")) .getRoot(); } diff --git a/rewrite-xml/src/test/java/org/openrewrite/xml/XPathMatcherTest.java b/rewrite-xml/src/test/java/org/openrewrite/xml/XPathMatcherTest.java index d084d1ca72f..ff8c668801e 100755 --- a/rewrite-xml/src/test/java/org/openrewrite/xml/XPathMatcherTest.java +++ b/rewrite-xml/src/test/java/org/openrewrite/xml/XPathMatcherTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.Test; import org.openrewrite.ExecutionContext; +import org.openrewrite.SourceFile; import org.openrewrite.TreeVisitor; import org.openrewrite.marker.SearchResult; import org.openrewrite.xml.tree.Xml; @@ -27,7 +28,7 @@ class XPathMatcherTest { - private final Xml.Document xmlDoc = new XmlParser().parse( + private final SourceFile xmlDoc = new XmlParser().parse( """ <?xml version="1.0" encoding="UTF-8"?> <dependencies> @@ -40,9 +41,9 @@ class XPathMatcherTest { </dependency> </dependencies> """ - ).findFirst().orElseThrow(() -> new IllegalArgumentException("Could not parse as XML")); + ).toList().get(0); - private final Xml.Document pomXml = new XmlParser().parse( + private final SourceFile pomXml = new XmlParser().parse( """ <project> <groupId>com.mycompany.app</groupId> @@ -65,6 +66,7 @@ class XPathMatcherTest { """ ).toList().get(0); + @Test void matchAbsolute() { assertThat(match("/dependencies/dependency", xmlDoc)).isTrue(); @@ -107,7 +109,7 @@ void matchPom() { pomXml)).isFalse(); } - private boolean match(String xpath, Xml.Document x) { + private boolean match(String xpath, SourceFile x) { XPathMatcher matcher = new XPathMatcher(xpath); return !TreeVisitor.collect(new XmlVisitor<>() { @Override diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/MergeYaml.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/MergeYaml.java index 8c11a4e13ee..1cdaec98b46 100644 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/MergeYaml.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/MergeYaml.java @@ -57,7 +57,7 @@ public Validated<Object> validate() { .and(Validated.test("yaml", "Must be valid YAML", yaml, y -> new YamlParser().parse(yaml) .findFirst() - .map(doc -> !doc.getDocuments().isEmpty()) + .map(doc -> !((Yaml.Documents) doc).getDocuments().isEmpty()) .orElse(false))); } @@ -76,6 +76,7 @@ public TreeVisitor<?, ExecutionContext> getVisitor() { JsonPathMatcher matcher = new JsonPathMatcher(key); Yaml incoming = new YamlParser().parse(yaml) .findFirst() + .map(Yaml.Documents.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as YAML")) .getDocuments().get(0).getBlock(); diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/MergeYamlVisitor.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/MergeYamlVisitor.java index 18a8f9ec753..0aee495e9d7 100644 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/MergeYamlVisitor.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/MergeYamlVisitor.java @@ -45,6 +45,7 @@ public class MergeYamlVisitor<P> extends YamlVisitor<P> { public MergeYamlVisitor(Yaml scope, @Language("yml") String yamlString, boolean acceptTheirs, @Nullable String objectIdentifyingProperty) { this(scope, new YamlParser().parse(yamlString) .findFirst() + .map(Yaml.Documents.class::cast) .orElseThrow(() -> new IllegalArgumentException("Could not parse as YAML")) .getDocuments().get(0).getBlock(), acceptTheirs, objectIdentifyingProperty); } diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/YamlParser.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/YamlParser.java index 39c49c6815c..58b8e2fc1da 100644 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/YamlParser.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/YamlParser.java @@ -15,16 +15,11 @@ */ package org.openrewrite.yaml; -import io.micrometer.core.instrument.Metrics; -import io.micrometer.core.instrument.Timer; import lombok.Getter; import org.intellij.lang.annotations.Language; -import org.openrewrite.ExecutionContext; -import org.openrewrite.FileAttributes; -import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.*; import org.openrewrite.internal.EncodingDetectingInputStream; import org.openrewrite.internal.ListUtils; -import org.openrewrite.internal.MetricsHelper; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.marker.Markers; import org.openrewrite.tree.ParsingEventListener; @@ -54,45 +49,41 @@ import static java.util.Collections.singletonList; import static org.openrewrite.Tree.randomId; -public class YamlParser implements org.openrewrite.Parser<Yaml.Documents> { +public class YamlParser implements org.openrewrite.Parser { private static final Pattern VARIABLE_PATTERN = Pattern.compile(":\\s*(@[^\n\r@]+@)"); @Override - public Stream<Yaml.Documents> parse(@Language("yml") String... sources) { + public Stream<SourceFile> parse(@Language("yml") String... sources) { return parse(new InMemoryExecutionContext(), sources); } @Override - public Stream<Yaml.Documents> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + public Stream<SourceFile> parseInputs(Iterable<Input> sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); - return acceptedInputs(sourceFiles).stream() + return acceptedInputs(sourceFiles) .map(sourceFile -> { - Timer.Builder timer = Timer.builder("rewrite.parse") - .description("The time spent parsing a YAML file") - .tag("file.type", "YAML"); - Timer.Sample sample = Timer.start(); Path path = sourceFile.getRelativePath(relativeTo); try (EncodingDetectingInputStream is = sourceFile.getSource(ctx)) { Yaml.Documents yaml = parseFromInput(path, is); - sample.stop(MetricsHelper.successTags(timer).register(Metrics.globalRegistry)); parsingListener.parsed(sourceFile, yaml); return yaml.withFileAttributes(sourceFile.getFileAttributes()); } catch (Throwable t) { - sample.stop(MetricsHelper.errorTags(timer, t).register(Metrics.globalRegistry)); - ParsingExecutionContextView.view(ctx).parseFailure(sourceFile, relativeTo, this, t); - ctx.getOnError().accept(new IllegalStateException(path + " " + t.getMessage(), t)); - return null; + ctx.getOnError().accept(t); + return ParseError.build(this, sourceFile, relativeTo, ctx, t); } }) - .filter(Objects::nonNull) .map(this::unwrapPrefixedMappings) - .map(docs -> { - // ensure there is always at least one Document, even in an empty yaml file - if (docs.getDocuments().isEmpty()) { - return docs.withDocuments(singletonList(new Yaml.Document(randomId(), "", Markers.EMPTY, - false, new Yaml.Mapping(randomId(), Markers.EMPTY, null, emptyList(), null, null), null))); + .map(sourceFile -> { + if (sourceFile instanceof Yaml.Documents) { + Yaml.Documents docs = (Yaml.Documents) sourceFile; + // ensure there is always at least one Document, even in an empty yaml file + if (docs.getDocuments().isEmpty()) { + return docs.withDocuments(singletonList(new Yaml.Document(randomId(), "", Markers.EMPTY, + false, new Yaml.Mapping(randomId(), Markers.EMPTY, null, emptyList(), null, null), null))); + } + return docs; } - return docs; + return sourceFile; }); } @@ -151,7 +142,6 @@ private Yaml.Documents parseFromInput(Path sourceFile, EncodingDetectingInputStr case DocumentStart: { String fmt = newLine + reader.prefix(lastEnd, event); newLine = ""; - document = new Yaml.Document( randomId(), fmt, @@ -535,7 +525,10 @@ public Sequence withPrefix(String prefix) { } } - private Yaml.Documents unwrapPrefixedMappings(Yaml.Documents y) { + private SourceFile unwrapPrefixedMappings(SourceFile y) { + if (!(y instanceof Yaml.Documents)) { + return y; + } //noinspection ConstantConditions return (Yaml.Documents) new YamlIsoVisitor<Integer>() { @Override