Skip to content

Commit bb41637

Browse files
Remove inputstream finalizer (#245)
* recipe for replace finalize() from FileInputStream and FileOutputStream with close() * io fileinputstream and fileoutputstream finalize replacement recipe * license header * fixed recipe based on review comments * recipe formatting changes * Remove excess space * Fix various test compilation issues * Switch to JavaIsoVisitor and simplify implementation * Rename recipes * Simplify test cases as extends is not needed here --------- Co-authored-by: Tim te Beek <timtebeek@gmail.com> Co-authored-by: Tim te Beek <tim@moderne.io>
1 parent 4745b92 commit bb41637

File tree

3 files changed

+329
-0
lines changed

3 files changed

+329
-0
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.openrewrite.java.migrate.io;
18+
19+
import lombok.EqualsAndHashCode;
20+
import lombok.Value;
21+
import org.openrewrite.ExecutionContext;
22+
import org.openrewrite.Preconditions;
23+
import org.openrewrite.Recipe;
24+
import org.openrewrite.TreeVisitor;
25+
import org.openrewrite.java.JavaIsoVisitor;
26+
import org.openrewrite.java.MethodMatcher;
27+
import org.openrewrite.java.search.UsesJavaVersion;
28+
import org.openrewrite.java.search.UsesMethod;
29+
import org.openrewrite.java.tree.Expression;
30+
import org.openrewrite.java.tree.J;
31+
import org.openrewrite.java.tree.JavaType;
32+
import org.openrewrite.java.tree.TypeUtils;
33+
34+
import java.util.Collections;
35+
import java.util.Set;
36+
37+
@Value
38+
@EqualsAndHashCode(callSuper = true)
39+
public class ReplaceFileInOrOutputStreamFinalizeWithClose extends Recipe {
40+
41+
private static final String JAVA_IO_FILE_INPUT_STREAM = "java.io.FileInputStream";
42+
private static final String JAVA_IO_FILE_OUTPUT_STREAM = "java.io.FileOutputStream";
43+
private static final MethodMatcher METHOD_MATCHER = new MethodMatcher("java.lang.Object finalize()");
44+
45+
@Override
46+
public String getDisplayName() {
47+
return "Replace invocations of `finalize()` on `FileInputStream` and `FileOutputStream` with `close()`";
48+
}
49+
50+
@Override
51+
public String getDescription() {
52+
return "Replace invocations of the deprecated `finalize()` method on `FileInputStream` and `FileOutputStream` with `close()`.";
53+
}
54+
55+
@Override
56+
public Set<String> getTags() {
57+
return Collections.singleton("JDK-8212050");
58+
}
59+
60+
@Override
61+
public TreeVisitor<?, ExecutionContext> getVisitor() {
62+
return Preconditions.check(
63+
Preconditions.and(new UsesJavaVersion<>(9, 11), new UsesMethod<>(METHOD_MATCHER)),
64+
new JavaIsoVisitor<ExecutionContext>() {
65+
@Override
66+
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) {
67+
J.MethodInvocation mi = super.visitMethodInvocation(method, executionContext);
68+
if (METHOD_MATCHER.matches(mi)) {
69+
Expression select = mi.getSelect();
70+
JavaType type = select != null ? select.getType() : getCursor().firstEnclosingOrThrow(J.ClassDeclaration.class).getType();
71+
if (TypeUtils.isAssignableTo(JAVA_IO_FILE_INPUT_STREAM, type)
72+
|| TypeUtils.isAssignableTo(JAVA_IO_FILE_OUTPUT_STREAM, type)) {
73+
return mi.withName(mi.getName().withSimpleName("close"));
74+
}
75+
}
76+
return mi;
77+
}
78+
}
79+
);
80+
}
81+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
@NonNullApi
17+
@NonNullFields
18+
package org.openrewrite.java.migrate.io;
19+
20+
import org.openrewrite.internal.lang.NonNullApi;
21+
import org.openrewrite.internal.lang.NonNullFields;
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.openrewrite.java.migrate.io;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.openrewrite.DocumentExample;
21+
import org.openrewrite.test.RecipeSpec;
22+
import org.openrewrite.test.RewriteTest;
23+
24+
import static org.openrewrite.java.Assertions.java;
25+
import static org.openrewrite.java.Assertions.javaVersion;
26+
27+
class ReplaceFileInOrOutputStreamFinalizeWithCloseTest implements RewriteTest {
28+
29+
@Override
30+
public void defaults(RecipeSpec spec) {
31+
spec
32+
.recipe(new ReplaceFileInOrOutputStreamFinalizeWithClose())
33+
.allSources(s -> s.markers(javaVersion(11)));
34+
}
35+
36+
@Test
37+
@DocumentExample
38+
void removeFinalizerForFileInputStream() {
39+
//language=java
40+
rewriteRun(
41+
java(
42+
"""
43+
import java.io.FileInputStream;
44+
import java.io.IOException;
45+
46+
class FooBar {
47+
public void test() throws IOException {
48+
FileInputStream obj = new FileInputStream("foo");
49+
obj.finalize();
50+
}
51+
}
52+
""",
53+
"""
54+
import java.io.FileInputStream;
55+
import java.io.IOException;
56+
57+
class FooBar {
58+
public void test() throws IOException {
59+
FileInputStream obj = new FileInputStream("foo");
60+
obj.close();
61+
}
62+
}
63+
"""
64+
)
65+
);
66+
}
67+
68+
@Test
69+
void replaceDirectCall() {
70+
//language=java
71+
rewriteRun(
72+
java(
73+
"""
74+
import java.io.FileInputStream;
75+
import java.io.IOException;
76+
77+
class FooBar {
78+
public void test() throws IOException {
79+
new FileInputStream("foo").finalize();
80+
}
81+
}
82+
""",
83+
"""
84+
import java.io.FileInputStream;
85+
import java.io.IOException;
86+
87+
class FooBar {
88+
public void test() throws IOException {
89+
new FileInputStream("foo").close();
90+
}
91+
}
92+
"""
93+
)
94+
);
95+
}
96+
97+
@Test
98+
void replaceOnExtends() {
99+
//language=java
100+
rewriteRun(
101+
java(
102+
"""
103+
import java.io.FileInputStream;
104+
import java.io.IOException;
105+
106+
class FooBar extends FileInputStream {
107+
FooBar() throws IOException {
108+
super("foo");
109+
}
110+
public void test() throws IOException {
111+
new FooBar().finalize();
112+
}
113+
}
114+
""",
115+
"""
116+
import java.io.FileInputStream;
117+
import java.io.IOException;
118+
119+
class FooBar extends FileInputStream {
120+
FooBar() throws IOException {
121+
super("foo");
122+
}
123+
public void test() throws IOException {
124+
new FooBar().close();
125+
}
126+
}
127+
"""
128+
)
129+
);
130+
}
131+
132+
@Test
133+
void noChangeOnAnyOtherFinalize() {
134+
//language=java
135+
rewriteRun(
136+
java(
137+
"""
138+
import java.io.FileInputStream;
139+
import java.io.IOException;
140+
141+
class FooBar extends FileInputStream {
142+
FooBar() throws IOException {
143+
super("foo");
144+
}
145+
public void test() {
146+
new Object().finalize();
147+
}
148+
}
149+
"""
150+
)
151+
);
152+
}
153+
154+
@Test
155+
void noChangeWithCloseForFileInputStream() {
156+
//language=java
157+
rewriteRun(
158+
java(
159+
"""
160+
import java.io.FileInputStream;
161+
import java.io.IOException;
162+
163+
class FooBar extends FileInputStream {
164+
FooBar() throws IOException {
165+
super("foo");
166+
}
167+
public void test() throws IOException {
168+
FileInputStream obj = new FileInputStream("foo");
169+
obj.close();
170+
}
171+
}
172+
"""
173+
)
174+
);
175+
}
176+
177+
@Test
178+
void noFinalizerUsedForFileInputStream() {
179+
//language=java
180+
rewriteRun(
181+
java(
182+
"""
183+
import java.io.FileInputStream;
184+
import java.io.IOException;
185+
186+
class FooBar {
187+
public void test() throws IOException {
188+
FileInputStream obj = new FileInputStream("foo");
189+
obj.read();
190+
}
191+
}
192+
"""
193+
)
194+
);
195+
}
196+
197+
@Test
198+
void removeFinalizerForFileOutputStream() {
199+
//language=java
200+
rewriteRun(
201+
java(
202+
"""
203+
import java.io.FileOutputStream;
204+
import java.io.IOException;
205+
206+
class FooBar {
207+
public void test() throws IOException {
208+
FileOutputStream obj = new FileOutputStream("foo");
209+
obj.finalize();
210+
}
211+
}
212+
""",
213+
"""
214+
import java.io.FileOutputStream;
215+
import java.io.IOException;
216+
217+
class FooBar {
218+
public void test() throws IOException {
219+
FileOutputStream obj = new FileOutputStream("foo");
220+
obj.close();
221+
}
222+
}
223+
"""
224+
)
225+
);
226+
}
227+
}

0 commit comments

Comments
 (0)