jakartaee / jakartaee/jsonb-api

Jsonb close contract should be revisited

Open
#346 13 comments 3 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
95
Forks
41
Avg merge
1d 6h
Merged PRs (30d)
35

Description

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:
1. 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.
2. 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

```java
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 https://github.com/eclipse-ee4j/yasson/pull/586

Contributor guide

Open the contributing guide

Research direction

Start by reviewing the Json methods that accept InputStream, OutputStream, Reader, and Writer, then read the discussion linked from issue #346 and pull request #586. Done means reaching and documenting a clear, consistent close contract for these methods, with the affected API behavior reflected in the project’s validation.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.