Skip to content

Commit

Permalink
Update for rewrite 8.0.0 (#216)
Browse files Browse the repository at this point in the history
* Update for rewrite 8.0.0. Something about template generation is not working

* Update for rewrite 8.0.0

* Remove redundant `getEstimatedEffortPerOccurrence()` overloads

Migrate some more recipes.

* Migrate a few more recipes

Now using rewrite-static-analysis

* UpgradeJavaVersion migrated

* Update more stuff for rewrite 8.0

* Fix a few more failing tests

* Migrate `MaybeAddJakartaServletApi` recipe to Java

* Update to use new `JavaTemplate` API for context-free templates

* Migrate to new `Recipe#getInitialState(ExecutionContext)` API

* Minor OpenRewrite 8.0 updates

* fix failing test of UpgradeJavaVersion

* update a failing test of JavaxToJakartaTest

* `TreeVisitor#doAfterVisit(Recipe)` was removed

---------

Co-authored-by: Knut Wannheden <[email protected]>
Co-authored-by: Kun Li <[email protected]>
  • Loading branch information
3 people authored May 31, 2023
1 parent 9392540 commit 09f4212
Show file tree
Hide file tree
Showing 64 changed files with 708 additions and 1,020 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies {
implementation("org.openrewrite:rewrite-gradle")
implementation("org.openrewrite.recipe:rewrite-github-actions:$rewriteVersion")
implementation("org.openrewrite.recipe:rewrite-java-dependencies:$rewriteVersion")
implementation("org.openrewrite.recipe:rewrite-static-analysis:$rewriteVersion")
implementation("org.openrewrite.gradle.tooling:model:$rewriteVersion")

runtimeOnly("org.openrewrite:rewrite-java-8")
Expand Down
29 changes: 10 additions & 19 deletions src/main/java/org/openrewrite/java/migrate/AddJDeprScanPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,14 @@

import lombok.Getter;
import lombok.RequiredArgsConstructor;

import org.openrewrite.*;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.internal.StringUtils;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.maven.AddPlugin;
import org.openrewrite.maven.MavenIsoVisitor;
import org.openrewrite.maven.MavenVisitor;
import org.openrewrite.maven.tree.MavenResolutionResult;
import org.openrewrite.xml.tree.Xml;

import java.time.Duration;
import java.util.List;

/**
* This imperative recipe will add the jdeprscan plugin to a maven project. In the case of a multi-module project,
* this recipe will attempt to add the plugin to only the top level project.
Expand All @@ -52,19 +48,14 @@ public String getDescription() {
}

@Override
public Duration getEstimatedEffortPerOccurrence() {
return Duration.ofMinutes(5);
}

@Override
protected List<SourceFile> visit(List<SourceFile> before, ExecutionContext ctx) {
return ListUtils.map(before, s -> {
if ("pom.xml".equals(s.getSourcePath().toString())
&& s.getMarkers().findFirst(MavenResolutionResult.class).isPresent()) {
return (SourceFile) new AddJDeprScanPluginVisitor().visit(s, ctx);
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new MavenIsoVisitor<ExecutionContext>() {
@Override
public @Nullable Xml preVisit(Xml tree, ExecutionContext ctx) {
stopAfterPreVisit();
return new AddJDeprScanPluginVisitor().visit(tree, ctx);
}
return s;
});
};
}

private class AddJDeprScanPluginVisitor extends MavenVisitor<ExecutionContext> {
Expand All @@ -78,7 +69,7 @@ public Xml visitDocument(Xml.Document document, ExecutionContext ctx) {
String.format("<configuration>%n <release>%s</release>%n</configuration>",
StringUtils.isNullOrEmpty(getRelease()) ? "11" : getRelease()),
null,
null));
null).getVisitor());
return document;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
import org.openrewrite.xml.XPathMatcher;
import org.openrewrite.xml.tree.Xml;

import java.time.Duration;

/**
* This imperative recipe will add the maven jar plugin to a maven project. The maven jar plugin will be configured to suppress
* Illegal Reflection Warnings. In the case of a multi-module project, this recipe will attempt to add the plugin to only the top level project.
Expand Down Expand Up @@ -56,12 +54,7 @@ public String getDescription() {
}

@Override
public Duration getEstimatedEffortPerOccurrence() {
return Duration.ofMinutes(5);
}

@Override
protected TreeVisitor<?, ExecutionContext> getVisitor() {
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new MavenIsoVisitor<ExecutionContext>() {
@Override
public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) {
Expand All @@ -82,7 +75,7 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) {
" </archive>\n" +
"</configuration>";

doAfterVisit(new AddPlugin(groupId, artifactId, version, configuration, null, null));
doAfterVisit(new AddPlugin(groupId, artifactId, version, configuration, null, null).getVisitor());
}
}
return t;
Expand Down
93 changes: 51 additions & 42 deletions src/main/java/org/openrewrite/java/migrate/UpgradeJavaVersion.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
import org.openrewrite.*;
import org.openrewrite.gradle.IsBuildGradle;
import org.openrewrite.gradle.UpdateJavaCompatibility;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.groovy.tree.G;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.java.marker.JavaVersion;
import org.openrewrite.maven.MavenVisitor;
import org.openrewrite.xml.XPathMatcher;
Expand All @@ -41,9 +42,9 @@ public String getDisplayName() {
@Override
public String getDescription() {
return "Upgrade build plugin configuration to use the specified Java version. " +
"This recipe changes `java.toolchain.languageVersion` in `build.gradle(.kts)` of gradle projects, " +
"or maven-compiler-plugin target version and related settings. " +
"Will not downgrade if the version is newer than the specified version.";
"This recipe changes `java.toolchain.languageVersion` in `build.gradle(.kts)` of gradle projects, " +
"or maven-compiler-plugin target version and related settings. " +
"Will not downgrade if the version is newer than the specified version.";
}

@Option(displayName = "Java version",
Expand All @@ -52,47 +53,55 @@ public String getDescription() {
Integer version;

@Override
protected List<SourceFile> visit(List<SourceFile> before, ExecutionContext ctx) {
String newVersion = this.version.toString();
TreeVisitor<?, ExecutionContext> gradleUpdateJavaVersionVisitor = new UpdateJavaCompatibility(version, null, null).getVisitor();
MavenUpdateJavaVersionVisitor mavenUpdateVisitor = new MavenUpdateJavaVersionVisitor();

public TreeVisitor<?, ExecutionContext> getVisitor() {
String newVersion = version.toString();
Map<JavaVersion, JavaVersion> updatedMarkers = new HashMap<>();
return ListUtils.map(before, s -> {
Optional<JavaVersion> maybeJavaVersion = s.getMarkers().findFirst(JavaVersion.class);
if (!maybeJavaVersion.isPresent()) {
return s;
}

JavaVersion javaVersion = maybeJavaVersion.get();
if (javaVersion.getMajorVersion() >= version) {
return s;
}
return new TreeVisitor<Tree, ExecutionContext>() {
@Override
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
if (!(tree instanceof SourceFile)) {
return tree;
}
SourceFile source = (SourceFile) tree;

Optional<JavaVersion> maybeJavaVersion = source.getMarkers().findFirst(JavaVersion.class);
if (maybeJavaVersion.isPresent() && maybeJavaVersion.get().getMajorVersion() >= version) {
// No change if try to downgrade java version, or on same java version.
return source;
}

if (source instanceof G.CompilationUnit && new IsBuildGradle<ExecutionContext>().visit(source, ctx) != source) {
source = (SourceFile) new UpdateJavaCompatibility(version, null, null).getVisitor().visitNonNull(source, ctx);
} else if (source instanceof Xml.Document) {
source = (SourceFile) new MavenUpdateJavaVersionVisitor().visitNonNull(source, ctx);
}

if (maybeJavaVersion.isPresent()) {
source =
source.withMarkers(source.getMarkers().setByType(updatedMarkers.computeIfAbsent(maybeJavaVersion.get(),
m -> m.withSourceCompatibility(newVersion).withTargetCompatibility(newVersion))));
}

s = (SourceFile) mavenUpdateVisitor.visitNonNull(s, ctx);
if (new IsBuildGradle<ExecutionContext>().visit(s, ctx) != s) {
s = (SourceFile) gradleUpdateJavaVersionVisitor.visitNonNull(s, ctx);
return source;
}
s = s.withMarkers(s.getMarkers().setByType(updatedMarkers.computeIfAbsent(javaVersion,
m -> m.withSourceCompatibility(newVersion).withTargetCompatibility(newVersion))));
return s;
});
};
}

private static final List<String> JAVA_VERSION_XPATHS = Arrays.asList(
"/project/properties/java.version",
"/project/properties/jdk.version",
"/project/properties/javaVersion",
"/project/properties/jdkVersion",
"/project/properties/maven.compiler.source",
"/project/properties/maven.compiler.target",
"/project/properties/maven.compiler.release",
"/project/build/plugins/plugin[artifactId='maven-compiler-plugin']/configuration/source",
"/project/build/plugins/plugin[artifactId='maven-compiler-plugin']/configuration/target",
"/project/build/plugins/plugin[artifactId='maven-compiler-plugin']/configuration/release");
"/project/properties/java.version",
"/project/properties/jdk.version",
"/project/properties/javaVersion",
"/project/properties/jdkVersion",
"/project/properties/maven.compiler.source",
"/project/properties/maven.compiler.target",
"/project/properties/maven.compiler.release",
"/project/build/plugins/plugin[artifactId='maven-compiler-plugin']/configuration/source",
"/project/build/plugins/plugin[artifactId='maven-compiler-plugin']/configuration/target",
"/project/build/plugins/plugin[artifactId='maven-compiler-plugin']/configuration/release");

private static final List<XPathMatcher> JAVA_VERSION_XPATH_MATCHERS =
JAVA_VERSION_XPATHS.stream().map(XPathMatcher::new).collect(Collectors.toList());
JAVA_VERSION_XPATHS.stream().map(XPathMatcher::new).collect(Collectors.toList());


private class MavenUpdateJavaVersionVisitor extends MavenVisitor<ExecutionContext> {
Expand All @@ -102,13 +111,13 @@ public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) {

if (JAVA_VERSION_XPATH_MATCHERS.stream().anyMatch(matcher -> matcher.matches(getCursor()))) {
Optional<Float> maybeVersion = tag.getValue().flatMap(
value -> {
try {
return Optional.of(Float.parseFloat(value));
} catch (NumberFormatException e) {
return Optional.empty();
value -> {
try {
return Optional.of(Float.parseFloat(value));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
}
);

if (!maybeVersion.isPresent()) {
Expand Down
69 changes: 36 additions & 33 deletions src/main/java/org/openrewrite/java/migrate/UseJavaUtilBase64.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,20 @@
package org.openrewrite.java.migrate;

import com.fasterxml.jackson.annotation.JsonCreator;
import org.openrewrite.*;
import org.openrewrite.java.*;
import org.openrewrite.java.cleanup.UnnecessaryCatch;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.ChangeType;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.search.UsesType;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaSourceFile;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.marker.Markup;
import org.openrewrite.staticanalysis.UnnecessaryCatch;

import java.util.Base64;

Expand All @@ -39,15 +45,7 @@ public String getDisplayName() {
public String getDescription() {
//language=markdown
return "Prefer `java.util.Base64` instead of using `sun.misc` in Java 8 or higher. `sun.misc` is not exported " +
"by the Java module system and accessing this class will result in a warning in Java 11 and an error in Java 17.";
}

@Override
protected TreeVisitor<?, ExecutionContext> getSingleSourceApplicableTest() {
return Applicability.or(
new UsesType<>(sunPackage + ".BASE64Encoder", false),
new UsesType<>(sunPackage + ".BASE64Decoder", false)
);
"by the Java module system and accessing this class will result in a warning in Java 11 and an error in Java 17.";
}

public UseJavaUtilBase64(String sunPackage) {
Expand All @@ -60,34 +58,38 @@ public UseJavaUtilBase64() {
}

@Override
protected JavaVisitor<ExecutionContext> getVisitor() {

public TreeVisitor<?, ExecutionContext> getVisitor() {
TreeVisitor<?, ExecutionContext> check = Preconditions.or(
new UsesType<>(sunPackage + ".BASE64Encoder", false),
new UsesType<>(sunPackage + ".BASE64Decoder", false)
);
MethodMatcher base64EncodeMethod = new MethodMatcher(sunPackage + ".CharacterEncoder *(byte[])");
MethodMatcher base64DecodeBuffer = new MethodMatcher(sunPackage + ".CharacterDecoder decodeBuffer(String)");

MethodMatcher newBase64Encoder = new MethodMatcher(sunPackage + ".BASE64Encoder <constructor>()");
MethodMatcher newBase64Decoder = new MethodMatcher(sunPackage + ".BASE64Decoder <constructor>()");

return new JavaVisitor<ExecutionContext>() {
final JavaTemplate getDecoderTemplate = JavaTemplate.builder(this::getCursor, "Base64.getDecoder()")
return Preconditions.check(check, new JavaVisitor<ExecutionContext>() {
final JavaTemplate getDecoderTemplate = JavaTemplate.builder("Base64.getDecoder()")
.context(this::getCursor)
.imports("java.util.Base64")
.build();

final JavaTemplate encodeToString = JavaTemplate.builder(this::getCursor, "Base64.getEncoder().encodeToString(#{anyArray(byte)})")
final JavaTemplate encodeToString = JavaTemplate.builder("Base64.getEncoder().encodeToString(#{anyArray(byte)})")
.imports("java.util.Base64")
.build();

final JavaTemplate decode = JavaTemplate.builder(this::getCursor, "Base64.getDecoder().decode(#{any(String)})")
final JavaTemplate decode = JavaTemplate.builder("Base64.getDecoder().decode(#{any(String)})")
.imports("java.util.Base64")
.build();

@Override
public J visitJavaSourceFile(JavaSourceFile cu, ExecutionContext ctx) {
if(alreadyUsingIncompatibleBase64(cu)) {
public J visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
if (alreadyUsingIncompatibleBase64(cu)) {
return Markup.warn(cu, new IllegalStateException(
"Already using a class named Base64 other than java.util.Base64. Manual intervention required."));
}
JavaSourceFile c = (JavaSourceFile) super.visitJavaSourceFile(cu, ctx);
J.CompilationUnit c = (J.CompilationUnit) super.visitCompilationUnit(cu, ctx);

c = (J.CompilationUnit) new ChangeType(sunPackage + ".BASE64Encoder", "java.util.Base64$Encoder", true)
.getVisitor().visitNonNull(c, ctx);
Expand All @@ -100,20 +102,20 @@ public J visitJavaSourceFile(JavaSourceFile cu, ExecutionContext ctx) {
public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx);
if (base64EncodeMethod.matches(m) &&
("encode".equals(method.getSimpleName()) || "encodeBuffer".equals(method.getSimpleName()))) {
m = m.withTemplate(encodeToString, m.getCoordinates().replace(), method.getArguments().get(0));
("encode".equals(method.getSimpleName()) || "encodeBuffer".equals(method.getSimpleName()))) {
m = m.withTemplate(encodeToString, getCursor(), m.getCoordinates().replace(), method.getArguments().get(0));
if (method.getSelect() instanceof J.Identifier) {
m = m.withSelect(method.getSelect());
}
} else if (base64DecodeBuffer.matches(method)) {
m = m.withTemplate(decode, m.getCoordinates().replace(), method.getArguments().get(0));
m = m.withTemplate(decode, getCursor(), m.getCoordinates().replace(), method.getArguments().get(0));
if (method.getSelect() instanceof J.Identifier) {
m = m.withSelect(method.getSelect());
}
// Note: The sun.misc.CharacterDecoder#decodeBuffer throws an IOException, whereas the java
// Base64Decoder.decode does not throw a checked exception. If this recipe converts decode, we
// may need to remove the catch or completely unwrap a try/catch.
doAfterVisit(new UnnecessaryCatch(false));
doAfterVisit(new UnnecessaryCatch(false).getVisitor());
}
return m;
}
Expand All @@ -126,23 +128,24 @@ public J visitNewClass(J.NewClass newClass, ExecutionContext ctx) {
return c.withTemplate(
JavaTemplate.compile(this, "getEncoder",
() -> Base64.getEncoder()).build(),
getCursor(),
c.getCoordinates().replace()
);
} else if (newBase64Decoder.matches(c)) {
return c.withTemplate(getDecoderTemplate, c.getCoordinates().replace());
return c.withTemplate(getDecoderTemplate, getCursor(), c.getCoordinates().replace());
}
return c;
}
};
});
}

private boolean alreadyUsingIncompatibleBase64(JavaSourceFile cu) {
return cu.getClasses().stream().anyMatch(it -> "Base64".equals(it.getSimpleName())) ||
cu.getTypesInUse().getTypesInUse().stream()
.filter(it -> it instanceof JavaType.FullyQualified)
.map(JavaType.FullyQualified.class::cast)
.map(JavaType.FullyQualified::getFullyQualifiedName)
.filter(it -> !"java.util.Base64".equals(it))
.anyMatch(it -> it.endsWith(".Base64"));
cu.getTypesInUse().getTypesInUse().stream()
.filter(it -> it instanceof JavaType.FullyQualified)
.map(JavaType.FullyQualified.class::cast)
.map(JavaType.FullyQualified::getFullyQualifiedName)
.filter(it -> !"java.util.Base64".equals(it))
.anyMatch(it -> it.endsWith(".Base64"));
}
}
Loading

0 comments on commit 09f4212

Please sign in to comment.