From 927b01de8e8fd8f1ab68bc934a860043e0eba441 Mon Sep 17 00:00:00 2001 From: Satvika Eda Date: Mon, 26 Jun 2023 17:52:12 +0530 Subject: [PATCH] Remove finalizer from classes in util.zip (#233) * recipe for removing finalizer from ZipFile, Deflater and Inflater * adding license header to recipe * Format textblocks and resolve ZipFile compilation issues * Format RemoveFinalizerFromZip * Add tests to show or prevent implementation issues * added preconditions and refactored the logic * fixing finalize removal recipe to handle edge cases * Apply formatter * Only override visitMethodInvocation Support case of empty select by looking at surrounding class declaration Use method matcher instead of String comparison to find finalize calls Use TypeUtils instead of String comparison to find extending classes * Also removeCallsToSelfFinalize * Limit to Java 12+ --------- Co-authored-by: Tim te Beek --- .../migrate/util/RemoveFinalizerFromZip.java | 101 +++++++ .../util/RemoveFinalizerFromZipTest.java | 272 ++++++++++++++++++ 2 files changed, 373 insertions(+) create mode 100644 src/main/java/org/openrewrite/java/migrate/util/RemoveFinalizerFromZip.java create mode 100644 src/test/java/org/openrewrite/java/migrate/util/RemoveFinalizerFromZipTest.java diff --git a/src/main/java/org/openrewrite/java/migrate/util/RemoveFinalizerFromZip.java b/src/main/java/org/openrewrite/java/migrate/util/RemoveFinalizerFromZip.java new file mode 100644 index 0000000000..145d862cca --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/util/RemoveFinalizerFromZip.java @@ -0,0 +1,101 @@ +/* + * 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.java.migrate.util; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaVisitor; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesJavaVersion; +import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.TypeUtils; + +import java.util.List; + +@Value +@EqualsAndHashCode(callSuper = true) +public class RemoveFinalizerFromZip extends Recipe { + + private static final String JAVA_UTIL_ZIP_DEFLATER = "java.util.zip.Deflater"; + private static final String JAVA_UTIL_ZIP_INFLATER = "java.util.zip.Inflater"; + private static final String JAVA_UTIL_ZIP_ZIP_FILE = "java.util.zip.ZipFile"; + + private static final MethodMatcher METHOD_MATCHER = new MethodMatcher("java.lang.Object finalize()"); + + @Override + public String getDisplayName() { + return "Remove invocations of deprecated invocations from Deflater, Inflater, ZipFile "; + } + + @Override + public String getDescription() { + return "Remove invocations of finalize() deprecated invocations from Deflater, Inflater, ZipFile."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(Preconditions.and( + new UsesJavaVersion<>(12), + Preconditions.or( + new UsesType<>(JAVA_UTIL_ZIP_DEFLATER, false), + new UsesType<>(JAVA_UTIL_ZIP_INFLATER, false), + new UsesType<>(JAVA_UTIL_ZIP_ZIP_FILE, false))), + new JavaVisitor() { + @Override + public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) { + J.MethodInvocation mi = (J.MethodInvocation) super.visitMethodInvocation(method, executionContext); + + if (METHOD_MATCHER.matches(mi)) { + Expression select = mi.getSelect(); + if (select == null) { + J.ClassDeclaration cd = getCursor().firstEnclosingOrThrow(J.ClassDeclaration.class); + if (shouldRemoveFinalize(cd.getType())) { + return null; + } + } else { + if (shouldRemoveFinalize(select.getType())) { + // Retain any side effects preceding the finalize() call + List sideEffects = select.getSideEffects(); + if (sideEffects.isEmpty()) { + return null; + } + if (sideEffects.size() == 1) { + return sideEffects.get(0).withPrefix(mi.getPrefix()); + } + } + } + } + + return mi; + } + + private boolean shouldRemoveFinalize(JavaType type) { + return TypeUtils.isAssignableTo(JAVA_UTIL_ZIP_DEFLATER, type) + || TypeUtils.isAssignableTo(JAVA_UTIL_ZIP_INFLATER, type) + || TypeUtils.isAssignableTo(JAVA_UTIL_ZIP_ZIP_FILE, type); + } + }); + } + +} \ No newline at end of file diff --git a/src/test/java/org/openrewrite/java/migrate/util/RemoveFinalizerFromZipTest.java b/src/test/java/org/openrewrite/java/migrate/util/RemoveFinalizerFromZipTest.java new file mode 100644 index 0000000000..425fcf41ab --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/util/RemoveFinalizerFromZipTest.java @@ -0,0 +1,272 @@ +/* + * 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.java.migrate.util; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.*; + +class RemoveFinalizerFromZipTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new RemoveFinalizerFromZip()).allSources(s -> s.markers(javaVersion(12))); + } + + @Test + @DocumentExample + void removeFinalizerForInflater() { + //language=java + rewriteRun(java(""" + import java.util.zip.Inflater; + + class FooInflater extends Inflater { + public void test() { + FooInflater obj = new FooInflater(); + obj.finalize(); + } + } + """, """ + import java.util.zip.Inflater; + + class FooInflater extends Inflater { + public void test() { + FooInflater obj = new FooInflater(); + } + } + """)); + } + + @Test + void removeCallsToSelfFinalize() { + //language=java + rewriteRun(java(""" + import java.util.zip.Inflater; + + class FooBar extends Inflater { + public void test() { + finalize(); + } + } + """, """ + import java.util.zip.Inflater; + + class FooBar extends Inflater { + public void test() { + } + } + """)); + } + + @Test + void removeCallsToThisFinalize() { + //language=java + rewriteRun(java(""" + import java.util.zip.Inflater; + + class FooBar extends Inflater { + public void test() { + this.finalize(); + } + } + """, """ + import java.util.zip.Inflater; + + class FooBar extends Inflater { + public void test() { + } + } + """)); + } + + @Test + void removeWhileKeepingSideEffects() { + //language=java + rewriteRun(java(""" + import java.util.zip.Inflater; + + class FooBar extends Inflater { + public void test() { + new FooBar().finalize(); + } + } + """, """ + import java.util.zip.Inflater; + + class FooBar extends Inflater { + public void test() { + new FooBar(); + } + } + """)); + } + + @Test + void noChangeWithFinalizeOnObject() { + //language=java + rewriteRun(java(""" + import java.util.zip.Inflater; + + class FooBar extends Inflater { + public void test() { + new Object().finalize(); + } + } + """)); + } + + @Test + void noChangeWithoutFinalizerForInflater() { + //language=java + rewriteRun(java(""" + import java.util.zip.Inflater; + + class FooBar extends Inflater { + public void test() { + FooBar obj = new FooBar(); + } + } + """)); + } + + @Test + void removeFinalizerForDeflater() { + //language=java + rewriteRun(java(""" + import java.util.zip.Deflater; + + class FooBar extends Deflater { + public void test() { + FooBar obj = new FooBar(); + obj.finalize(); + } + } + """, """ + import java.util.zip.Deflater; + + class FooBar extends Deflater { + public void test() { + FooBar obj = new FooBar(); + } + } + """)); + } + + @Test + void noChangeWithoutFinalizerForDeflater() { + //language=java + rewriteRun(java(""" + import java.util.zip.Deflater; + + class FooBar extends Deflater { + public void test() { + FooBar obj = new FooBar(); + } + } + """)); + } + + @Test + void removeFinalizerForZipFile() { + //language=java + rewriteRun(java(""" + import java.util.zip.ZipFile; + + class FooBar extends ZipFile { + FooBar(){ + super(""); + } + public void test() { + FooBar obj = new FooBar(); + obj.finalize(); + } + } + """, """ + import java.util.zip.ZipFile; + + class FooBar extends ZipFile { + FooBar(){ + super(""); + } + public void test() { + FooBar obj = new FooBar(); + } + } + """)); + } + + @Test + void noChangeWithoutFinalizerForZipFile() { + //language=java + rewriteRun(java(""" + import java.util.zip.ZipFile; + + class FooBar extends ZipFile { + FooBar(){ + super(""); + } + public void test() { + FooBar obj = new FooBar(); + } + } + """)); + } + + @Test + void noChangeWithoutExtends() { + //language=java + rewriteRun(java(""" + class FooBar { + public void test() { + new Object().finalize(); + } + } + """)); + } + + @Test + void noChangeWithoutExtendsOrSelect() { + //language=java + rewriteRun(java(""" + class FooBar { + public void test() { + finalize(); + } + } + """)); + } + + @Test + void noChangeOnJava11() { + //language=java + rewriteRun(version(java(""" + import java.util.zip.ZipFile; + + class FooBar extends ZipFile { + FooBar(){ + super(""); + } + public void test() { + finalize(); + } + } + """), 11)); + } +}