Extract rewrite specific bits into commons-rewrite
This commit is contained in:
@@ -1,348 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2022 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.rewrite;
|
||||
|
||||
import static org.openrewrite.Tree.randomId;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.openrewrite.ExecutionContext;
|
||||
import org.openrewrite.SourceFile;
|
||||
import org.openrewrite.internal.ListUtils;
|
||||
import org.openrewrite.java.JavaParser;
|
||||
import org.openrewrite.java.marker.JavaProject;
|
||||
import org.openrewrite.java.marker.JavaSourceSet;
|
||||
import org.openrewrite.java.marker.JavaVersion;
|
||||
import org.openrewrite.marker.BuildTool;
|
||||
import org.openrewrite.marker.Marker;
|
||||
import org.openrewrite.maven.MavenParser;
|
||||
import org.openrewrite.maven.tree.Dependency;
|
||||
import org.openrewrite.maven.tree.MavenResolutionResult;
|
||||
import org.openrewrite.maven.tree.Pom;
|
||||
import org.openrewrite.maven.tree.ResolvedPom;
|
||||
import org.openrewrite.properties.PropertiesParser;
|
||||
import org.openrewrite.xml.XmlParser;
|
||||
import org.openrewrite.xml.tree.Xml;
|
||||
import org.openrewrite.xml.tree.Xml.Document;
|
||||
import org.openrewrite.yaml.YamlParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Parse a Maven project on disk into a list of {@link org.openrewrite.SourceFile} including
|
||||
* Maven, Java, YAML, properties, and XML AST representations of sources and resources found.
|
||||
*/
|
||||
public class MavenProjectParser {
|
||||
|
||||
private static final Pattern mavenWrapperVersionPattern = Pattern.compile(".*apache-maven/(.*?)/.*");
|
||||
private static final Logger logger = LoggerFactory.getLogger(MavenProjectParser.class);
|
||||
|
||||
private final MavenParser mavenParser;
|
||||
private final JavaParser.Builder<?, ?> javaParserBuilder;
|
||||
private final ExecutionContext ctx;
|
||||
|
||||
public MavenProjectParser(MavenParser.Builder mavenParserBuilder,
|
||||
JavaParser.Builder<?, ?> javaParserBuilder,
|
||||
ExecutionContext ctx) {
|
||||
this.mavenParser = mavenParserBuilder.build();
|
||||
this.javaParserBuilder = javaParserBuilder;
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a root path to a maven project, this parser will parse the maven project (including submodules)
|
||||
* and return a list of ALL source files for all maven modules under the root path.
|
||||
* <PRE>
|
||||
* Notes About Provenance Information:
|
||||
*
|
||||
* There are always three markers applied to each source file and there can potentially be up to five provenance
|
||||
* markers in total:
|
||||
*
|
||||
* BuildTool - What build tool was used to compile the source file (This will always be Maven)
|
||||
* JavaVersion - What Java version/vendor was used when compiling the source file.
|
||||
* JavaProject - For each maven module/sub-module, the same JavaProject will be associated with ALL source files
|
||||
* belonging to that module.
|
||||
*
|
||||
* Optional:
|
||||
*
|
||||
* GitProvenance - If the entire project exists in the context of a git repository, all source files (for all modules) will have the same GitProvenance.
|
||||
* JavaSourceSet - All Java source files and all resource files that exist in src/main or src/test will have a JavaSourceSet marker assigned to them.
|
||||
*
|
||||
* </PRE>
|
||||
* @param projectDirectory A path to the root folder containing a meven project.
|
||||
* @return A list of source files that have been parsed from the root folder
|
||||
*/
|
||||
public List<SourceFile> parse(Path projectDirectory, List<Path> dependencies) {
|
||||
List<Xml.Document> mavens = mavenParser.parse(getMavenPoms(projectDirectory, ctx), projectDirectory, ctx);
|
||||
List<Document> sorted = sort(mavens);
|
||||
|
||||
// Filter out pom files inside target folders. (Naive implementation.)
|
||||
mavens = sorted.stream().filter(m -> !isInsideBuildFolderOfOtherMavenProjects(sorted, m)).collect(Collectors.toList());
|
||||
|
||||
JavaParser javaParser = javaParserBuilder.build();
|
||||
|
||||
logger.info("The order in which projects are being parsed is:");
|
||||
for (Xml.Document maven : mavens) {
|
||||
logger.info(" {}:{}", getModel(maven).getGroupId(), getModel(maven).getArtifactId());
|
||||
}
|
||||
|
||||
List<SourceFile> sourceFiles = new ArrayList<>();
|
||||
for (Xml.Document maven : mavens) {
|
||||
List<Marker> projectProvenance = getJavaProvenance(maven, projectDirectory);
|
||||
sourceFiles.add(addProjectProvenance(maven, projectProvenance));
|
||||
|
||||
// List<Path> dependencies = downloadArtifacts(getResolvedPom(maven).getDependencies().get(Scope.Compile));
|
||||
javaParser.setSourceSet("main");
|
||||
javaParser.setClasspath(dependencies);
|
||||
sourceFiles.addAll(ListUtils.map(javaParser.parse(
|
||||
getJavaSources(getModel(maven).getRequested(), projectDirectory, ctx), projectDirectory, ctx), addProvenance(projectProvenance)));
|
||||
//Resources in the src/main should also have the main source set attached to them.
|
||||
parseResources(getResources(getModel(maven).getRequested(), projectDirectory, ctx), projectDirectory, sourceFiles, projectProvenance, javaParser.getSourceSet(ctx));
|
||||
|
||||
// List<Path> testDependencies = downloadArtifacts(maven.getModel().getDependencies(Scope.Test));
|
||||
javaParser.setSourceSet("test");
|
||||
// javaParser.setClasspath(testDependencies);
|
||||
sourceFiles.addAll(ListUtils.map(javaParser.parse(
|
||||
getTestJavaSources(getModel(maven).getRequested(), projectDirectory, ctx), projectDirectory, ctx), addProvenance(projectProvenance)));
|
||||
//Resources in the src/test should also have the test source set attached to them.
|
||||
parseResources(getTestResources(getModel(maven).getRequested(), projectDirectory, ctx), projectDirectory, sourceFiles, projectProvenance, javaParser.getSourceSet(ctx));
|
||||
}
|
||||
|
||||
return sourceFiles;
|
||||
}
|
||||
|
||||
private List<Marker> getJavaProvenance(Xml.Document maven, Path projectDirectory) {
|
||||
ResolvedPom mavenModel = getModel(maven);
|
||||
String javaRuntimeVersion = System.getProperty("java.runtime.version");
|
||||
String javaVendor = System.getProperty("java.vm.vendor");
|
||||
String sourceCompatibility = javaRuntimeVersion;
|
||||
String targetCompatibility = javaRuntimeVersion;
|
||||
String propertiesSourceCompatibility = mavenModel.getValue(mavenModel.getValue("maven.compiler.source"));
|
||||
if (propertiesSourceCompatibility != null) {
|
||||
sourceCompatibility = propertiesSourceCompatibility;
|
||||
}
|
||||
String propertiesTargetCompatibility = mavenModel.getValue(mavenModel.getValue("maven.compiler.target"));
|
||||
if (propertiesTargetCompatibility != null) {
|
||||
targetCompatibility = propertiesTargetCompatibility;
|
||||
}
|
||||
|
||||
Path wrapperPropertiesPath = projectDirectory.resolve(".mvn/wrapper/maven-wrapper.properties");
|
||||
String mavenVersion = "3.6";
|
||||
if (Files.exists(wrapperPropertiesPath)) {
|
||||
try {
|
||||
Properties wrapperProperties = new Properties();
|
||||
wrapperProperties.load(new FileReader(wrapperPropertiesPath.toFile()));
|
||||
String distributionUrl = (String) wrapperProperties.get("distributionUrl");
|
||||
if (distributionUrl != null) {
|
||||
Matcher wrapperVersionMatcher = mavenWrapperVersionPattern.matcher(distributionUrl);
|
||||
if (wrapperVersionMatcher.matches()) {
|
||||
mavenVersion = wrapperVersionMatcher.group(1);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
ctx.getOnError().accept(e);
|
||||
}
|
||||
}
|
||||
|
||||
return Arrays.asList(
|
||||
new BuildTool(randomId(), BuildTool.Type.Maven, mavenVersion),
|
||||
new JavaVersion(randomId(), javaRuntimeVersion, javaVendor, sourceCompatibility, targetCompatibility),
|
||||
new JavaProject(randomId(), mavenModel.getRequested().getName(), new JavaProject.Publication(
|
||||
mavenModel.getGroupId(),
|
||||
mavenModel.getArtifactId(),
|
||||
mavenModel.getVersion()
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
private void parseResources(List<Path> resources, Path projectDirectory, List<SourceFile> sourceFiles, List<Marker> projectProvenance, JavaSourceSet sourceSet) {
|
||||
List<Marker> provenance = new ArrayList<>(projectProvenance);
|
||||
provenance.add(sourceSet);
|
||||
|
||||
sourceFiles.addAll(ListUtils.map(new XmlParser().parse(
|
||||
resources.stream()
|
||||
.filter(p -> p.getFileName().toString().endsWith(".xml") ||
|
||||
p.getFileName().toString().endsWith(".wsdl") ||
|
||||
p.getFileName().toString().endsWith(".xhtml") ||
|
||||
p.getFileName().toString().endsWith(".xsd") ||
|
||||
p.getFileName().toString().endsWith(".xsl") ||
|
||||
p.getFileName().toString().endsWith(".xslt"))
|
||||
.collect(Collectors.toList()),
|
||||
projectDirectory,
|
||||
ctx
|
||||
), addProvenance(provenance)));
|
||||
|
||||
sourceFiles.addAll(ListUtils.map(new YamlParser().parse(
|
||||
resources.stream()
|
||||
.filter(p -> p.getFileName().toString().endsWith(".yml") || p.getFileName().toString().endsWith(".yaml"))
|
||||
.collect(Collectors.toList()),
|
||||
projectDirectory,
|
||||
ctx
|
||||
), addProvenance(provenance)));
|
||||
|
||||
sourceFiles.addAll(ListUtils.map(new PropertiesParser().parse(
|
||||
resources.stream()
|
||||
.filter(p -> p.getFileName().toString().endsWith(".properties"))
|
||||
.collect(Collectors.toList()),
|
||||
projectDirectory,
|
||||
ctx
|
||||
), addProvenance(provenance)));
|
||||
}
|
||||
|
||||
private <S extends SourceFile> S addProjectProvenance(S s, List<Marker> projectProvenance) {
|
||||
for (Marker marker : projectProvenance) {
|
||||
s = s.withMarkers(s.getMarkers().addIfAbsent(marker));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private <S extends SourceFile> UnaryOperator<S> addProvenance(List<Marker> projectProvenance) {
|
||||
return s -> {
|
||||
s = addProjectProvenance(s, projectProvenance);
|
||||
return s;
|
||||
};
|
||||
}
|
||||
|
||||
// private List<Path> downloadArtifacts(Set<Dependency> dependencies) {
|
||||
// return dependencies.stream()
|
||||
// .filter(d -> d.getRepository() != null)
|
||||
// .map(artifactDownloader::downloadArtifact)
|
||||
// .filter(Objects::nonNull)
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
|
||||
public static List<Xml.Document> sort(List<Xml.Document> mavens) {
|
||||
// the value is the set of maven projects that depend on the key
|
||||
Map<Xml.Document, Set<Xml.Document>> byDependedOn = new HashMap<>();
|
||||
|
||||
for (Xml.Document maven : mavens) {
|
||||
byDependedOn.computeIfAbsent(maven, m -> new HashSet<>());
|
||||
for (Dependency dependency : getModel(maven).getRequested().getDependencies()) {
|
||||
for (Xml.Document test : mavens) {
|
||||
if (getModel(test).getGroupId().equals(dependency.getGroupId()) &&
|
||||
getModel(test).getArtifactId().equals(dependency.getArtifactId())) {
|
||||
byDependedOn.computeIfAbsent(maven, m -> new HashSet<>()).add(test);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Xml.Document> sorted = new ArrayList<>(mavens.size());
|
||||
next:
|
||||
while (!byDependedOn.isEmpty()) {
|
||||
for (Map.Entry<Xml.Document, Set<Xml.Document>> mavenAndDependencies : byDependedOn.entrySet()) {
|
||||
if (mavenAndDependencies.getValue().isEmpty()) {
|
||||
Xml.Document maven = mavenAndDependencies.getKey();
|
||||
byDependedOn.remove(maven);
|
||||
sorted.add(maven);
|
||||
for (Set<Xml.Document> dependencies : byDependedOn.values()) {
|
||||
dependencies.remove(maven);
|
||||
}
|
||||
continue next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
private static boolean isInsideBuildFolderOfOtherMavenProjects(List<Xml.Document> all, Xml.Document current) {
|
||||
return all.stream().filter(m -> {
|
||||
if (m != current) {
|
||||
Path pomPath = m.getSourcePath();
|
||||
return current.getSourcePath().startsWith((pomPath.getParent() == null ? Paths.get("") : pomPath.getParent()) .resolve("target"));
|
||||
}
|
||||
return false;
|
||||
}).findFirst().isPresent();
|
||||
}
|
||||
|
||||
private static List<Path> getSources(Path srcDir, ExecutionContext ctx, String... fileTypes) {
|
||||
if (!srcDir.toFile().exists()) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
BiPredicate<Path, java.nio.file.attribute.BasicFileAttributes> predicate = (p, bfa) ->
|
||||
bfa.isRegularFile() && Arrays.stream(fileTypes).anyMatch(type -> p.getFileName().toString().endsWith(type));
|
||||
try {
|
||||
return Files.find(srcDir, 999, predicate).collect(Collectors.toList());
|
||||
} catch (IOException e) {
|
||||
ctx.getOnError().accept(e);
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Path> getMavenPoms(Path projectDir, ExecutionContext ctx) {
|
||||
return getSources(projectDir, ctx, "pom.xml").stream()
|
||||
.filter(p -> p.getFileName().toString().equals("pom.xml") &&
|
||||
!p.toString().contains("/src/"))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static ResolvedPom getModel(Xml.Document maven) {
|
||||
MavenResolutionResult pom = getResolvedPom(maven);
|
||||
return pom == null ? null : pom.getPom();
|
||||
}
|
||||
|
||||
private static MavenResolutionResult getResolvedPom(Xml.Document maven) {
|
||||
return maven.getMarkers().findFirst(MavenResolutionResult.class).orElse(null);
|
||||
}
|
||||
|
||||
private static List<Path> getJavaSources(Pom pom, Path projectDir, ExecutionContext ctx) {
|
||||
if (pom.getPackaging() != null && !"jar".equals(pom.getPackaging()) && !"bundle".equals(pom.getPackaging())) {
|
||||
return List.of();
|
||||
}
|
||||
return getSources(projectDir.resolve(pom.getSourcePath()).getParent().resolve(Paths.get("src", "main", "java")),
|
||||
ctx, ".java");
|
||||
}
|
||||
|
||||
private static List<Path> getTestJavaSources(Pom pom, Path projectDir, ExecutionContext ctx) {
|
||||
if (pom.getPackaging() != null && !"jar".equals(pom.getPackaging()) && !"bundle".equals(pom.getPackaging())) {
|
||||
return List.of();
|
||||
}
|
||||
return getSources(projectDir.resolve(pom.getSourcePath()).getParent().resolve(Paths.get("src", "test", "java")),
|
||||
ctx, ".java");
|
||||
}
|
||||
|
||||
private static List<Path> getResources(Pom pom, Path projectDir, ExecutionContext ctx) {
|
||||
if (pom.getPackaging() != null && !"jar".equals(pom.getPackaging()) && !"bundle".equals(pom.getPackaging())) {
|
||||
return List.of();
|
||||
}
|
||||
return getSources(projectDir.resolve(pom.getSourcePath()).getParent().resolve(Paths.get("src", "main", "resources")),
|
||||
ctx, ".properties", ".xml", ".yml", ".yaml");
|
||||
}
|
||||
|
||||
private static List<Path> getTestResources(Pom pom, Path projectDir, ExecutionContext ctx) {
|
||||
if (pom.getPackaging() != null && !"jar".equals(pom.getPackaging()) && !"bundle".equals(pom.getPackaging())) {
|
||||
return List.of();
|
||||
}
|
||||
return getSources(projectDir.resolve(pom.getSourcePath()).getParent().resolve(Paths.get("src", "test", "resources")),
|
||||
ctx, ".properties", ".xml", ".yml", ".yaml");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,341 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2022 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.rewrite;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.openrewrite.ExecutionContext;
|
||||
import org.openrewrite.InMemoryExecutionContext;
|
||||
import org.openrewrite.Parser;
|
||||
import org.openrewrite.Recipe;
|
||||
import org.openrewrite.Tree;
|
||||
import org.openrewrite.TreeVisitor;
|
||||
import org.openrewrite.java.JavaParser;
|
||||
import org.openrewrite.java.JavaVisitor;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.CompilationUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ORAstUtils {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ORAstUtils.class);
|
||||
|
||||
// private static class ParentMarker implements Marker {
|
||||
//
|
||||
// private UUID uuid;
|
||||
// private J parent;
|
||||
//
|
||||
// public ParentMarker(J parent) {
|
||||
// this.uuid = Tree.randomId();
|
||||
// this.parent = parent;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public UUID getId() {
|
||||
// return uuid;
|
||||
// }
|
||||
//
|
||||
// public J getParent() {
|
||||
// return parent;
|
||||
// }
|
||||
//
|
||||
// public J getGrandParent() {
|
||||
// if (parent != null) {
|
||||
// return parent.getMarkers().findFirst(ParentMarker.class).map(m -> m.getParent()).orElse(null);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public <T> T getFirstAnsector(Class<T> clazz) {
|
||||
// if (clazz.isInstance(parent)) {
|
||||
// return clazz.cast(parent);
|
||||
// } else if (parent != null) {
|
||||
// return parent.getMarkers().findFirst(ParentMarker.class).map(m -> m.getFirstAnsector(clazz)).orElse(null);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public <T extends Tree> T withId(UUID id) {
|
||||
// this.uuid = id;
|
||||
// return (T) this;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private static class AncestersMarker implements Marker {
|
||||
//
|
||||
// private UUID uuid;
|
||||
// private List<J> ancesters = List.of();
|
||||
//
|
||||
// public AncestersMarker(List<J> ancesters) {
|
||||
// this.uuid = Tree.randomId();
|
||||
// this.ancesters = ancesters;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public UUID getId() {
|
||||
// return uuid;
|
||||
// }
|
||||
//
|
||||
// @SuppressWarnings("unchecked")
|
||||
// public <T> T getFirstAnsector(Class<T> clazz) {
|
||||
// if (ancesters != null) {
|
||||
// for (J node : ancesters) {
|
||||
// if (clazz.isInstance(node)) {
|
||||
// return (T) node;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public J getParent() {
|
||||
// if (ancesters != null && !ancesters.isEmpty()) {
|
||||
// return ancesters.get(0);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public J getGrandParent() {
|
||||
// if (ancesters != null && ancesters.size() > 1) {
|
||||
// return ancesters.get(1);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private static class MarkParentRecipe extends Recipe {
|
||||
//
|
||||
// @Override
|
||||
// public String getDisplayName() {
|
||||
// return "Create parent AST node references via markers";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
// return new JavaIsoVisitor<>() {
|
||||
//
|
||||
// private Cursor parentCursor(Class<?> clazz) {
|
||||
// for (Cursor c = getCursor(); c != null
|
||||
// && !(c.getValue() instanceof SourceFile); c = c.getParent()) {
|
||||
// Object o = c.getValue();
|
||||
// if (clazz.isInstance(o)) {
|
||||
// return c;
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public J visit(Tree tree, ExecutionContext p) {
|
||||
// if (tree instanceof J) {
|
||||
// J j = (J) tree;
|
||||
// J newJ = super.visit(j, p).withMarkers(j.getMarkers().addIfAbsent(new ParentMarker(null)));
|
||||
//
|
||||
// List<J> children = p.pollMessage(j.getId().toString(), Collections.emptyList());
|
||||
// for (J child : children) {
|
||||
// child.getMarkers().findFirst(ParentMarker.class).map(m -> m.parent = newJ);
|
||||
// }
|
||||
//
|
||||
// // Prepare myself for the parent;
|
||||
//
|
||||
// Cursor parentCursor = parentCursor(J.class);
|
||||
// if (parentCursor != null) {
|
||||
// J parent = parentCursor.getValue();
|
||||
// String parentId = parent.getId().toString();
|
||||
// List<J> siblings = p.pollMessage(parentId, new ArrayList<J>());
|
||||
// siblings.add(newJ);
|
||||
// p.putMessage(parentId, siblings);
|
||||
// }
|
||||
// return newJ;
|
||||
// }
|
||||
// return (J) tree;
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public static J findAstNodeAt(CompilationUnit cu, int offset) {
|
||||
// AtomicReference<J> f = new AtomicReference<>();
|
||||
// new JavaIsoVisitor<AtomicReference<J>>() {
|
||||
// public J visit(Tree tree, AtomicReference<J> found) {
|
||||
// if (tree == null) {
|
||||
// return null;
|
||||
// }
|
||||
// if (found.get() == null && tree instanceof J) {
|
||||
// J node = (J) tree;
|
||||
// Range range = node.getMarkers().findFirst(Range.class).orElse(null);
|
||||
// if (range != null
|
||||
// && range.getStart().getOffset() <= offset
|
||||
// && offset <= range.getEnd().getOffset()) {
|
||||
// super.visit(tree, found);
|
||||
// if (found.get() == null) {
|
||||
// found.set(node);
|
||||
// return node;
|
||||
// }
|
||||
// } else {
|
||||
// return (J) tree;
|
||||
// }
|
||||
// }
|
||||
// return (J) tree;
|
||||
// };
|
||||
// }.visitNonNull(cu, f);
|
||||
// return f.get();
|
||||
// }
|
||||
//
|
||||
// @SuppressWarnings("unchecked")
|
||||
// public static <T> T findNode(J node, Class<T> clazz) {
|
||||
// if (clazz.isInstance(node)) {
|
||||
// return (T) node;
|
||||
// }
|
||||
// return node.getMarkers().findFirst(ParentMarker.class).map(m -> m.getFirstAnsector(clazz)).orElse(null);
|
||||
// }
|
||||
//
|
||||
// public static J getParent(J node) {
|
||||
// return node.getMarkers().findFirst(ParentMarker.class).map(m -> m.getParent()).orElse(null);
|
||||
// }
|
||||
|
||||
public static List<CompilationUnit> parse(JavaParser parser, Iterable<Path> sourceFiles) {
|
||||
InMemoryExecutionContext ctx = new InMemoryExecutionContext(e -> log.error("", e));
|
||||
ctx.putMessage(JavaParser.SKIP_SOURCE_SET_TYPE_GENERATION, true);
|
||||
List<CompilationUnit> cus = parser.parse(sourceFiles, null, ctx);
|
||||
return cus;
|
||||
// List<Result> results = new UpdateSourcePositions().doNext(new MarkParentRecipe()).run(cus);
|
||||
// return results.stream().map(r -> r.getAfter() == null ? r.getBefore() : r.getAfter()).map(CompilationUnit.class::cast).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<CompilationUnit> parseInputs(JavaParser parser, Iterable<Parser.Input> inputs) {
|
||||
InMemoryExecutionContext ctx = new InMemoryExecutionContext(e -> log.error("", e));
|
||||
ctx.putMessage(JavaParser.SKIP_SOURCE_SET_TYPE_GENERATION, true);
|
||||
List<CompilationUnit> cus = parser.parseInputs(inputs, null, ctx);
|
||||
return cus;
|
||||
// List<Result> results = new UpdateSourcePositions().doNext(new MarkParentRecipe()).run(cus);
|
||||
// return results.stream().map(r -> r.getAfter() == null ? r.getBefore() : r.getAfter()).map(CompilationUnit.class::cast).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static J.EnumValueSet getEnumValues(J.ClassDeclaration classDecl) {
|
||||
return classDecl.getBody().getStatements().stream()
|
||||
.filter(J.EnumValueSet.class::isInstance)
|
||||
.map(J.EnumValueSet.class::cast)
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public static List<J.VariableDeclarations> getFields(J.ClassDeclaration classDecl) {
|
||||
return classDecl.getBody().getStatements().stream()
|
||||
.filter(J.VariableDeclarations.class::isInstance)
|
||||
.map(J.VariableDeclarations.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<J.MethodDeclaration> getMethods(J.ClassDeclaration classDecl) {
|
||||
return classDecl.getBody().getStatements().stream()
|
||||
.filter(J.MethodDeclaration.class::isInstance)
|
||||
.map(J.MethodDeclaration.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static String getSimpleName(String fqName) {
|
||||
int idx = fqName.lastIndexOf('.');
|
||||
if (idx < fqName.length() - 1) {
|
||||
return fqName.substring(idx + 1);
|
||||
}
|
||||
return fqName;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static TreeVisitor<?, ExecutionContext> getVisitor(Recipe r) {
|
||||
try {
|
||||
Method m = Recipe.class.getDeclaredMethod("getVisitor");
|
||||
m.setAccessible(true);
|
||||
return (TreeVisitor<?, ExecutionContext>) m.invoke(r);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<TreeVisitor<J, ExecutionContext>> getAfterVisitors(TreeVisitor<J, ExecutionContext> visitor) {
|
||||
try {
|
||||
Method m = TreeVisitor.class.getDeclaredMethod("getAfterVisit");
|
||||
m.setAccessible(true);
|
||||
return (List<TreeVisitor<J, ExecutionContext>>) m.invoke(visitor);
|
||||
} catch (Exception e) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private static void makeVisitorNonTopLevel(JavaVisitor<ExecutionContext> visitor) {
|
||||
try {
|
||||
Field f = TreeVisitor.class.getDeclaredField("afterVisit");
|
||||
f.setAccessible(true);
|
||||
f.set(visitor, new ArrayList<>());
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
public static Recipe nodeRecipe(JavaVisitor<ExecutionContext> v, Predicate<J> condition) {
|
||||
return new NodeRecipe((JavaVisitor<ExecutionContext>) v, condition);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Recipe nodeRecipe(Recipe r, Predicate<J> condition) {
|
||||
return new NodeRecipe((JavaVisitor<ExecutionContext>) getVisitor(r), condition);
|
||||
}
|
||||
|
||||
private static class NodeRecipe extends Recipe {
|
||||
|
||||
private JavaVisitor<ExecutionContext> visitor;
|
||||
private Predicate<J> condition;
|
||||
|
||||
public NodeRecipe(JavaVisitor<ExecutionContext> visitor, Predicate<J> condition) {
|
||||
this.visitor = visitor;
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
return new JavaVisitor<>() {
|
||||
|
||||
@Override
|
||||
public J visit(Tree tree, ExecutionContext ctx) {
|
||||
J t = super.visit(tree, ctx);
|
||||
if (condition.test(t)) {
|
||||
makeVisitorNonTopLevel(visitor);
|
||||
t = visitor.visit(t, ctx, getCursor());
|
||||
for (TreeVisitor<J, ExecutionContext> v : getAfterVisitors(visitor)) {
|
||||
doAfterVisit(v);
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFin
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.ORAstUtils;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2022 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.rewrite;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.lsp4j.CreateFile;
|
||||
import org.eclipse.lsp4j.DeleteFile;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.TextDocumentEdit;
|
||||
import org.eclipse.lsp4j.TextEdit;
|
||||
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.WorkspaceEdit;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.openrewrite.Result;
|
||||
import org.openrewrite.shaded.jgit.diff.Edit;
|
||||
import org.openrewrite.shaded.jgit.diff.EditList;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.utils.JGitUtils;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.commons.util.text.IRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public class ORDocUtils {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ORDocUtils.class);
|
||||
|
||||
public static Optional<DocumentEdits> computeEdits(IDocument doc, Result result) {
|
||||
TextDocument newDoc = new TextDocument(null, LanguageId.PLAINTEXT, 0, result.getAfter().printAll());
|
||||
|
||||
EditList diff = JGitUtils.getDiff(result.getBefore().printAll(), newDoc.get());
|
||||
if (!diff.isEmpty()) {
|
||||
DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
for (Edit e : diff) {
|
||||
try {
|
||||
switch(e.getType()) {
|
||||
case DELETE:
|
||||
edits.delete(doc.getLineOffset(e.getBeginA()), getStartOfLine(doc, e.getEndA()));
|
||||
break;
|
||||
case INSERT:
|
||||
edits.insert(doc.getLineOffset(e.getBeginA()), newDoc.textBetween(newDoc.getLineOffset(e.getBeginB()), getStartOfLine(newDoc, e.getEndB())));
|
||||
break;
|
||||
case REPLACE:
|
||||
edits.replace(doc.getLineOfOffset(e.getBeginA()), getStartOfLine(doc, e.getEndA()), newDoc.textBetween(newDoc.getLineOffset(e.getBeginB()), getStartOfLine(newDoc, e.getEndB())));
|
||||
break;
|
||||
case EMPTY:
|
||||
break;
|
||||
}
|
||||
} catch (BadLocationException ex) {
|
||||
log.error("Diff conversion failed", ex);
|
||||
}
|
||||
}
|
||||
return Optional.of(edits);
|
||||
}
|
||||
return Optional.empty();
|
||||
|
||||
}
|
||||
|
||||
public static Optional<TextDocumentEdit> computeTextDocEdit(TextDocument doc, Result result) {
|
||||
TextDocument newDoc = new TextDocument(null, LanguageId.PLAINTEXT, 0, result.getAfter().printAll());
|
||||
|
||||
EditList diff = JGitUtils.getDiff(result.getBefore().printAll(), newDoc.get());
|
||||
if (!diff.isEmpty()) {
|
||||
TextDocumentEdit edit = new TextDocumentEdit();
|
||||
edit.setTextDocument(new VersionedTextDocumentIdentifier(doc.getUri(), doc.getVersion()));
|
||||
List<TextEdit> textEdits = new ArrayList<>();
|
||||
edit.setEdits(textEdits);
|
||||
for (Edit e : diff) {
|
||||
try {
|
||||
switch(e.getType()) {
|
||||
case DELETE:
|
||||
TextEdit textEdit = new TextEdit();
|
||||
int start = doc.getLineOffset(e.getBeginA());
|
||||
int end = getStartOfLine(doc, e.getEndA());
|
||||
textEdit.setRange(new Range(doc.toPosition(start), doc.toPosition(end)));
|
||||
textEdit.setNewText("");
|
||||
textEdits.add(textEdit);
|
||||
break;
|
||||
case INSERT:
|
||||
textEdit = new TextEdit();
|
||||
Position position = doc.toPosition(doc.getLineOffset(e.getBeginA()));
|
||||
textEdit.setRange(new Range(position, position));
|
||||
textEdit.setNewText(newDoc.textBetween(newDoc.getLineOffset(e.getBeginB()), getStartOfLine(newDoc, e.getEndB())));
|
||||
textEdits.add(textEdit);
|
||||
break;
|
||||
case REPLACE:
|
||||
textEdit = new TextEdit();
|
||||
start = doc.getLineOffset(e.getBeginA());
|
||||
end = getStartOfLine(doc, e.getEndA());
|
||||
textEdit.setRange(new Range(doc.toPosition(start), doc.toPosition(end)));
|
||||
textEdit.setNewText(newDoc.textBetween(newDoc.getLineOffset(e.getBeginB()), getStartOfLine(newDoc, e.getEndB())));
|
||||
textEdits.add(textEdit);
|
||||
break;
|
||||
case EMPTY:
|
||||
break;
|
||||
}
|
||||
} catch (BadLocationException ex) {
|
||||
log.error("Diff conversion failed", ex);
|
||||
}
|
||||
}
|
||||
return Optional.of(edit);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static Optional<TextDocumentEdit> computeSimpleTextDocEdit(TextDocument doc, Result result) {
|
||||
TextDocument newDoc = new TextDocument(null, LanguageId.PLAINTEXT, 0, result.getAfter().printAll());
|
||||
|
||||
EditList diff = JGitUtils.getDiff(result.getBefore().printAll(), newDoc.get());
|
||||
if (!diff.isEmpty()) {
|
||||
TextDocumentEdit edit = new TextDocumentEdit();
|
||||
edit.setTextDocument(new VersionedTextDocumentIdentifier(doc.getUri(), doc.getVersion()));
|
||||
TextEdit te = new TextEdit();
|
||||
te.setNewText(result.getAfter().printAll());
|
||||
try {
|
||||
te.setRange(new Range(new Position(0,0), doc.toPosition(doc.getLength())));
|
||||
} catch (BadLocationException e) {
|
||||
// ignore
|
||||
}
|
||||
edit.setEdits(List.of(te));
|
||||
return Optional.of(edit);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static int getStartOfLine(IDocument doc, int lineNumber) {
|
||||
IRegion lineInformation = doc.getLineInformation(lineNumber);
|
||||
if (lineInformation != null) {
|
||||
return lineInformation.getOffset();
|
||||
}
|
||||
if (lineNumber > 0) {
|
||||
IRegion currentLine = doc.getLineInformation(lineNumber - 1);
|
||||
return currentLine.getOffset() + currentLine.getLength();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static Optional<WorkspaceEdit> createWorkspaceEdit(Path absoluteProjectDir, SimpleTextDocumentService documents, List<Result> results) {
|
||||
if (results.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
WorkspaceEdit we = new WorkspaceEdit();
|
||||
we.setDocumentChanges(new ArrayList<>());
|
||||
for (Result result : results) {
|
||||
if (result.getBefore() == null) {
|
||||
String docUri = absoluteProjectDir.resolve(result.getAfter().getSourcePath()).toUri().toString();
|
||||
CreateFile ro = new CreateFile();
|
||||
ro.setUri(docUri);
|
||||
we.getDocumentChanges().add(Either.forRight(ro));
|
||||
|
||||
TextDocumentEdit te = new TextDocumentEdit();
|
||||
te.setTextDocument(new VersionedTextDocumentIdentifier(docUri, 0));
|
||||
Position cursor = new Position(0,0);
|
||||
te.setEdits(List.of(new TextEdit(new Range(cursor, cursor), result.getAfter().printAll())));
|
||||
we.getDocumentChanges().add(Either.forLeft(te));
|
||||
} else if (result.getAfter() == null) {
|
||||
String docUri = absoluteProjectDir.resolve(result.getBefore().getSourcePath()).toUri().toString();
|
||||
we.getDocumentChanges().add(Either.forRight(new DeleteFile(docUri)));
|
||||
} else {
|
||||
String docUri = absoluteProjectDir.resolve(result.getBefore().getSourcePath()).toUri().toString();
|
||||
TextDocument doc = documents.getLatestSnapshot(docUri);
|
||||
if (doc == null) {
|
||||
doc = new TextDocument(docUri, null, 0, result.getBefore().printAll());
|
||||
ORDocUtils.computeTextDocEdit(doc, result).ifPresent(te -> we.getDocumentChanges().add(Either.forLeft(te)));
|
||||
} else {
|
||||
ORDocUtils.computeTextDocEdit(doc, result).ifPresent(te -> we.getDocumentChanges().add(Either.forLeft(te)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return Optional.of(we);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -48,6 +48,8 @@ import org.springframework.ide.vscode.commons.java.IClasspathUtil;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.rewrite.ORDocUtils;
|
||||
import org.springframework.ide.vscode.commons.rewrite.maven.MavenProjectParser;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
|
||||
@@ -34,12 +34,12 @@ import org.openrewrite.Result;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.JavaCodeAction;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.ORCompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.ORDocUtils;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.RewriteRefactorings;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient.Client;
|
||||
import org.springframework.ide.vscode.commons.rewrite.ORDocUtils;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.text.IRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
|
||||
@@ -32,10 +32,10 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.ORCompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.RewriteRefactorings;
|
||||
import org.springframework.ide.vscode.boot.rewrite.java.ConvertAutowiredParameterIntoConstructorParameter;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.ConvertAutowiredParameterIntoConstructorParameter;
|
||||
import org.springframework.ide.vscode.commons.util.text.IRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
|
||||
@@ -29,12 +29,12 @@ import org.eclipse.lsp4j.WorkspaceEdit;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.openrewrite.java.MethodMatcher;
|
||||
import org.openrewrite.java.spring.NoRequestMappingAnnotation;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.ORAstUtils;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.ORCompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.RewriteRefactorings;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.ORAstUtils;
|
||||
import org.springframework.ide.vscode.commons.util.text.IRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
|
||||
@@ -23,12 +23,12 @@ import org.openrewrite.Recipe;
|
||||
import org.openrewrite.Result;
|
||||
import org.openrewrite.java.JavaVisitor;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.ORAstUtils;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.ORCompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.ORDocUtils;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixEdit;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixHandler;
|
||||
import org.springframework.ide.vscode.commons.rewrite.ORDocUtils;
|
||||
import org.springframework.ide.vscode.commons.rewrite.java.ORAstUtils;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.openrewrite.shaded.jgit.diff.EditList;
|
||||
import org.openrewrite.shaded.jgit.diff.HistogramDiff;
|
||||
import org.openrewrite.shaded.jgit.diff.RawText;
|
||||
import org.openrewrite.shaded.jgit.diff.RawTextComparator;
|
||||
|
||||
public class JGitUtils {
|
||||
|
||||
public static EditList getDiff(String txt1, String txt2) {
|
||||
RawText rt1 = new RawText(txt1.getBytes(StandardCharsets.UTF_8));
|
||||
RawText rt2 = new RawText(txt2.getBytes(StandardCharsets.UTF_8));
|
||||
EditList diffList = new EditList();
|
||||
diffList.addAll(new HistogramDiff().diff(RawTextComparator.DEFAULT, rt1, rt2));
|
||||
return diffList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2022 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.rewrite.java;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.openrewrite.Cursor;
|
||||
import org.openrewrite.ExecutionContext;
|
||||
import org.openrewrite.Recipe;
|
||||
import org.openrewrite.TreeVisitor;
|
||||
import org.openrewrite.java.AnnotationMatcher;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.JavaTemplate;
|
||||
import org.openrewrite.java.JavaVisitor;
|
||||
import org.openrewrite.java.RemoveAnnotationVisitor;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.Block;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.Empty;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.J.VariableDeclarations;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.openrewrite.java.tree.Statement;
|
||||
import org.openrewrite.java.tree.TypeTree;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.rewrite.ORAstUtils;
|
||||
|
||||
public class ConvertAutowiredParameterIntoConstructorParameter extends Recipe {
|
||||
|
||||
private String classFqName;
|
||||
private String fieldName;
|
||||
|
||||
public ConvertAutowiredParameterIntoConstructorParameter(String classFqName, String fieldName) {
|
||||
super();
|
||||
this.classFqName = classFqName;
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Convert autowired field into constructor parameter";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
return new JavaVisitor<ExecutionContext>() {
|
||||
|
||||
@Override
|
||||
public J visitClassDeclaration(ClassDeclaration classDecl, ExecutionContext p) {
|
||||
if (classFqName.equals(classDecl.getType().getFullyQualifiedName())) {
|
||||
return super.visitClassDeclaration(classDecl, p);
|
||||
}
|
||||
return classDecl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public J visitVariableDeclarations(VariableDeclarations multiVariable, ExecutionContext p) {
|
||||
Cursor blockCursor = getCursor().dropParentUntil(Block.class::isInstance);
|
||||
VariableDeclarations mv = multiVariable;
|
||||
if (blockCursor != null && blockCursor.getParent().getValue() instanceof ClassDeclaration
|
||||
&& multiVariable.getVariables().size() == 1
|
||||
&& fieldName.equals(multiVariable.getVariables().get(0).getName().printTrimmed())) {
|
||||
|
||||
mv = (VariableDeclarations) new RemoveAnnotationVisitor(new AnnotationMatcher("@" + Annotations.AUTOWIRED)).visit(multiVariable, p);
|
||||
doAfterVisit(new AddContructorParameterVisitor(classFqName, fieldName, multiVariable.getTypeExpression()));
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private static class AddContructorParameterVisitor extends JavaVisitor<ExecutionContext> {
|
||||
|
||||
private String classFqName;
|
||||
private String fieldName;
|
||||
private TypeTree type;
|
||||
|
||||
public AddContructorParameterVisitor(String classFqName, String fieldName, TypeTree type) {
|
||||
super();
|
||||
this.classFqName = classFqName;
|
||||
this.fieldName = fieldName;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public J visitClassDeclaration(ClassDeclaration classDecl, ExecutionContext p) {
|
||||
ClassDeclaration c = classDecl;
|
||||
if (classFqName.equals(c.getType().getFullyQualifiedName())) {
|
||||
List<MethodDeclaration> constructors = ORAstUtils.getMethods(c).stream().filter(m -> m.isConstructor()).collect(Collectors.toList());
|
||||
if (constructors.isEmpty()) {
|
||||
doAfterVisit(new AddConstructorVisitor(c.getSimpleName(), fieldName, type));
|
||||
} else {
|
||||
Optional<MethodDeclaration> autowiredConstructor = constructors.stream().filter(constr -> constr.getLeadingAnnotations().stream()
|
||||
.map(a -> TypeUtils.asFullyQualified(a.getType()))
|
||||
.filter(Objects::nonNull)
|
||||
.map(fq -> fq.getFullyQualifiedName())
|
||||
.filter(fqn -> Annotations.AUTOWIRED.equals(fqn))
|
||||
.findFirst()
|
||||
.isPresent()
|
||||
)
|
||||
.findFirst();
|
||||
if (autowiredConstructor.isPresent()) {
|
||||
// Autowired constructor found - add argument to it
|
||||
doAfterVisit(new AddMethodParameter(autowiredConstructor.get(), fieldName, type));
|
||||
} else {
|
||||
if (constructors.size() == 1) {
|
||||
doAfterVisit(new AddMethodParameter(constructors.get(0), fieldName, type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class AddConstructorVisitor extends JavaVisitor<ExecutionContext> {
|
||||
private String className;
|
||||
private String fieldName;
|
||||
private TypeTree type;
|
||||
|
||||
public AddConstructorVisitor(String className, String fieldName, TypeTree type) {
|
||||
this.className = className;
|
||||
this.fieldName = fieldName;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public J visitBlock(Block block, ExecutionContext p) {
|
||||
if (getCursor().getParent() != null) {
|
||||
Object n = getCursor().getParent().getValue();
|
||||
if (n instanceof ClassDeclaration) {
|
||||
ClassDeclaration classDecl = (ClassDeclaration) n;
|
||||
if (classDecl.getKind() == ClassDeclaration.Kind.Type.Class && className.equals(classDecl.getSimpleName())) {
|
||||
JavaTemplate.Builder template = JavaTemplate.builder(() -> getCursor(), ""
|
||||
+ classDecl.getSimpleName() + "(" + type.printTrimmed() + " " + fieldName + ") {\n"
|
||||
+ "this." + fieldName + " = " + fieldName + ";\n"
|
||||
+ "}\n"
|
||||
);
|
||||
FullyQualified fq = TypeUtils.asFullyQualified(type.getType());
|
||||
if (fq != null) {
|
||||
template.imports(fq.getFullyQualifiedName());
|
||||
maybeAddImport(fq);
|
||||
}
|
||||
Optional<Statement> firstMethod = block.getStatements().stream().filter(MethodDeclaration.class::isInstance).findFirst();
|
||||
if (firstMethod.isPresent()) {
|
||||
return block.withTemplate(template.build(), firstMethod.get().getCoordinates().before());
|
||||
} else {
|
||||
return block.withTemplate(template.build(), block.getCoordinates().lastStatement());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AddMethodParameter extends JavaIsoVisitor<ExecutionContext> {
|
||||
|
||||
private MethodDeclaration method;
|
||||
private String fieldName;
|
||||
private TypeTree type;
|
||||
|
||||
public AddMethodParameter(MethodDeclaration method, String fieldName, TypeTree type) {
|
||||
this.method = method;
|
||||
this.fieldName = fieldName;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodDeclaration visitMethodDeclaration(MethodDeclaration method, ExecutionContext p) {
|
||||
if (method == this.method) {
|
||||
String paramsStr = Stream.concat(method.getParameters().stream().filter(s -> !Empty.class.isInstance(s)).map(s -> s.printTrimmed()), Stream.of(type.printTrimmed() + " " + fieldName)).collect(Collectors.joining(", "));
|
||||
JavaTemplate.Builder paramsTemplate = JavaTemplate.builder(() -> getCursor(), paramsStr);
|
||||
JavaTemplate.Builder statementTemplate = JavaTemplate.builder(() -> getCursor(), "this." + fieldName + " = " + fieldName + ";\n");
|
||||
return method
|
||||
.withTemplate(paramsTemplate.build(), method.getCoordinates().replaceParameters())
|
||||
.withTemplate(statementTemplate.build(), method.getBody().getCoordinates().lastStatement());
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2022 VMware, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* VMware, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.rewrite.maven;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.openrewrite.ExecutionContext;
|
||||
import org.openrewrite.Option;
|
||||
import org.openrewrite.Recipe;
|
||||
import org.openrewrite.TreeVisitor;
|
||||
import org.openrewrite.internal.lang.Nullable;
|
||||
import org.openrewrite.maven.MavenVisitor;
|
||||
import org.openrewrite.xml.AddToTagVisitor;
|
||||
import org.openrewrite.xml.ChangeTagValueVisitor;
|
||||
import org.openrewrite.xml.RemoveContentVisitor;
|
||||
import org.openrewrite.xml.tree.Xml;
|
||||
|
||||
public class ChangeDependencyClassifier extends Recipe {
|
||||
|
||||
@Option(displayName = "Group",
|
||||
description = "The first part of a dependency coordinate 'com.google.guava:guava:VERSION'.",
|
||||
example = "com.google.guava")
|
||||
String groupId;
|
||||
|
||||
@Option(displayName = "Artifact",
|
||||
description = "The second part of a dependency coordinate 'com.google.guava:guava:VERSION'.",
|
||||
example = "guava")
|
||||
String artifactId;
|
||||
|
||||
/**
|
||||
* If null, strips the scope from an existing dependency.
|
||||
*/
|
||||
@Option(displayName = "New classifier",
|
||||
description = "Classifier to apply to specified Maven dependency. " +
|
||||
"May be omitted, which indicates that no classifier should be added and any existing scope be removed from the dependency.",
|
||||
example = "jar",
|
||||
required = false)
|
||||
@Nullable
|
||||
String newClassifier;
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Change Maven dependency classifier";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Add or alter the classifier of the specified dependency.";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
return new MavenVisitor<ExecutionContext>() {
|
||||
@Override
|
||||
public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) {
|
||||
if (isDependencyTag()) {
|
||||
if (groupId.equals(tag.getChildValue("groupId").orElse(getResolutionResult().getPom().getGroupId())) &&
|
||||
artifactId.equals(tag.getChildValue("artifactId").orElse(null))) {
|
||||
Optional<Xml.Tag> scope = tag.getChild("classifier");
|
||||
if (scope.isPresent()) {
|
||||
if (newClassifier == null) {
|
||||
doAfterVisit(new RemoveContentVisitor<>(scope.get(), false));
|
||||
} else if (!newClassifier.equals(scope.get().getValue().orElse(null))) {
|
||||
doAfterVisit(new ChangeTagValueVisitor<>(scope.get(), newClassifier));
|
||||
}
|
||||
} else if (newClassifier != null) {
|
||||
doAfterVisit(new AddToTagVisitor<>(tag, Xml.Tag.build("<classifier>" + newClassifier + "</classifier>")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitTag(tag, ctx);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(String groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public String getArtifactId() {
|
||||
return artifactId;
|
||||
}
|
||||
|
||||
public void setArtifactId(String artifactId) {
|
||||
this.artifactId = artifactId;
|
||||
}
|
||||
|
||||
public String getNewClassifier() {
|
||||
return newClassifier;
|
||||
}
|
||||
|
||||
public void setNewClassifier(String newClassifier) {
|
||||
this.newClassifier = newClassifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + Objects.hash(artifactId, groupId, newClassifier);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
ChangeDependencyClassifier other = (ChangeDependencyClassifier) obj;
|
||||
return Objects.equals(artifactId, other.artifactId) && Objects.equals(groupId, other.groupId)
|
||||
&& Objects.equals(newClassifier, other.newClassifier);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
---
|
||||
########################################################################################################################
|
||||
# SpringBoot 3_0
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
name: org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0
|
||||
displayName: Upgrade to Spring Boot 3.0 from 2.x
|
||||
description: 'Upgrade to Spring Boot 3.0 from prior 2.x version.'
|
||||
recipeList:
|
||||
# Upgrade 3.0.x from 2.x
|
||||
- org.openrewrite.maven.UpgradeDependencyVersion:
|
||||
groupId: org.springframework.boot
|
||||
artifactId: "*"
|
||||
newVersion: 3.0.0-SNAPSHOT
|
||||
trustParent: true
|
||||
- org.openrewrite.maven.UpgradeParentVersion:
|
||||
groupId: org.springframework.boot
|
||||
artifactId: spring-boot-starter-parent
|
||||
newVersion: 3.0.0-SNAPSHOT
|
||||
- org.openrewrite.maven.ChangePropertyValue:
|
||||
key: 'java.version'
|
||||
newValue: 17
|
||||
addIfMissing: true
|
||||
|
||||
- org.openrewrite.java.spring.data.UpgradeSpringData_3_0
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
########################################################################################################################
|
||||
# Spring Data 3.0
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
name: org.openrewrite.java.spring.data.UpgradeSpringData_3_0
|
||||
displayName: Upgrade to Spring Data 3.0
|
||||
description: 'Upgrade to Spring Data to 3.0 from any prior version.'
|
||||
recipeList:
|
||||
- org.springframework.ide.vscode.boot.rewrite.maven.ChangeDependencyClassifier:
|
||||
groupId: org.ehcache
|
||||
artifactId: ehcache
|
||||
newClassifier: jakarta
|
||||
- org.openrewrite.java.ChangePackage:
|
||||
oldPackageName: javax.persistence
|
||||
newPackageName: jakarta.persistence
|
||||
recursive: true
|
||||
- org.openrewrite.java.ChangePackage:
|
||||
oldPackageName: javax.validation
|
||||
newPackageName: jakarta.validation
|
||||
recursive: true
|
||||
- org.openrewrite.java.ChangePackage:
|
||||
oldPackageName: javax.xml.bind
|
||||
newPackageName: jakarta.xml.bind
|
||||
recursive: true
|
||||
|
||||
Reference in New Issue
Block a user