The Json methods that take IO streams should have their #close() contract revisited.
The current situation is:
- The methods taking an
InputStream or OutputStream 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 or Writer 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
The
Jsonmethods that take IO streams should have their#close()contract revisited.The current situation is:
InputStreamorOutputStreamas an argument specify"Upon a successful completion, the stream will be closed by this method."
ReaderorWriteras an argument.The issues with this are:
#close()in these cases.InputStream/OutputStream) are closed but the character oriented streams (Reader/Writer) are not.Secondly, it is debatable whether
Jsonshould 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 thisThis 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
mallocis also responsible for callingfree. 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 currentJsonbAPI 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