Description
The Json
methods that take IO streams should have their #close()
contract revisited.
The current situation is:
- The methods taking an
InputStream
orOutputStream
as an argument specify
"Upon a successful completion, the stream will be closed by this method." - No contract exits for the method taking a
Reader
orWriter
as an argument.
The issues with this are:
- If the method throws an exception it is not specified wether the streams are closed. This leaves it unclear whether the caller is responsible for calling
#close()
in these cases. - It is inconsistent that the byte oriented streams (
InputStream
/OutputStream
) are closed but the character oriented streams (Reader
/Writer
) are not.
Secondly, it is debatable whether Json
should call #close()
on the streams passed at all or whether that should be left to the caller. In my personal view it is idiomatic Java if the creator of a "resource", eg. IO stream, is responsible for its closing. Meaning generally calling code should look like this
try (var ioStream = createIoStream()) {
jsonb.toJson(object, ioStream);
}
This also integrates well with static analysis tools looking for resource leaks. If a user wants to keep the IO stream open, eg. to implement line oriented JSON, they can do this by simply not calling #close()
. Otherwise they would have to wrap the IO stream with one suppressing #close()
.
This is similar to C where in general code calling malloc
is also responsible for calling free
. Functions are in general not expected to clean up memory they are passed.
I could find no written rule or recommendation for this but the majority of the JDK code I can find does not close IO streams passed as an argument and leaves calling #close()
to the caller.
Examples from the JDK where calling #close()
is left to the caller:
Properties#load(Reader)
KeyStore#load(InputStream, char[])
javax.imageio.ImageIO#read(InputStream)
java.util.logging.LogManager#readConfiguration(InputStream)
javax.tools.Tool#run(InputStream, OutputStream, OutputStream, String...)
Examples from the JDK where #close()
is only called if the method returns without throwing an exception (strict interpretation of the current Jsonb
API contract)
Properties#loadFromXML(InputStream)
Examples from the JDK with no specified contract for calling #close()
, likely left to the caller:
javax.script.ScriptEngine#eval(Reader)
javax.xml.parsers.DocumentBuilder#parse(InputStream)
See also eclipse-ee4j/yasson#586