如果JsonGenerator是在ByteArrayOutputStream之上创建的,那么它是否有意义

时间:2015-02-20 11:36:59

标签: java json glassfish

假设我想创建JSON并使用Java JSON Streaming API将其存储在String中。为此,我在它上面创建了ByteArrayOutputStream(BAOS)和JsonGenerator。

ByteArrayOutputStream collector = new ByteArrayOutputStream();
JsonGenerator jsonGenerator = Json.createGenerator(collector);

过了一会儿,当我完成它之后,我从BAOS中取出String并且应该释放所有资源。如下来自BAOS close 方法实现

public void close() throws IOException {
}

它什么都不做。然而,JsonGenerator的 close 方法不仅会关闭底层流,还会刷新缓冲区并回收缓冲池(坦率地说,我不知道后者是什么意思)。
我怀疑JsonGenerator在将数据写入BAOS时会缓冲数据。但是,我需要花一些时间进一步调查,所以我希望有人已经知道:关闭发电机是否有意义,或者不是。 注意
我使用了javax.json的Glassfish实现。

2 个答案:

答案 0 :(得分:2)

确定。我检查了JsonGeneratorImpl源代码。我不得不说我真的需要关闭它。首先,JsonGeneratorImpl从BufferPoolImpl接收缓冲区:

public final char[] take() {
    char[] t = (char[])getQueue().poll();
    if (t == null)
        return new char[4096];
    return t;
}

当我们打电话给关闭时,我们把它放回去了:

public final void recycle(char[] t)
{
    getQueue().offer(t);
}

如果你像我所说的那样创建jsonGenerator,那就没有多大意义了:

JsonGenerator jsonGenerator = Json.createGenerator(collector);

因为在这种情况下,每个新创建的生成器将使用自己的JsonProvider实例,以及它自己的缓冲池实例,当我完成使用生成器时,它将由GC收集。因此,最好创建JsonGeneratorFactory,因为此工厂创建的所有生成器都将共享公共缓冲池。是的 - 在这种情况下,最后关闭发电机真的更好 关闭生成器的另一个原因是 close 方法调用 flushBuffer 方法。是的,无论输出流类型如何,生成器都使用缓冲区:

void writeChar(char c) {
    if (this.len >= this.buf.length) {
        flushBuffer();
    }
    this.buf[(this.len++)] = c;
}

所以最终答案是。最终关闭JsonGenerator总是有意义的 的更新
正如@StephenC正确地指出的那样,关闭它还有另一个原因,因为它强制检查未完成的JSON:

if ((this.currentContext.scope != Scope.IN_NONE) || (this.currentContext.first)) {
  throw new JsonGenerationException(JsonMessages.GENERATOR_INCOMPLETE_JSON());
}

答案 1 :(得分:1)

我认为在资源完成时关闭资源总是有意义的,无论底层实现如何。没有什么说未来的实施不会改变,如果处理不当,可能会导致资源泄漏。

如果您使用的是Java 7或更高版本,则这两个类都会实现Closeable。为什么不把它们放在试用资源中呢?

try (ByteArrayOutputStream collector = new ByteArrayOutputStream(); 
    JsonGenerator jsonGenerator = Json.createGenerator(collector)) {
    // your implementation here  
} catch (IOException e) {
    // handle exceptions
}

不需要Java 7样板前代码,您可以确保所有资源都已正确关闭。