Skip to content

Commit

Permalink
Remove finalizer from classes in util.zip (#233)
Browse files Browse the repository at this point in the history
* 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 <tim@moderne.io>
  • Loading branch information
satvika-eda and timtebeek committed Jun 26, 2023
1 parent 4241d47 commit 927b01d
Show file tree
Hide file tree
Showing 2 changed files with 373 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright 2023 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.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<?, ExecutionContext> 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<ExecutionContext>() {
@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<J> 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);
}
});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
/*
* Copyright 2023 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.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));
}
}

0 comments on commit 927b01d

Please sign in to comment.