From 933f33c4d2c58caec1ce579ec6a4a192f40a9b28 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Wed, 22 Feb 2017 21:20:54 -0800 Subject: [PATCH] Minor changes wrt #17 to use recyclable buffers --- release-notes/CREDITS | 4 + release-notes/VERSION | 2 + .../fasterxml/jackson/core/JsonGenerator.java | 10 +- .../jackson/core/base/GeneratorBase.java | 2 +- .../jackson/core/json/UTF8JsonGenerator.java | 20 +-- .../core/json/WriterBasedJsonGenerator.java | 114 +++++++++--------- 6 files changed, 75 insertions(+), 77 deletions(-) diff --git a/release-notes/CREDITS b/release-notes/CREDITS index e2b3d3d215..59c507e1e2 100644 --- a/release-notes/CREDITS +++ b/release-notes/CREDITS @@ -122,3 +122,7 @@ Brad Hess (bdhess@github) (2.9.0) * Reported #325: `DataInput` backed parser should handle `EOFException` at end of doc (2.9.0) + +Logan Widick (uhhhh2@github) + * Contributed #17: Add 'JsonGenerator.writeString(Reader r, int charLength)' + (2.9.0) diff --git a/release-notes/VERSION b/release-notes/VERSION index 615c6498a6..c933f8812e 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -16,6 +16,8 @@ JSON library. 2.9.0 (not yet released) +#17: Add 'JsonGenerator.writeString(Reader r, int charLength)' + (constributed by Logan W) #304: Optimize `NumberOutput.outputLong()` method #312: Add `JsonProcessingException.clearLocation()` to allow clearing possibly security-sensitive information diff --git a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java index 02401d5444..c99cc23801 100644 --- a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java +++ b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java @@ -4,10 +4,6 @@ */ package com.fasterxml.jackson.core; -import com.fasterxml.jackson.core.JsonParser.NumberType; -import com.fasterxml.jackson.core.io.CharacterEscapes; -import com.fasterxml.jackson.core.util.VersionUtil; - import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; @@ -15,6 +11,10 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import com.fasterxml.jackson.core.JsonParser.NumberType; +import com.fasterxml.jackson.core.io.CharacterEscapes; +import com.fasterxml.jackson.core.util.VersionUtil; + import static com.fasterxml.jackson.core.JsonTokenId.*; /** @@ -941,6 +941,8 @@ public void writeArray(double[] array, int offset, int length) throws IOExceptio * If the reader is null, then write a null. * If len is < 0, then write all contents of the reader. * Otherwise, write only len characters. + * + * @since 2.9 */ public abstract void writeString(Reader reader, int len) throws IOException; diff --git a/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java b/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java index 128a4d7ae5..464e528429 100644 --- a/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java +++ b/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java @@ -341,7 +341,7 @@ public int writeBinary(Base64Variant b64variant, InputStream data, int dataLengt return 0; } - @Override + @Override // since 2.9 public void writeString(Reader reader, int len) throws IOException { // Let's implement this as "unsupported" to make it easier to add new parser impls _reportUnsupportedOperation(); diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java index 2ae970a192..a0b8c655ae 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java @@ -1,18 +1,15 @@ package com.fasterxml.jackson.core.json; +import java.io.*; +import java.math.BigDecimal; +import java.math.BigInteger; + import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.io.CharTypes; import com.fasterxml.jackson.core.io.CharacterEscapes; import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.core.io.NumberOutput; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.math.BigDecimal; -import java.math.BigInteger; - public class UTF8JsonGenerator extends JsonGeneratorImpl { @@ -476,7 +473,6 @@ public void writeString(Reader reader, int len) throws IOException { int toRead = (len >= 0) ? len : Integer.MAX_VALUE; - //TODO: Check that this use is OK final char[] buf = _charBuffer; //Add leading quote @@ -486,11 +482,8 @@ public void writeString(Reader reader, int len) throws IOException { _outputBuffer[_outputTail++] = _quoteChar; //read - while(toRead > 0){ + while (toRead > 0){ int toReadNow = Math.min(toRead, buf.length); - if(toRead <= 0){ - break; - } int numRead = reader.read(buf, 0, toReadNow); if(numRead <= 0){ break; @@ -499,7 +492,6 @@ public void writeString(Reader reader, int len) throws IOException { _flushBuffer(); } _writeStringSegments(buf, 0, numRead); - //decrease tracker toRead -= numRead; } @@ -510,7 +502,7 @@ public void writeString(Reader reader, int len) throws IOException { } _outputBuffer[_outputTail++] = _quoteChar; - if(toRead > 0 && len >= 0){ + if (toRead > 0 && len >= 0){ _reportError("Didn't read enough from reader"); } } diff --git a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java index 149146ddf6..ebf782af6a 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java +++ b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java @@ -1,18 +1,15 @@ package com.fasterxml.jackson.core.json; +import java.io.*; +import java.math.BigDecimal; +import java.math.BigInteger; + import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.io.CharTypes; import com.fasterxml.jackson.core.io.CharacterEscapes; import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.core.io.NumberOutput; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.Writer; -import java.math.BigDecimal; -import java.math.BigInteger; - /** * {@link JsonGenerator} that outputs JSON content using a {@link java.io.Writer} * which handles character encoding. @@ -75,23 +72,20 @@ public class WriterBasedJsonGenerator */ protected char[] _entityBuffer; - /** - * Intermediate buffer in which characters of a String are copied - * before being encoded. - */ - protected char[] _charBuffer; - - /** - * Length of _charBuffer - */ - protected final int _charBufferLength; - /** * When custom escapes are used, this member variable is used * internally to hold a reference to currently used escape */ protected SerializableString _currentEscape; + /** + * Intermediate buffer in which characters of a String are copied + * before being encoded. + * + * @since 2.9 + */ + protected char[] _charBuffer; + /* /********************************************************** /* Life-cycle @@ -105,16 +99,14 @@ public WriterBasedJsonGenerator(IOContext ctxt, int features, _writer = w; _outputBuffer = ctxt.allocConcatBuffer(); _outputEnd = _outputBuffer.length; - _charBuffer = new char[_outputBuffer.length]; - _charBufferLength = _charBuffer.length; } - + /* /********************************************************** /* Overridden configuration, introspection methods /********************************************************** */ - + @Override public Object getOutputTarget() { return _writer; @@ -395,46 +387,38 @@ public void writeString(Reader reader, int len) throws IOException { _verifyValueWrite(WRITE_STRING); if (reader == null) { _reportError("null reader"); - } else { - int toRead = (len >= 0) ? len : Integer.MAX_VALUE; - - //TODO: Check that this use is OK - final char[] buf = _charBuffer; - - //Add leading quote - if ((_outputTail + len) >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - - //read - while (toRead > 0) { - int toReadNow = Math.min(toRead, buf.length); - if (toRead <= 0) { - break; - } - int numRead = reader.read(buf, 0, toReadNow); - if (numRead <= 0) { - break; - } - if ((_outputTail + len) >= _outputEnd) { - _flushBuffer(); - } - _writeString(buf, 0, numRead); + } + int toRead = (len >= 0) ? len : Integer.MAX_VALUE; + final char[] buf = _allocateCopyBuffer(); + //Add leading quote + if ((_outputTail + len) >= _outputEnd) { + _flushBuffer(); + } + _outputBuffer[_outputTail++] = _quoteChar; - //decrease tracker - toRead -= numRead; + //read + while (toRead > 0) { + int toReadNow = Math.min(toRead, buf.length); + int numRead = reader.read(buf, 0, toReadNow); + if (numRead <= 0) { + break; } - - //Add trailing quote if ((_outputTail + len) >= _outputEnd) { _flushBuffer(); } - _outputBuffer[_outputTail++] = _quoteChar; + _writeString(buf, 0, numRead); - if (toRead > 0 && len >= 0) { - _reportError("Didn't read enough from reader"); - } + //decrease tracker + toRead -= numRead; + } + //Add trailing quote + if ((_outputTail + len) >= _outputEnd) { + _flushBuffer(); + } + _outputBuffer[_outputTail++] = _quoteChar; + + if (toRead > 0 && len >= 0) { + _reportError("Didn't read enough from reader"); } } @@ -957,7 +941,11 @@ protected void _releaseBuffers() _outputBuffer = null; _ioContext.releaseConcatBuffer(buf); } - _charBuffer = null; + buf = _charBuffer; + if (buf != null) { + _charBuffer = null; + _ioContext.releaseNameCopyBuffer(buf); + } } /* @@ -1938,7 +1926,17 @@ private char[] _allocateEntityBuffer() _entityBuffer = buf; return buf; } - + + /** + * @since 2.9 + */ + private char[] _allocateCopyBuffer() { + if (_charBuffer == null) { + _charBuffer = _ioContext.allocNameCopyBuffer(2000); + } + return _charBuffer; + } + protected void _flushBuffer() throws IOException { int len = _outputTail - _outputHead;