tl;dr:我想告诉Eclipse,我的辅助方法closedown(AutoCloseable... aaa)
实际上关闭了它给出的所有AutoCloseable对象。
关于细节:
我继承了一组大型Java应用程序,其中包含大量写得很差的DAO类。太多的方法执行一长串的SELECT/INSERT/UPDATE查询,重用PreparedStatement和ResultSet对象等等,* 有时 * 在再次重用它们之前关闭资源;Eclipse产生了数百个“资源泄漏:'rs' is not closed at this location”警告。
作为代码净化过程的一部分,为了使清理更容易,我编写了一个辅助方法closedown(AutoCloseable... aaa)
,它只是为每个给定对象执行if (a!=null) a.close();
;这个一行程序可以很容易地插入到任何conn.prepareStatement()
调用之前等等…
...但是现在Eclipse产生的“潜在资源泄漏:'ps' may not be closed at this location”spurious info messages.我 * 正在 * 正确地放置closedown()调用(包括在那些类中的每一个try块的finally块中),所以问题只是Eclipse不能从自己的源代码分析中判断出事情是好的。
这些应用程序在Java 7上运行(迁移到Java 8终于开始了)。这意味着我可以使用try-with-resources,但是... Statement,PreparedStatement和ResultSet对象的大量重用使得这种策略只适用于Connection对象。出于明显的原因,我不想使用@SuppressWarnings标记。相反,我希望能够告诉Eclipse发送给closedown()的AutoCloseable对象确实是关闭的,这样Eclipse就知道不会产生那些虚假的消息。
结果JSR 305最终失败了,然而,像@WillClose
这样的东西很适合我的需要(@WillNotClose
用于处理某些Connection参数!)那么,如何在Eclipse上实现这个注解呢?
- ——————————————————————————————————————————-
编辑:根据howlger的要求,这是一个最小的可复制示例。考虑这个实用程序类:
package misc.util;
public class Closer {
public static void closedown(final AutoCloseable... objects) {
if (objects != null) {
for (AutoCloseable o : objects) {
try {
if (o != null) {
o.close();
}
} catch (Exception e) {
System.err.println("Unexpected error when trying to close object: '" + o.toString() + "'.");
}
}
}
}
public static java.sql.Connection getConnection() { return null; }
}
这个“主”类:
package misc.demo;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import static misc.util.Closer.closedown;
import static misc.util.Closer.getConnection;
public class Example {
public static void main(String[] args) {
PreparedStatement ps = null;
ResultSet rs = null;
try (Connection conn = getConnection();) { // Eclipse doesn't notice a null object is coming (doesn't matter for our purposes now).
ps = conn.prepareStatement("select 'a' from dual");
rs = ps.executeQuery();
ps = conn.prepareStatement("select 'b' from dual"); // Warning: "Resource leak: 'ps' is not closed at this location"
rs = ps.executeQuery();
closedown(rs, ps);
ps = conn.prepareStatement("select 'c' from dual"); // Info: "Potential resource leak: 'ps' may not be closed at this location"
rs = ps.executeQuery(); // ························ // Info: "Potential resource leak: 'rs' may not be closed at this location"
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
ps = conn.prepareStatement("select 'd' from dual"); // Eclipse knows everything is fine here (unlike above).
rs = ps.executeQuery(); // ························ // Eclipse knows everything is fine here (unlike above).
} catch (Exception e) {
e.printStackTrace();
} finally {
closedown(rs, ps);
}
}
}
Eclipse在“select 'b'”行中发现了一个真正的资源泄漏(不应该被抑制的资源泄漏!)。
Eclipse还在“select 'c'”行中发现了两个潜在的泄漏,这只会增加噪音,因为我们知道closedown()已经处理了它们。一种方法是通过添加@WillClose注解(如果它存在……但它不存在)来告诉Eclipse。
1条答案
按热度按时间8cdiaqws1#
您可以使用随Checker Framework一起分发的资源泄漏检查器。资源泄漏检查器在编译时保证程序在对象被释放之前完成每个对象的必须调用义务。
这个工具不使用JSR 305注解,但它自己的注解更通用(它们不仅仅是关闭资源)。例如,对于
close()
方法,您将使用@MustCall("close")
(尽管您不需要,因为该工具附带了JDK注解),并且您将使用@EnsuresCalledMethods("close")
而不是@WillClose
,并且@NotOwning
而不是@WillNotClose
。它没有内置到Eclipse中,而是一个可以从Eclipse运行的独立工具。
如果适用,您应该使用Java的try-with-resources语句,资源泄漏检查器将帮助您在适当的情况下使用它。但是,try-with-resources只能关闭实现
java.lang.AutoCloseable
接口的资源类型,并且它不能处理跨多个过程的常见资源使用模式。资源泄漏检查器在这些情况下特别有用。