Given a class MyClass
using an internal closeable object, myCloseable
and providing a method getCloseable()
that returns it; Eclipse, if configured for this kind of closeable resource warnings, will systematically warn each time anyone calls getCloseable()
, saying that the closeable “may not be closed at this location”.
It is nice to have such warnings about resources that should be closed in case one forgets to close them, so I like to leave this check enabled. But in the just described scenario, it is quite annoying. In principle, it seems possible to mark the getCloseable()
method with an annotation, say, @existingCloseable
, telling the compiler that “it’s okay, I am just returning a resource that already existed, not creating a new one, thus the caller is not supposed to close it”.
Has such annotation been considered for adoption, by Eclipse or other IDEs? I couldn’t find discussions about it, so I suspect it has not. I wonder why: the pattern described in my example seems quite common and natural to me. Would the solution I consider with annotations not work, or have drawbacks I didn’t think of?
Example
Here is a (silly) example where the closeable is an OutputStream
. The method fromPath
produces a warning (if not suppressed) about s
being not closed, and I do not mind about this: this warning seems adequate and need to be suppressed only once. The annoying part, and the object of my question, is the warning that appears from the main
method: “Potential resource leak: 'target' may not be closed”. This warning will appear each time any user of my class will use getTarget
. I would like to disable it once and for all by annotating the method getTarget
in order to let the compiler know that this method returns a resource that the caller is not supposed to close. To the best of my knowledge, this is currently unsupported in Eclipse, and I wonder why.
public class MyWriter implements AutoCloseable {
public static void main(String[] args) throws Exception {
try (MyWriter w = MyWriter.fromPath(Path.of("out.txt"))) {
// …
OutputStream target = w.getTarget();
target.flush();
// …
}
}
@SuppressWarnings("resource")
public static MyWriter fromPath(Path target) throws IOException {
OutputStream s = Files.newOutputStream(target);
return new MyWriter(s);
}
private OutputStream target;
public OutputStream getTarget() {
return target;
}
private MyWriter(OutputStream target) {
this.target = target;
}
@Override
public void close() throws Exception {
target.close();
}
}
Discussion
I have edited my question, which originally asked whether my code can be modified to avoid the warning: I realized this is not really the question I am interested in, I am rather interested about the annotation based solution I thought about – sorry for this.
I realize this example is silly: with no further context, and as several answers correctly point out, it looks like I should rather wrap all methods of the stream and never return the stream to the outside world. Unfortunately, it is difficult to make this example realistic while also keeping it small.
One example is well known, however, so that I do not need to give it in detailed form here: in a servlet, one can call getOutputStream()
, and this is a typical case that illustrates my point: the method getOutputStream()
returns a stream that the caller does not need to close, but Eclipse will warn about a potential resource leak each and every time it is called (that is, in every servlet), which is a pain. It is also clear why the conceptors of this method did not simply wrap everything instead of returning the stream itself: it is useful to get an object that implements this well known interface, because it will then be possible to use it with other libraries and methods that expect to interact with a stream.
As another illustration of my point, imagine that the getCloseable()
method is used only internally, thus the method is package-visible instead of being public. The implementation of getCloseable()
might be complex, with inheritance playing a role, for example, so that it is not necessarily possible to replace this call with a simple access to the underlying field as in my small example. In such a case, it feels like not KISS at all to implement a whole wrapper instead of returning an already existing interface, just to keep the compiler happy.