From 6d3998f50eabe47900ffc1084a30246076a8996f Mon Sep 17 00:00:00 2001 From: Wiehann Matthysen Date: Fri, 12 Apr 2019 22:27:28 +0200 Subject: [PATCH] Removed embedded Jackson sources. Removed the embedded Jackson sources. Instead, we now rely on the jackson-core-asl.jar file (version 1.9.13) as an external dependency. Various changes were made to the ant-scripts to include the new library on the class-path. The NetBeans and IntelliJ configurations were also changed to reference the new dependency. The Jackson license file was also added. --- .idea/libraries/jackson.xml | 9 + build.macros.xml | 15 +- build.properties | 1 - build.xml | 9 +- jackson-core-asl.jar | Bin 0 -> 232248 bytes jackson.LICENSE.txt | 13 + nbproject/project.xml | 6 +- src/org/codehaus/jackson/Base64Variant.java | 339 --- src/org/codehaus/jackson/Base64Variants.java | 90 - src/org/codehaus/jackson/JsonEncoding.java | 48 - src/org/codehaus/jackson/JsonFactory.java | 581 ------ .../jackson/JsonGenerationException.java | 27 - src/org/codehaus/jackson/JsonGenerator.java | 875 -------- src/org/codehaus/jackson/JsonLocation.java | 141 -- src/org/codehaus/jackson/JsonNode.java | 417 ---- .../codehaus/jackson/JsonParseException.java | 22 - src/org/codehaus/jackson/JsonParser.java | 945 --------- .../jackson/JsonProcessingException.java | 80 - .../codehaus/jackson/JsonStreamContext.java | 112 - src/org/codehaus/jackson/JsonToken.java | 160 -- src/org/codehaus/jackson/ObjectCodec.java | 141 -- src/org/codehaus/jackson/PrettyPrinter.java | 166 -- src/org/codehaus/jackson/VERSION | 795 ------- .../jackson/annotate/JacksonAnnotation.java | 20 - .../jackson/annotate/JsonAnySetter.java | 24 - .../jackson/annotate/JsonAutoDetect.java | 148 -- .../codehaus/jackson/annotate/JsonClass.java | 41 - .../jackson/annotate/JsonContentClass.java | 42 - .../jackson/annotate/JsonCreator.java | 19 - .../codehaus/jackson/annotate/JsonGetter.java | 34 - .../codehaus/jackson/annotate/JsonIgnore.java | 50 - .../annotate/JsonIgnoreProperties.java | 48 - .../jackson/annotate/JsonKeyClass.java | 44 - .../codehaus/jackson/annotate/JsonMethod.java | 90 - .../jackson/annotate/JsonProperty.java | 38 - .../jackson/annotate/JsonPropertyOrder.java | 46 - .../codehaus/jackson/annotate/JsonSetter.java | 29 - .../jackson/annotate/JsonSubTypes.java | 45 - .../jackson/annotate/JsonTypeInfo.java | 174 -- .../jackson/annotate/JsonTypeName.java | 28 - .../codehaus/jackson/annotate/JsonValue.java | 46 - .../annotate/JsonWriteNullProperties.java | 29 - .../jackson/impl/ByteSourceBootstrapper.java | 351 ---- .../jackson/impl/DefaultPrettyPrinter.java | 264 --- src/org/codehaus/jackson/impl/Indenter.java | 23 - .../jackson/impl/JsonGeneratorBase.java | 507 ----- .../jackson/impl/JsonNumericParserBase.java | 590 ------ .../codehaus/jackson/impl/JsonParserBase.java | 666 ------ .../jackson/impl/JsonReadContext.java | 176 -- .../jackson/impl/JsonWriteContext.java | 228 -- .../impl/ReaderBasedNumericParser.java | 302 --- .../jackson/impl/ReaderBasedParser.java | 1040 ---------- .../jackson/impl/ReaderBasedParserBase.java | 134 -- .../jackson/impl/StreamBasedParserBase.java | 134 -- .../jackson/impl/Utf8NumericParser.java | 190 -- .../jackson/impl/Utf8StreamParser.java | 1826 ----------------- .../jackson/impl/WriterBasedGenerator.java | 1019 --------- src/org/codehaus/jackson/io/BaseReader.java | 117 -- src/org/codehaus/jackson/io/IOContext.java | 240 --- src/org/codehaus/jackson/io/MergedStream.java | 141 -- src/org/codehaus/jackson/io/NumberInput.java | 110 - src/org/codehaus/jackson/io/NumberOutput.java | 269 --- .../jackson/io/SegmentedStringWriter.java | 104 - src/org/codehaus/jackson/io/UTF32Reader.java | 214 -- src/org/codehaus/jackson/io/UTF8Writer.java | 385 ---- .../jackson/sym/BytesToNameCanonicalizer.java | 958 --------- .../jackson/sym/CharsToNameCanonicalizer.java | 578 ------ src/org/codehaus/jackson/sym/Name.java | 53 - src/org/codehaus/jackson/sym/Name1.java | 41 - src/org/codehaus/jackson/sym/Name2.java | 37 - src/org/codehaus/jackson/sym/Name3.java | 36 - src/org/codehaus/jackson/sym/NameN.java | 68 - src/org/codehaus/jackson/type/JavaType.java | 333 --- .../codehaus/jackson/type/TypeReference.java | 59 - .../codehaus/jackson/util/BufferRecycler.java | 109 - .../jackson/util/ByteArrayBuilder.java | 233 --- src/org/codehaus/jackson/util/CharTypes.java | 193 -- .../codehaus/jackson/util/InternCache.java | 48 - .../jackson/util/JsonGeneratorDelegate.java | 225 -- .../jackson/util/JsonParserDelegate.java | 217 -- .../jackson/util/JsonParserSequence.java | 150 -- src/org/codehaus/jackson/util/TextBuffer.java | 634 ------ .../codehaus/jackson/util/TokenBuffer.java | 1235 ----------- 83 files changed, 38 insertions(+), 20186 deletions(-) create mode 100644 .idea/libraries/jackson.xml create mode 100644 jackson-core-asl.jar create mode 100644 jackson.LICENSE.txt delete mode 100644 src/org/codehaus/jackson/Base64Variant.java delete mode 100644 src/org/codehaus/jackson/Base64Variants.java delete mode 100644 src/org/codehaus/jackson/JsonEncoding.java delete mode 100644 src/org/codehaus/jackson/JsonFactory.java delete mode 100644 src/org/codehaus/jackson/JsonGenerationException.java delete mode 100644 src/org/codehaus/jackson/JsonGenerator.java delete mode 100644 src/org/codehaus/jackson/JsonLocation.java delete mode 100644 src/org/codehaus/jackson/JsonNode.java delete mode 100644 src/org/codehaus/jackson/JsonParseException.java delete mode 100644 src/org/codehaus/jackson/JsonParser.java delete mode 100644 src/org/codehaus/jackson/JsonProcessingException.java delete mode 100644 src/org/codehaus/jackson/JsonStreamContext.java delete mode 100644 src/org/codehaus/jackson/JsonToken.java delete mode 100644 src/org/codehaus/jackson/ObjectCodec.java delete mode 100644 src/org/codehaus/jackson/PrettyPrinter.java delete mode 100644 src/org/codehaus/jackson/VERSION delete mode 100644 src/org/codehaus/jackson/annotate/JacksonAnnotation.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonAnySetter.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonAutoDetect.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonClass.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonContentClass.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonCreator.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonGetter.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonIgnore.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonIgnoreProperties.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonKeyClass.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonMethod.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonProperty.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonPropertyOrder.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonSetter.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonSubTypes.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonTypeInfo.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonTypeName.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonValue.java delete mode 100644 src/org/codehaus/jackson/annotate/JsonWriteNullProperties.java delete mode 100644 src/org/codehaus/jackson/impl/ByteSourceBootstrapper.java delete mode 100644 src/org/codehaus/jackson/impl/DefaultPrettyPrinter.java delete mode 100644 src/org/codehaus/jackson/impl/Indenter.java delete mode 100644 src/org/codehaus/jackson/impl/JsonGeneratorBase.java delete mode 100644 src/org/codehaus/jackson/impl/JsonNumericParserBase.java delete mode 100644 src/org/codehaus/jackson/impl/JsonParserBase.java delete mode 100644 src/org/codehaus/jackson/impl/JsonReadContext.java delete mode 100644 src/org/codehaus/jackson/impl/JsonWriteContext.java delete mode 100644 src/org/codehaus/jackson/impl/ReaderBasedNumericParser.java delete mode 100644 src/org/codehaus/jackson/impl/ReaderBasedParser.java delete mode 100644 src/org/codehaus/jackson/impl/ReaderBasedParserBase.java delete mode 100644 src/org/codehaus/jackson/impl/StreamBasedParserBase.java delete mode 100644 src/org/codehaus/jackson/impl/Utf8NumericParser.java delete mode 100644 src/org/codehaus/jackson/impl/Utf8StreamParser.java delete mode 100644 src/org/codehaus/jackson/impl/WriterBasedGenerator.java delete mode 100644 src/org/codehaus/jackson/io/BaseReader.java delete mode 100644 src/org/codehaus/jackson/io/IOContext.java delete mode 100644 src/org/codehaus/jackson/io/MergedStream.java delete mode 100644 src/org/codehaus/jackson/io/NumberInput.java delete mode 100644 src/org/codehaus/jackson/io/NumberOutput.java delete mode 100644 src/org/codehaus/jackson/io/SegmentedStringWriter.java delete mode 100644 src/org/codehaus/jackson/io/UTF32Reader.java delete mode 100644 src/org/codehaus/jackson/io/UTF8Writer.java delete mode 100644 src/org/codehaus/jackson/sym/BytesToNameCanonicalizer.java delete mode 100644 src/org/codehaus/jackson/sym/CharsToNameCanonicalizer.java delete mode 100644 src/org/codehaus/jackson/sym/Name.java delete mode 100644 src/org/codehaus/jackson/sym/Name1.java delete mode 100644 src/org/codehaus/jackson/sym/Name2.java delete mode 100644 src/org/codehaus/jackson/sym/Name3.java delete mode 100644 src/org/codehaus/jackson/sym/NameN.java delete mode 100644 src/org/codehaus/jackson/type/JavaType.java delete mode 100644 src/org/codehaus/jackson/type/TypeReference.java delete mode 100644 src/org/codehaus/jackson/util/BufferRecycler.java delete mode 100644 src/org/codehaus/jackson/util/ByteArrayBuilder.java delete mode 100644 src/org/codehaus/jackson/util/CharTypes.java delete mode 100644 src/org/codehaus/jackson/util/InternCache.java delete mode 100644 src/org/codehaus/jackson/util/JsonGeneratorDelegate.java delete mode 100644 src/org/codehaus/jackson/util/JsonParserDelegate.java delete mode 100644 src/org/codehaus/jackson/util/JsonParserSequence.java delete mode 100644 src/org/codehaus/jackson/util/TextBuffer.java delete mode 100644 src/org/codehaus/jackson/util/TokenBuffer.java diff --git a/.idea/libraries/jackson.xml b/.idea/libraries/jackson.xml new file mode 100644 index 0000000000..855bfd9fb8 --- /dev/null +++ b/.idea/libraries/jackson.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/build.macros.xml b/build.macros.xml index f7b257f286..2522529a4d 100644 --- a/build.macros.xml +++ b/build.macros.xml @@ -43,11 +43,9 @@ + + @@ -318,6 +323,7 @@ jdk="${worldwind.jdk}"> + @@ -338,6 +344,7 @@ + @@ -550,7 +557,7 @@ diff --git a/jackson-core-asl.jar b/jackson-core-asl.jar new file mode 100644 index 0000000000000000000000000000000000000000..bb4fe1da1186505a254611ad5a7c49e9f64a3ee1 GIT binary patch literal 232248 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

2dsko`4LW75AF7j}p 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 r`!5Nc&-vMJ2%v#qs9y&B+gD=Ba)?00gn src - gdal.jar;gluegen-rt-natives-linux-amd64.jar;gluegen-rt-natives-linux-i586.jar;gluegen-rt-natives-macosx-universal.jar;gluegen-rt-natives-windows-amd64.jar;gluegen-rt-natives-windows-i586.jar;gluegen-rt.jar;jogl-all-natives-linux-amd64.jar;jogl-all-natives-linux-i586.jar;jogl-all-natives-macosx-universal.jar;jogl-all-natives-windows-amd64.jar;jogl-all-natives-windows-i586.jar;jogl-all.jar;junit-4.5.jar;vpf-symbols.jar + gdal.jar:gluegen-rt-natives-linux-amd64.jar:gluegen-rt-natives-linux-i586.jar:gluegen-rt-natives-macosx-universal.jar:gluegen-rt-natives-windows-amd64.jar:gluegen-rt-natives-windows-i586.jar:gluegen-rt.jar:jackson-core-asl.jar:jogl-all-natives-linux-amd64.jar:jogl-all-natives-linux-i586.jar:jogl-all-natives-macosx-universal.jar:jogl-all-natives-windows-amd64.jar:jogl-all-natives-windows-i586.jar:jogl-all.jar:junit-4.5.jar:vpf-symbols.jar build/classes/debug 1.5 test - gdal.jar;gluegen-rt-natives-linux-amd64.jar;gluegen-rt-natives-linux-i586.jar;gluegen-rt-natives-macosx-universal.jar;gluegen-rt-natives-windows-amd64.jar;gluegen-rt-natives-windows-i586.jar;gluegen-rt.jar;jogl-all-natives-linux-amd64.jar;jogl-all-natives-linux-i586.jar;jogl-all-natives-macosx-universal.jar;jogl-all-natives-windows-amd64.jar;jogl-all-natives-windows-i586.jar;jogl-all.jar;junit-4.5.jar;vpf-symbols.jar;worldwind.jar;worldwindx.jar + gdal.jar:gluegen-rt-natives-linux-amd64.jar:gluegen-rt-natives-linux-i586.jar:gluegen-rt-natives-macosx-universal.jar:gluegen-rt-natives-windows-amd64.jar:gluegen-rt-natives-windows-i586.jar:gluegen-rt.jar:jackson-core-asl.jar:jogl-all-natives-linux-amd64.jar:jogl-all-natives-linux-i586.jar:jogl-all-natives-macosx-universal.jar:jogl-all-natives-windows-amd64.jar:jogl-all-natives-windows-i586.jar:jogl-all.jar:junit-4.5.jar:vpf-symbols.jar:worldwind.jar:worldwindx.jar build/classes/test build/doc 1.5 @@ -129,7 +129,7 @@ auxiliary.show.customizer.message= testFunctional - gdal.jar;gluegen-rt-natives-linux-amd64.jar;gluegen-rt-natives-linux-i586.jar;gluegen-rt-natives-macosx-universal.jar;gluegen-rt-natives-windows-amd64.jar;gluegen-rt-natives-windows-i586.jar;gluegen-rt.jar;jogl-all-natives-linux-amd64.jar;jogl-all-natives-linux-i586.jar;jogl-all-natives-macosx-universal.jar;jogl-all-natives-windows-amd64.jar;jogl-all-natives-windows-i586.jar;jogl-all.jar;junit-4.5.jar;vpf-symbols.jar;worldwind.jar;worldwindx.jar + gdal.jar:gluegen-rt-natives-linux-amd64.jar:gluegen-rt-natives-linux-i586.jar:gluegen-rt-natives-macosx-universal.jar:gluegen-rt-natives-windows-amd64.jar:gluegen-rt-natives-windows-i586.jar:gluegen-rt.jar:jackson-core-asl.jar:jogl-all-natives-linux-amd64.jar:jogl-all-natives-linux-i586.jar:jogl-all-natives-macosx-universal.jar:jogl-all-natives-windows-amd64.jar:jogl-all-natives-windows-i586.jar:jogl-all.jar:junit-4.5.jar:vpf-symbols.jar:worldwind.jar:worldwindx.jar build/classes/test 1.5 diff --git a/src/org/codehaus/jackson/Base64Variant.java b/src/org/codehaus/jackson/Base64Variant.java deleted file mode 100644 index 4a4573b1be..0000000000 --- a/src/org/codehaus/jackson/Base64Variant.java +++ /dev/null @@ -1,339 +0,0 @@ -/* Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in file LICENSE, included with - * the source code and binary code bundles. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.codehaus.jackson; - -import java.util.Arrays; - -/** - * Abstract base class used to define specific details of which - * variant of Base64 encoding/decoding is to be used. Although there is - * somewhat standard basic version (so-called "MIME Base64"), other variants - * exists, see Base64 Wikipedia entry for details. - * - * @author Tatu Saloranta - * - * @since 0.9.3 - */ -public final class Base64Variant -{ - /** - * Placeholder used by "no padding" variant, to be used when a character - * value is needed. - */ - final static char PADDING_CHAR_NONE = '\0'; - - /** - * Marker used to denote ascii characters that do not correspond - * to a 6-bit value (in this variant), and is not used as a padding - * character. - */ - public final static int BASE64_VALUE_INVALID = -1; - - /** - * Marker used to denote ascii character (in decoding table) that - * is the padding character using this variant (if any). - */ - public final static int BASE64_VALUE_PADDING = -2; - - /* - //////////////////////////////////////////////////// - // Encoding/decoding tables - //////////////////////////////////////////////////// - */ - - /** - * Decoding table used for base 64 decoding. - */ - private final int[] _asciiToBase64 = new int[128]; - - /** - * Encoding table used for base 64 decoding when output is done - * as characters. - */ - private final char[] _base64ToAsciiC = new char[64]; - - /** - * Alternative encoding table used for base 64 decoding when output is done - * as ascii bytes. - */ - private final byte[] _base64ToAsciiB = new byte[64]; - - /* - //////////////////////////////////////////////////// - // Other configuration - //////////////////////////////////////////////////// - */ - - /** - * Symbolic name of variant; used for diagnostics/debugging. - */ - final String _name; - - /** - * Whether this variant uses padding or not. - */ - final boolean _usesPadding; - - /** - * Characted used for padding, if any ({@link #PADDING_CHAR_NONE} if not). - */ - final char _paddingChar; - - /** - * Maximum number of encoded base64 characters to output during encoding - * before adding a linefeed, if line length is to be limited - * ({@link java.lang.Integer#MAX_VALUE} if not limited). - *

- * Note: for some output modes (when writing attributes) linefeeds may - * need to be avoided, and this value ignored. - */ - final int _maxLineLength; - - /* - //////////////////////////////////////////////////// - // Life-cycle - //////////////////////////////////////////////////// - */ - - public Base64Variant(String name, String base64Alphabet, boolean usesPadding, char paddingChar, int maxLineLength) - { - _name = name; - _usesPadding = usesPadding; - _paddingChar = paddingChar; - _maxLineLength = maxLineLength; - - // Ok and then we need to create codec tables. - - // First the main encoding table: - int alphaLen = base64Alphabet.length(); - if (alphaLen != 64) { - throw new IllegalArgumentException("Base64Alphabet length must be exactly 64 (was "+alphaLen+")"); - } - - // And then secondary encoding table and decoding table: - base64Alphabet.getChars(0, alphaLen, _base64ToAsciiC, 0); - Arrays.fill(_asciiToBase64, BASE64_VALUE_INVALID); - for (int i = 0; i < alphaLen; ++i) { - char alpha = _base64ToAsciiC[i]; - _base64ToAsciiB[i] = (byte) alpha; - _asciiToBase64[alpha] = i; - } - - // Plus if we use padding, add that in too - if (usesPadding) { - _asciiToBase64[(int) paddingChar] = BASE64_VALUE_PADDING; - } - } - - /** - * "Copy constructor" that can be used when the base alphabet is identical - * to one used by another variant except for the maximum line length - * (and obviously, name). - */ - public Base64Variant(Base64Variant base, String name, int maxLineLength) - { - this(base, name, base._usesPadding, base._paddingChar, maxLineLength); - } - - /** - * "Copy constructor" that can be used when the base alphabet is identical - * to one used by another variant, but other details (padding, maximum - * line length) differ - */ - public Base64Variant(Base64Variant base, String name, boolean usesPadding, char paddingChar, int maxLineLength) - { - _name = name; - byte[] srcB = base._base64ToAsciiB; - System.arraycopy(srcB, 0, this._base64ToAsciiB, 0, srcB.length); - char[] srcC = base._base64ToAsciiC; - System.arraycopy(srcC, 0, this._base64ToAsciiC, 0, srcC.length); - int[] srcV = base._asciiToBase64; - System.arraycopy(srcV, 0, this._asciiToBase64, 0, srcV.length); - - _usesPadding = usesPadding; - _paddingChar = paddingChar; - _maxLineLength = maxLineLength; - } - - /* - //////////////////////////////////////////////////// - // Public accessors - //////////////////////////////////////////////////// - */ - - public String getName() { return _name; } - - public boolean usesPadding() { return _usesPadding; } - public boolean usesPaddingChar(char c) { return c == _paddingChar; } - public boolean usesPaddingChar(int ch) { return ch == (int) _paddingChar; } - public char getPaddingChar() { return _paddingChar; } - public byte getPaddingByte() { return (byte)_paddingChar; } - - public int getMaxLineLength() { return _maxLineLength; } - - /* - //////////////////////////////////////////////////// - // Decoding support - //////////////////////////////////////////////////// - */ - - /** - * @return 6-bit decoded value, if valid character; - */ - public int decodeBase64Char(char c) - { - int ch = (int) c; - return (ch <= 127) ? _asciiToBase64[ch] : BASE64_VALUE_INVALID; - } - - public int decodeBase64Char(int ch) - { - return (ch <= 127) ? _asciiToBase64[ch] : BASE64_VALUE_INVALID; - } - - public int decodeBase64Byte(byte b) - { - int ch = (int) b; - return (ch <= 127) ? _asciiToBase64[ch] : BASE64_VALUE_INVALID; - } - - /* - //////////////////////////////////////////////////// - // Encoding support - //////////////////////////////////////////////////// - */ - - public char encodeBase64BitsAsChar(int value) - { - /* Let's assume caller has done necessary checks; this - * method must be fast and inlinable - */ - return _base64ToAsciiC[value]; - } - - /** - * Method that encodes given right-aligned (LSB) 24-bit value - * into 4 base64 characters, stored in given result buffer. - */ - public int encodeBase64Chunk(int b24, char[] buffer, int ptr) - { - buffer[ptr++] = _base64ToAsciiC[(b24 >> 18) & 0x3F]; - buffer[ptr++] = _base64ToAsciiC[(b24 >> 12) & 0x3F]; - buffer[ptr++] = _base64ToAsciiC[(b24 >> 6) & 0x3F]; - buffer[ptr++] = _base64ToAsciiC[b24 & 0x3F]; - return ptr; - } - - public void encodeBase64Chunk(StringBuilder sb, int b24) - { - sb.append(_base64ToAsciiC[(b24 >> 18) & 0x3F]); - sb.append(_base64ToAsciiC[(b24 >> 12) & 0x3F]); - sb.append(_base64ToAsciiC[(b24 >> 6) & 0x3F]); - sb.append(_base64ToAsciiC[b24 & 0x3F]); - } - - /** - * Method that outputs partial chunk (which only encodes one - * or two bytes of data). Data given is still aligned same as if - * it as full data; that is, missing data is at the "right end" - * (LSB) of int. - * - * @param outputBytes Number of encoded bytes included (either 1 or 2) - */ - public int encodeBase64Partial(int bits, int outputBytes, char[] buffer, int outPtr) - { - buffer[outPtr++] = _base64ToAsciiC[(bits >> 18) & 0x3F]; - buffer[outPtr++] = _base64ToAsciiC[(bits >> 12) & 0x3F]; - if (_usesPadding) { - buffer[outPtr++] = (outputBytes == 2) ? - _base64ToAsciiC[(bits >> 6) & 0x3F] : _paddingChar; - buffer[outPtr++] = _paddingChar; - } else { - if (outputBytes == 2) { - buffer[outPtr++] = _base64ToAsciiC[(bits >> 6) & 0x3F]; - } - } - return outPtr; - } - - public void encodeBase64Partial(StringBuilder sb, int bits, int outputBytes) - { - sb.append(_base64ToAsciiC[(bits >> 18) & 0x3F]); - sb.append(_base64ToAsciiC[(bits >> 12) & 0x3F]); - if (_usesPadding) { - sb.append((outputBytes == 2) ? - _base64ToAsciiC[(bits >> 6) & 0x3F] : _paddingChar); - sb.append(_paddingChar); - } else { - if (outputBytes == 2) { - sb.append(_base64ToAsciiC[(bits >> 6) & 0x3F]); - } - } - } - - public byte encodeBase64BitsAsByte(int value) - { - // As with above, assuming it is 6-bit value - return _base64ToAsciiB[value]; - } - - /** - * Method that encodes given right-aligned (LSB) 24-bit value - * into 4 base64 bytes (ascii), stored in given result buffer. - */ - public int encodeBase64Chunk(int b24, byte[] buffer, int ptr) - { - buffer[ptr++] = _base64ToAsciiB[(b24 >> 18) & 0x3F]; - buffer[ptr++] = _base64ToAsciiB[(b24 >> 12) & 0x3F]; - buffer[ptr++] = _base64ToAsciiB[(b24 >> 6) & 0x3F]; - buffer[ptr++] = _base64ToAsciiB[b24 & 0x3F]; - return ptr; - } - - /** - * Method that outputs partial chunk (which only encodes one - * or two bytes of data). Data given is still aligned same as if - * it as full data; that is, missing data is at the "right end" - * (LSB) of int. - * - * @param outputBytes Number of encoded bytes included (either 1 or 2) - */ - public int encodeBase64Partial(int bits, int outputBytes, byte[] buffer, int outPtr) - { - buffer[outPtr++] = _base64ToAsciiB[(bits >> 18) & 0x3F]; - buffer[outPtr++] = _base64ToAsciiB[(bits >> 12) & 0x3F]; - if (_usesPadding) { - byte pb = (byte) _paddingChar; - buffer[outPtr++] = (outputBytes == 2) ? - _base64ToAsciiB[(bits >> 6) & 0x3F] : pb; - buffer[outPtr++] = pb; - } else { - if (outputBytes == 2) { - buffer[outPtr++] = _base64ToAsciiB[(bits >> 6) & 0x3F]; - } - } - return outPtr; - } - - /* - //////////////////////////////////////////////////// - // other methods - //////////////////////////////////////////////////// - */ - - // @Override - public String toString() { return _name; } -} - diff --git a/src/org/codehaus/jackson/Base64Variants.java b/src/org/codehaus/jackson/Base64Variants.java deleted file mode 100644 index 3c67ba4cab..0000000000 --- a/src/org/codehaus/jackson/Base64Variants.java +++ /dev/null @@ -1,90 +0,0 @@ -/* Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in file LICENSE, included with - * the source code and binary code bundles. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.codehaus.jackson; - -/** - * Container for commonly used Base64 variants. - * - * @author Tatu Saloranta - */ -public final class Base64Variants -{ - final static String STD_BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - /** - * This variant is what most people would think of "the standard" - * Base64 encoding. - *

- * See wikipedia Base64 entry for details. - *

- * Note that although this can be thought of as the standard variant, - * it is not the default for Jackson: no-linefeeds alternative - * is because of JSON requirement of escaping all linefeeds. - */ - public final static Base64Variant MIME; - static { - MIME = new Base64Variant("MIME", STD_BASE64_ALPHABET, true, '=', 76); - } - - /** - * Slightly non-standard modification of {@link #MIME} which does not - * use linefeeds (max line length set to infinite). Useful when linefeeds - * wouldn't work well (possibly in attributes), or for minor space savings - * (save 1 linefeed per 76 data chars, ie. ~1.4% savings). - */ - public final static Base64Variant MIME_NO_LINEFEEDS; - static { - MIME_NO_LINEFEEDS = new Base64Variant(MIME, "MIME-NO-LINEFEEDS", Integer.MAX_VALUE); - } - - /** - * This variant is the one that predates {@link #MIME}: it is otherwise - * identical, except that it mandates shorter line length. - */ - public final static Base64Variant PEM = new Base64Variant(MIME, "PEM", true, '=', 64); - - /** - * This non-standard variant is usually used when encoded data needs to be - * passed via URLs (such as part of GET request). It differs from the - * base {@link #MIME} variant in multiple ways. - * First, no padding is used: this also means that it generally can not - * be written in multiple separate but adjacent chunks (which would not - * be the usual use case in any case). Also, no linefeeds are used (max - * line length set to infinite). And finally, two characters (plus and - * slash) that would need quoting in URLs are replaced with more - * optimal alternatives (hyphen and underscore, respectively). - */ - public final static Base64Variant MODIFIED_FOR_URL; - static { - StringBuffer sb = new StringBuffer(STD_BASE64_ALPHABET); - // Replace plus with hyphen, slash with underscore (and no padding) - sb.setCharAt(sb.indexOf("+"), '-'); - sb.setCharAt(sb.indexOf("/"), '_'); - /* And finally, let's not split lines either, wouldn't work too - * well with URLs - */ - MODIFIED_FOR_URL = new Base64Variant("MODIFIED-FOR-URL", sb.toString(), false, Base64Variant.PADDING_CHAR_NONE, Integer.MAX_VALUE); - } - - /** - * Method used to get the default variant ("MIME_NO_LINEFEEDS") for cases - * where caller does not explicitly specify the variant. - * We will prefer no-linefeed version because linefeeds in JSON values - * must be escaped, making linefeed-containing variants sub-optimal. - */ - public static Base64Variant getDefaultVariant() { - return MIME_NO_LINEFEEDS; - } -} diff --git a/src/org/codehaus/jackson/JsonEncoding.java b/src/org/codehaus/jackson/JsonEncoding.java deleted file mode 100644 index 46495ad82c..0000000000 --- a/src/org/codehaus/jackson/JsonEncoding.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.codehaus.jackson; - -/** - * Enumeration that defines legal encodings that can be used - * for JSON content, based on list of allowed encodings from - * JSON specification. - *

- * Note: if application want to explicitly disregard Encoding - * limitations (to read in JSON encoded using an encoding not - * listed as allowed), they can use {@link java.io.Reader} / - * {@link java.io.Writer} instances as input - * source (or output target). - */ -public enum JsonEncoding { - UTF8("UTF-8", false), // N/A for big-endian, really - UTF16_BE("UTF-16BE", true), - UTF16_LE("UTF-16LE", false), - UTF32_BE("UTF-32BE", true), - UTF32_LE("UTF-32LE", false) - ; - - final String mJavaName; - - final boolean mBigEndian; - - JsonEncoding(String javaName, boolean bigEndian) - { - mJavaName = javaName; - mBigEndian = bigEndian; - } - - /** - * Method for accessing encoding name that JDK will support. - * - * @return Matching encoding name that JDK will support. - */ - public String getJavaName() { return mJavaName; } - - /** - * Whether encoding is big-endian (if encoding supports such - * notion). If no such distinction is made (as is the case for - * {@link #UTF8}), return value is undefined. - * - * @return True for big-endian encodings; false for little-endian - * (or if not applicable) - */ - public boolean isBigEndian() { return mBigEndian; } -} diff --git a/src/org/codehaus/jackson/JsonFactory.java b/src/org/codehaus/jackson/JsonFactory.java deleted file mode 100644 index e7d09a4651..0000000000 --- a/src/org/codehaus/jackson/JsonFactory.java +++ /dev/null @@ -1,581 +0,0 @@ -/* Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in file LICENSE, included with - * the source code and binary code bundles. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.codehaus.jackson; - -import java.io.*; -import java.lang.ref.SoftReference; -import java.net.URL; - -import org.codehaus.jackson.io.*; -import org.codehaus.jackson.impl.ByteSourceBootstrapper; -import org.codehaus.jackson.impl.ReaderBasedParser; -import org.codehaus.jackson.impl.WriterBasedGenerator; -import org.codehaus.jackson.sym.BytesToNameCanonicalizer; -import org.codehaus.jackson.sym.CharsToNameCanonicalizer; -import org.codehaus.jackson.util.BufferRecycler; - -/** - * The main factory class of Jackson package, used to configure and - * construct reader (aka parser, {@link JsonParser}) - * and writer (aka generator, {@link JsonGenerator}) - * instances. - *

- * Factory instances are thread-safe and reusable after configuration - * (if any). Typically applications and services use only a single - * globally shared factory instance, unless they need differently - * configured factories. Factory reuse is important if efficiency matters; - * most recycling of expensive construct is done on per-factory basis. - *

- * Creation of a factory instance is a light-weight operation, - * and since there is no need for pluggable alternative implementations - * (as there is no "standard" json processor API to implement), - * the default constructor is used for constructing factory - * instances. - * - * @author Tatu Saloranta - */ -public class JsonFactory -{ - /** - * Bitfield (set of flags) of all parser features that are enabled - * by default. - */ - final static int DEFAULT_PARSER_FEATURE_FLAGS = JsonParser.Feature.collectDefaults(); - - /** - * Bitfield (set of flags) of all generator features that are enabled - * by default. - */ - final static int DEFAULT_GENERATOR_FEATURE_FLAGS = JsonGenerator.Feature.collectDefaults(); - - /* - /****************************************************** - /* Buffer, symbol table management - /****************************************************** - */ - - /** - * This ThreadLocal contains a {@link SoftRerefence} - * to a {@link BufferRecycler} used to provide a low-cost - * buffer recycling between reader and writer instances. - */ - final static ThreadLocal> _recyclerRef = new ThreadLocal>(); - - /** - * Each factory comes equipped with a shared root symbol table. - * It should not be linked back to the original blueprint, to - * avoid contents from leaking between factories. - */ - protected CharsToNameCanonicalizer _rootCharSymbols = CharsToNameCanonicalizer.createRoot(); - - /** - * Alternative to the basic symbol table, some stream-based - * parsers use different name canonicalization method. - *

- * TODO: should clean up this; looks messy having 2 alternatives - * with not very clear differences. - */ - protected BytesToNameCanonicalizer _rootByteSymbols = BytesToNameCanonicalizer.createRoot(); - - /* - /****************************************************** - /* Configuration - /****************************************************** - */ - - /** - * Object that implements conversion functionality between - * Java objects and Json content. For base JsonFactory implementation - * usually not set by default, but can be explicitly set. - * Sub-classes (like @link org.codehaus.jackson.map.MappingJsonFactory} - * usually provide an implementation. - */ - protected ObjectCodec _objectCodec; - - protected int _parserFeatures = DEFAULT_PARSER_FEATURE_FLAGS; - - protected int _generatorFeatures = DEFAULT_GENERATOR_FEATURE_FLAGS; - - /** - * Default constructor used to create factory instances. - * Creation of a factory instance is a light-weight operation, - * but it is still a good idea to reuse limited number of - * factory instances (and quite often just a single instance): - * factories are used as context for storing some reused - * processing objects (such as symbol tables parsers use) - * and this reuse only works within context of a single - * factory instance. - */ - public JsonFactory() { this(null); } - - public JsonFactory(ObjectCodec oc) { _objectCodec = oc; } - - /* - /****************************************************** - /* Configuration, parser settings - /****************************************************** - */ - - /** - * Method for enabling or disabling specified parser feature - * (check {@link JsonParser.Feature} for list of features) - * - * @since 1.2 - */ - public final JsonFactory configure(JsonParser.Feature f, boolean state) - { - if (state) { - enable(f); - } else { - disable(f); - } - return this; - } - - /** - * Method for enabling specified parser feature - * (check {@link JsonParser.Feature} for list of features) - * - * @since 1.2 - */ - public JsonFactory enable(JsonParser.Feature f) { - _parserFeatures |= f.getMask(); - return this; - } - - /** - * Method for disabling specified parser features - * (check {@link JsonParser.Feature} for list of features) - * - * @since 1.2 - */ - public JsonFactory disable(JsonParser.Feature f) { - _parserFeatures &= ~f.getMask(); - return this; - } - - /** - * Checked whether specified parser feature is enabled. - * - * @since 1.2 - */ - public final boolean isEnabled(JsonParser.Feature f) { - return (_parserFeatures & f.getMask()) != 0; - } - - // // // Older deprecated (as of 1.2) methods - - /** - * @deprecated Use {@link #enable(JsonParser.Feature)} instead - */ - public final void enableParserFeature(JsonParser.Feature f) { - enable(f); - } - - /** - * @deprecated Use {@link #disable(JsonParser.Feature)} instead - */ - public final void disableParserFeature(JsonParser.Feature f) { - disable(f); - } - - /** - * @deprecated Use {@link #configure(JsonParser.Feature, boolean)} instead - */ - public final void setParserFeature(JsonParser.Feature f, boolean state) { - configure(f, state); - } - - /** - * @deprecated Use {@link #isEnabled(JsonParser.Feature)} instead - */ - public final boolean isParserFeatureEnabled(JsonParser.Feature f) { - return (_parserFeatures & f.getMask()) != 0; - } - - /* - ////////////////////////////////////////////////////// - // Configuration, generator settings - ////////////////////////////////////////////////////// - */ - - /** - * Method for enabling or disabling specified generator feature - * (check {@link JsonGenerator.Feature} for list of features) - * - * @since 1.2 - */ - public final JsonFactory configure(JsonGenerator.Feature f, boolean state) { - if (state) { - enable(f); - } else { - disable(f); - } - return this; - } - - - /** - * Method for enabling specified generator features - * (check {@link JsonGenerator.Feature} for list of features) - * - * @since 1.2 - */ - public JsonFactory enable(JsonGenerator.Feature f) { - _generatorFeatures |= f.getMask(); - return this; - } - - /** - * Method for disabling specified generator feature - * (check {@link JsonGenerator.Feature} for list of features) - * - * @since 1.2 - */ - public JsonFactory disable(JsonGenerator.Feature f) { - _generatorFeatures &= ~f.getMask(); - return this; - } - - /** - * Checked whether specified generator feature is enabled. - * - * @since 1.2 - */ - public final boolean isEnabled(JsonGenerator.Feature f) { - return (_generatorFeatures & f.getMask()) != 0; - } - - // // // Older deprecated (as of 1.2) methods - - /** - * @deprecated Use {@link #enable(JsonGenerator.Feature)} instead - */ - public final void enableGeneratorFeature(JsonGenerator.Feature f) { - enable(f); - } - - /** - * @deprecated Use {@link #disable(JsonGenerator.Feature)} instead - */ - public final void disableGeneratorFeature(JsonGenerator.Feature f) { - disable(f); - } - - /** - * @deprecated Use {@link #configure(JsonGenerator.Feature, boolean)} instead - */ - public final void setGeneratorFeature(JsonGenerator.Feature f, boolean state) { - configure(f, state); - } - - /** - * @deprecated Use {@link #isEnabled(JsonGenerator.Feature)} instead - */ - public final boolean isGeneratorFeatureEnabled(JsonGenerator.Feature f) { - return isEnabled(f); - } - - /* - ////////////////////////////////////////////////////// - // Configuration, other - ////////////////////////////////////////////////////// - */ - - public JsonFactory setCodec(ObjectCodec oc) { - _objectCodec = oc; - return this; - } - - public ObjectCodec getCodec() { return _objectCodec; } - - /* - ////////////////////////////////////////////////////// - // Reader factories - ////////////////////////////////////////////////////// - */ - - /** - * Method for constructing json parser instance to parse - * contents of specified file. Encoding is auto-detected - * from contents according to json specification recommended - * mechanism. - *

- * Underlying input stream (needed for reading contents) - * will be owned (and managed, i.e. closed as need be) by - * the parser, since caller has no access to it. - * - * @param f File that contains JSON content to parse - */ - public JsonParser createJsonParser(File f) - throws IOException, JsonParseException - { - return _createJsonParser(new FileInputStream(f), _createContext(f, true)); - } - - /** - * Method for constructing json parser instance to parse - * contents of resource reference by given URL. - * Encoding is auto-detected - * from contents according to json specification recommended - * mechanism. - *

- * Underlying input stream (needed for reading contents) - * will be owned (and managed, i.e. closed as need be) by - * the parser, since caller has no access to it. - * - * @param url URL pointing to resource that contains JSON content to parse - */ - public JsonParser createJsonParser(URL url) - throws IOException, JsonParseException - { - return _createJsonParser(_optimizedStreamFromURL(url), _createContext(url, true)); - } - - /** - * Method for constructing json parser instance to parse - * the contents accessed via specified input stream. - *

- * The input stream will not be owned by - * the parser, it will still be managed (i.e. closed if - * end-of-stream is reacher, or parser close method called) - * if (and only if) {@link org.codehaus.jackson.JsonParser.Feature#AUTO_CLOSE_SOURCE} - * is enabled. - *

- * Note: no encoding argument is taken since it can always be - * auto-detected as suggested by Json RFC. - * - * @param in InputStream to use for reading JSON content to parse - */ - public JsonParser createJsonParser(InputStream in) - throws IOException, JsonParseException - { - return _createJsonParser(in, _createContext(in, false)); - } - - /** - * Method for constructing json parser instance to parse - * the contents accessed via specified Reader. -

- * The read stream will not be owned by - * the parser, it will still be managed (i.e. closed if - * end-of-stream is reacher, or parser close method called) - * if (and only if) {@link org.codehaus.jackson.JsonParser.Feature#AUTO_CLOSE_SOURCE} - * is enabled. - *

- * - * @param r Reader to use for reading JSON content to parse - */ - public JsonParser createJsonParser(Reader r) - throws IOException, JsonParseException - { - return _createJsonParser(r, _createContext(r, false)); - } - - public JsonParser createJsonParser(byte[] data) - throws IOException, JsonParseException - { - return _createJsonParser(data, 0, data.length, _createContext(data, true)); - } - - public JsonParser createJsonParser(byte[] data, int offset, int len) - throws IOException, JsonParseException - { - return _createJsonParser(data, offset, len, _createContext(data, true)); - } - - public JsonParser createJsonParser(String content) - throws IOException, JsonParseException - { - // true -> we own the Reader (and must close); not a big deal - Reader r = new StringReader(content); - return _createJsonParser(r, _createContext(r, true)); - } - - /* - ////////////////////////////////////////////////////// - // Generator factories - ////////////////////////////////////////////////////// - */ - - /** - * Method for constructing json generator for writing json content - * using specified output stream. - * Encoding to use must be specified, and needs to be one of available - * types (as per JSON specification). - *

- * Underlying stream is NOT owned by the generator constructed, - * so that generator will NOT close the output stream when - * {@link JsonGenerator#close} is called (unless auto-closing - * feature, - * {@link org.codehaus.jackson.JsonGenerator.Feature#AUTO_CLOSE_TARGET} - * is enabled). - * Using application needs to close it explicitly if this is the case. - * - * @param out OutputStream to use for writing json content - * @param enc Character encoding to use - */ - public JsonGenerator createJsonGenerator(OutputStream out, JsonEncoding enc) - throws IOException - { - // false -> we won't manage the stream unless explicitly directed to - IOContext ctxt = _createContext(out, false); - ctxt.setEncoding(enc); - return _createJsonGenerator(_createWriter(out, enc, ctxt), ctxt); - } - - /** - * Method for constructing json generator for writing json content - * using specified Writer. - *

- * Underlying stream is NOT owned by the generator constructed, - * so that generator will NOT close the Reader when - * {@link JsonGenerator#close} is called (unless auto-closing - * feature, - * {@link org.codehaus.jackson.JsonGenerator.Feature#AUTO_CLOSE_TARGET} is enabled). - * Using application needs to close it explicitly. - * - * @param out Writer to use for writing json content - */ - public JsonGenerator createJsonGenerator(Writer out) - throws IOException - { - IOContext ctxt = _createContext(out, false); - return _createJsonGenerator(out, ctxt); - } - - /** - * Method for constructing json generator for writing json content - * to specified file, overwriting contents it might have (or creating - * it if such file does not yet exist). - * Encoding to use must be specified, and needs to be one of available - * types (as per JSON specification). - *

- * Underlying stream is owned by the generator constructed, - * i.e. generator will handle closing of file when - * {@link JsonGenerator#close} is called. - * - * @param f File to write contents to - * @param enc Character encoding to use - */ - public JsonGenerator createJsonGenerator(File f, JsonEncoding enc) - throws IOException - { - OutputStream out = new FileOutputStream(f); - // true -> yes, we have to manage the stream since we created it - IOContext ctxt = _createContext(out, true); - ctxt.setEncoding(enc); - return _createJsonGenerator(_createWriter(out, enc, ctxt), ctxt); - } - - /* - /////////////////////////////////////////////////////////// - // Internal methods - /////////////////////////////////////////////////////////// - */ - - /** - * Overridable construction method that actually instantiates desired generator. - */ - protected IOContext _createContext(Object srcRef, boolean resourceManaged) - { - return new IOContext(_getBufferRecycler(), srcRef, resourceManaged); - } - - /** - * Overridable construction method that actually instantiates desired parser. - */ - protected JsonParser _createJsonParser(InputStream in, IOContext ctxt) - throws IOException, JsonParseException - { - return new ByteSourceBootstrapper(ctxt, in).constructParser(_parserFeatures, _objectCodec, _rootByteSymbols, _rootCharSymbols); - } - - protected JsonParser _createJsonParser(Reader r, IOContext ctxt) - throws IOException, JsonParseException - { - return new ReaderBasedParser(ctxt, _parserFeatures, r, _objectCodec, - _rootCharSymbols.makeChild(isEnabled(JsonParser.Feature.CANONICALIZE_FIELD_NAMES), - isEnabled(JsonParser.Feature.INTERN_FIELD_NAMES))); - } - - protected JsonParser _createJsonParser(byte[] data, int offset, int len, IOContext ctxt) - throws IOException, JsonParseException - { - // true -> managed (doesn't really matter; we have no stream!) - return new ByteSourceBootstrapper(ctxt, data, offset, len).constructParser(_parserFeatures, _objectCodec, _rootByteSymbols, _rootCharSymbols); - } - - /** - * Overridable construction method that actually instantiates desired generator - */ - protected JsonGenerator _createJsonGenerator(Writer out, IOContext ctxt) - throws IOException - { - return new WriterBasedGenerator(ctxt, _generatorFeatures, _objectCodec, out); - } - - /** - * Method used by factory to create buffer recycler instances - * for parsers and generators. - *

- * Note: only public to give access for ObjectMapper - */ - public BufferRecycler _getBufferRecycler() - { - SoftReference ref = _recyclerRef.get(); - BufferRecycler br = (ref == null) ? null : ref.get(); - - if (br == null) { - br = new BufferRecycler(); - if (ref == null) { - _recyclerRef.set(new SoftReference(br)); - } - } - return br; - } - - /** - * Helper methods used for constructing an optimal stream for - * parsers to use, when input is to be read from an URL. - * This helps when reading file content via URL. - */ - protected InputStream _optimizedStreamFromURL(URL url) - throws IOException - { - if ("file".equals(url.getProtocol())) { - /* Can not do this if the path refers - * to a network drive on windows. This fixes the problem; - * might not be needed on all platforms (NFS?), but should not - * matter a lot: performance penalty of extra wrapping is more - * relevant when accessing local file system. - */ - String host = url.getHost(); - if (host == null || host.length() == 0) { - return new FileInputStream(url.getPath()); - } - } - return url.openStream(); - } - - protected Writer _createWriter(OutputStream out, JsonEncoding enc, IOContext ctxt) throws IOException - { - if (enc == JsonEncoding.UTF8) { // We have optimized writer for UTF-8 - return new UTF8Writer(ctxt, out); - } - // not optimal, but should do unless we really care about UTF-16/32 encoding speed - return new OutputStreamWriter(out, enc.getJavaName()); - } -} diff --git a/src/org/codehaus/jackson/JsonGenerationException.java b/src/org/codehaus/jackson/JsonGenerationException.java deleted file mode 100644 index 07499b3203..0000000000 --- a/src/org/codehaus/jackson/JsonGenerationException.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.codehaus.jackson; - -/** - * Exception type for exceptions during JSON writing, such as trying - * to output content in wrong context (non-matching end-array or end-object, - * for example). - */ -public class JsonGenerationException - extends JsonProcessingException -{ - final static long serialVersionUID = 123; // Stupid eclipse... - - public JsonGenerationException(Throwable rootCause) - { - super(rootCause); - } - - public JsonGenerationException(String msg) - { - super(msg, (JsonLocation)null); - } - - public JsonGenerationException(String msg, Throwable rootCause) - { - super(msg, (JsonLocation)null, rootCause); - } -} diff --git a/src/org/codehaus/jackson/JsonGenerator.java b/src/org/codehaus/jackson/JsonGenerator.java deleted file mode 100644 index 7df8a80eec..0000000000 --- a/src/org/codehaus/jackson/JsonGenerator.java +++ /dev/null @@ -1,875 +0,0 @@ -/* Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in file LICENSE, included with - * the source code and binary code bundles. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.codehaus.jackson; - -import java.io.*; -import java.math.BigDecimal; -import java.math.BigInteger; - -/** - * Base class that defines public API for writing Json content. - * Instances are created using factory methods of - * a {@link JsonFactory} instance. - * - * @author Tatu Saloranta - */ -public abstract class JsonGenerator - implements Closeable -{ - /** - * Enumeration that defines all togglable features for generators. - */ - public enum Feature { - /** - * Feature that determines whether generator will automatically - * close underlying output target that is NOT owned by the - * generator. - * If disabled, calling application has to separately - * close the underlying {@link OutputStream} and {@link Writer} - * instances used to create the generator. If enabled, generator - * will handle closing, as long as generator itself gets closed: - * this happens when end-of-input is encountered, or generator - * is closed by a call to {@link JsonGenerator#close}. - *

- * Feature is enabled by default. - */ - AUTO_CLOSE_TARGET(true) - - /** - * Feature that determines what happens when the generator is - * closed while there are still unmatched - * {@link JsonToken#START_ARRAY} or {@link JsonToken#START_OBJECT} - * entries in output content. If enabled, such Array(s) and/or - * Object(s) are automatically closed; if disabled, nothing - * specific is done. - *

- * Feature is enabled by default. - */ - ,AUTO_CLOSE_JSON_CONTENT(true) - - /** - * Feature that determines whether Json Object field names are - * quoted using double-quotes, as specified by Json specification - * or not. Ability to disable quoting was added to support use - * cases where they are not usually expected, which most commonly - * occurs when used straight from javascript. - */ - ,QUOTE_FIELD_NAMES(true) - - /** - * Feature that determines whether "exceptional" (not real number) - * float/double values are outputted as quoted strings. - * The values checked are Double.Nan, - * Double.POSITIVE_INFINITY and Double.NEGATIVE_INIFINTY (and - * associated Float values). - * If feature is disabled, these numbers are still output using - * associated literal values, resulting in non-conformant - * output - *

- * Feature is enabled by default. - */ - ,QUOTE_NON_NUMERIC_NUMBERS(true) - - /** - * Feature that forces all Java numbers to be written as JSON strings. - * Default state is 'false', meaning that Java numbers are to - * be serialized using basic numeric serialization (as JSON - * numbers, integral or floating point). If enabled, all such - * numeric values are instead written out as JSON Strings. - *

- * One use case is to avoid problems with Javascript limitations: - * since Javascript standard specifies that all number handling - * should be done using 64-bit IEEE 754 floating point values, - * result being that some 64-bit integer values can not be - * accurately represent (as mantissa is only 51 bit wide). - * - * @since 1.3 - */ - ,WRITE_NUMBERS_AS_STRINGS(false) - - ; - - final boolean _defaultState; - - final int _mask; - - /** - * Method that calculates bit set (flags) of all features that - * are enabled by default. - */ - public static int collectDefaults() - { - int flags = 0; - for (Feature f : values()) { - if (f.enabledByDefault()) { - flags |= f.getMask(); - } - } - return flags; - } - - private Feature(boolean defaultState) { - _defaultState = defaultState; - _mask = (1 << ordinal()); - } - - public boolean enabledByDefault() { return _defaultState; } - - public int getMask() { return _mask; } - }; - - // // // Configuration: - - /** - * Object that handles pretty-printing (usually additional - * white space to make results more human-readable) during - * output. If null, no pretty-printing is done. - */ - protected PrettyPrinter _cfgPrettyPrinter; - - protected JsonGenerator() { - } - - /* - //////////////////////////////////////////////////// - // Public API, configuration - //////////////////////////////////////////////////// - */ - - /** - * Method for enabling specified parser features: - * check {@link Feature} for list of available features. - * - * @return Generator itself (this), to allow chaining - * - * @since 1.2 - */ - public abstract JsonGenerator enable(Feature f); - - /** - * Method for disabling specified features - * (check {@link Feature} for list of features) - * - * @return Generator itself (this), to allow chaining - * - * @since 1.2 - */ - public abstract JsonGenerator disable(Feature f); - - /** - * Method for enabling or disabling specified feature: - * check {@link Feature} for list of available features. - * - * @return Generator itself (this), to allow chaining - * - * @since 1.2 - */ - public JsonGenerator configure(Feature f, boolean state) - { - if (state) { - enable(f); - } else { - disable(f); - } - return this; - } - - /** - * Method for checking whether given feature is enabled. - * Check {@link Feature} for list of available features. - * - * @since 1.2 - */ - public abstract boolean isEnabled(Feature f); - - /** - * Method that can be called to set or reset the object to - * use for writing Java objects as JsonContent - * (using method {@link #writeObject}). - * - * @return Generator itself (this), to allow chaining - */ - public abstract JsonGenerator setCodec(ObjectCodec oc); - - /** - * Method for accessing the object used for writing Java - * object as Json content - * (using method {@link #writeObject}). - */ - public abstract ObjectCodec getCodec(); - - // // // Older deprecated versions - - /** @deprecated Use {@link #enable} instead - */ - public void enableFeature(Feature f) { enable(f); } - - /** @deprecated Use {@link #disable} instead - */ - public void disableFeature(Feature f) { disable(f); } - - /** @deprecated Use {@link #configure} instead - */ - public void setFeature(Feature f, boolean state) { configure(f, state); } - - /** @deprecated Use {@link #isEnabled} instead - */ - public boolean isFeatureEnabled(Feature f) { return isEnabled(f); } - - - /* - //////////////////////////////////////////////////// - // Configuring generator - //////////////////////////////////////////////////// - */ - - /** - * Method for setting a custom pretty printer, which is usually - * used to add indentation for improved human readability. - * By default, generator does not do pretty printing. - *

- * To use the default pretty printer that comes with core - * Jackson distribution, call {@link #useDefaultPrettyPrinter} - * instead. - * - * @return Generator itself (this), to allow chaining - */ - public JsonGenerator setPrettyPrinter(PrettyPrinter pp) { - _cfgPrettyPrinter = pp; - return this; - } - - /** - * Convenience method for enabling pretty-printing using - * the default pretty printer - * ({@link org.codehaus.jackson.impl.DefaultPrettyPrinter}). - * - * @return Generator itself (this), to allow chaining - */ - public abstract JsonGenerator useDefaultPrettyPrinter(); - - /* - //////////////////////////////////////////////////// - // Public API, write methods, structural - //////////////////////////////////////////////////// - */ - - /** - * Method for writing starting marker of a Json Array value - * (character '['; plus possible white space decoration - * if pretty-printing is enabled). - *

- * Array values can be written in any context where values - * are allowed: meaning everywhere except for when - * a field name is expected. - */ - public abstract void writeStartArray() - throws IOException, JsonGenerationException; - - /** - * Method for writing closing marker of a Json Array value - * (character ']'; plus possible white space decoration - * if pretty-printing is enabled). - *

- * Marker can be written if the innermost structured type - * is Array. - */ - public abstract void writeEndArray() - throws IOException, JsonGenerationException; - - /** - * Method for writing starting marker of a Json Object value - * (character '{'; plus possible white space decoration - * if pretty-printing is enabled). - *

- * Object values can be written in any context where values - * are allowed: meaning everywhere except for when - * a field name is expected. - */ - public abstract void writeStartObject() - throws IOException, JsonGenerationException; - - /** - * Method for writing closing marker of a Json Object value - * (character '}'; plus possible white space decoration - * if pretty-printing is enabled). - *

- * Marker can be written if the innermost structured type - * is Object, and the last written event was either a - * complete value, or START-OBJECT marker (see Json specification - * for more details). - */ - public abstract void writeEndObject() - throws IOException, JsonGenerationException; - - /** - * Method for writing a field name (json String surrounded by - * double quotes: syntactically identical to a json String value), - * possibly decorated by white space if pretty-printing is enabled. - *

- * Field names can only be written in Object context (check out - * Json specification for details), when field name is expected - * (field names alternate with values). - */ - public abstract void writeFieldName(String name) - throws IOException, JsonGenerationException; - - /* - //////////////////////////////////////////////////// - // Public API, write methods, textual/binary - //////////////////////////////////////////////////// - */ - - /** - * Method for outputting a String value. Depending on context - * this means either array element, (object) field value or - * a stand alone String; but in all cases, String will be - * surrounded in double quotes, and contents will be properly - * escaped as required by Json specification. - */ - public abstract void writeString(String text) - throws IOException, JsonGenerationException; - - public abstract void writeString(char[] text, int offset, int len) - throws IOException, JsonGenerationException; - - /** - * Fallback method which can be used to make generator copy - * input text verbatim with no modifications (including - * that no quoting is done and no separators are added even - * if context [array, object] would otherwise require such). - * If such separators are desired, use - * {@link #writeRawValue(String)} instead. - */ - public abstract void writeRaw(String text) - throws IOException, JsonGenerationException; - - public abstract void writeRaw(String text, int offset, int len) - throws IOException, JsonGenerationException; - - public abstract void writeRaw(char[] text, int offset, int len) - throws IOException, JsonGenerationException; - - public abstract void writeRaw(char c) - throws IOException, JsonGenerationException; - - /** - * Fallback method which can be used to make generator copy - * input text verbatim without any modifications, but assuming - * it must constitute a single legal Json value (number, string, - * boolean, null, Array or List). Assuming this, proper separators - * are added if and as needed (comma or colon), and generator - * state updated to reflect this. - */ - public abstract void writeRawValue(String text) - throws IOException, JsonGenerationException; - - public abstract void writeRawValue(String text, int offset, int len) - throws IOException, JsonGenerationException; - - public abstract void writeRawValue(char[] text, int offset, int len) - throws IOException, JsonGenerationException; - - /** - * Method that will output given chunk of binary data as base64 - * encoded, as a complete String value (surrounded by double quotes). - * This method defaults - *

- * Note: because Json Strings can not contain unescaped linefeeds, - * if linefeeds are included (as per last argument), they must be - * escaped. This adds overhead for decoding without improving - * readability. - * Alternatively if linefeeds are not included, - * resulting String value may violate the requirement of base64 - * RFC which mandates line-length of 76 characters and use of - * linefeeds. However, all {@link JsonParser} implementations - * are required to accept such "long line base64"; as do - * typical production-level base64 decoders. - * - * @param b64variant Base64 variant to use: defines details such as - * whether padding is used (and if so, using which character); - * what is the maximum line length before adding linefeed, - * and also the underlying alphabet to use. - */ - public abstract void writeBinary(Base64Variant b64variant, - byte[] data, int offset, int len) - throws IOException, JsonGenerationException; - - /** - * Similar to {@link #writeBinary(Base64Variant,byte[],int,int)}, - * but default to using the Jackson default Base64 variant - * (which is {@link Base64Variants#MIME_NO_LINEFEEDS}). - */ - public void writeBinary(byte[] data, int offset, int len) - throws IOException, JsonGenerationException - { - writeBinary(Base64Variants.getDefaultVariant(), data, offset, len); - } - - /** - * Similar to {@link #writeBinary(Base64Variant,byte[],int,int)}, - * but assumes default to using the Jackson default Base64 variant - * (which is {@link Base64Variants#MIME_NO_LINEFEEDS}). Also - * assumes that whole byte array is to be output. - */ - public void writeBinary(byte[] data) - throws IOException, JsonGenerationException - { - writeBinary(Base64Variants.getDefaultVariant(), data, 0, data.length); - } - - /* - //////////////////////////////////////////////////// - // Public API, write methods, other value types - //////////////////////////////////////////////////// - */ - - /** - * Method for outputting given value as Json number. - * Can be called in any context where a value is expected - * (Array value, Object field value, root-level value). - * Additional white space may be added around the value - * if pretty-printing is enabled. - */ - public abstract void writeNumber(int v) - throws IOException, JsonGenerationException; - - /** - * Method for outputting given value as Json number. - * Can be called in any context where a value is expected - * (Array value, Object field value, root-level value). - * Additional white space may be added around the value - * if pretty-printing is enabled. - */ - public abstract void writeNumber(long v) - throws IOException, JsonGenerationException; - - /** - * Method for outputting given value as Json number. - * Can be called in any context where a value is expected - * (Array value, Object field value, root-level value). - * Additional white space may be added around the value - * if pretty-printing is enabled. - */ - public abstract void writeNumber(BigInteger v) - throws IOException, JsonGenerationException; - - /** - * Method for outputting indicate Json numeric value. - * Can be called in any context where a value is expected - * (Array value, Object field value, root-level value). - * Additional white space may be added around the value - * if pretty-printing is enabled. - */ - public abstract void writeNumber(double d) - throws IOException, JsonGenerationException; - - /** - * Method for outputting indicate Json numeric value. - * Can be called in any context where a value is expected - * (Array value, Object field value, root-level value). - * Additional white space may be added around the value - * if pretty-printing is enabled. - */ - public abstract void writeNumber(float f) - throws IOException, JsonGenerationException; - - /** - * Method for outputting indicate Json numeric value. - * Can be called in any context where a value is expected - * (Array value, Object field value, root-level value). - * Additional white space may be added around the value - * if pretty-printing is enabled. - */ - public abstract void writeNumber(BigDecimal dec) - throws IOException, JsonGenerationException; - - /** - * Write method that can be used for custom numeric types that can - * not be (easily?) converted to "standard" Java number types. - * Because numbers are not surrounded by double quotes, regular - * {@link #writeString} method can not be used; nor - * {@link #writeRaw} because that does not properly handle - * value separators needed in Array or Object contexts. - *

- * Note: because of lack of type safety, some generator - * implementations may not be able to implement this - * method. For example, if a binary json format is used, - * it may require type information for encoding; similarly - * for generator-wrappers around Java objects or Json nodes. - * If implementation does not implement this method, - * it needs to throw {@link UnsupportedOperationException}. - */ - public abstract void writeNumber(String encodedValue) - throws IOException, JsonGenerationException, - UnsupportedOperationException; - - /** - * Method for outputting literal Json boolean value (one of - * Strings 'true' and 'false'). - * Can be called in any context where a value is expected - * (Array value, Object field value, root-level value). - * Additional white space may be added around the value - * if pretty-printing is enabled. - */ - public abstract void writeBoolean(boolean state) - throws IOException, JsonGenerationException; - - /** - * Method for outputting literal Json null value. - * Can be called in any context where a value is expected - * (Array value, Object field value, root-level value). - * Additional white space may be added around the value - * if pretty-printing is enabled. - */ - public abstract void writeNull() - throws IOException, JsonGenerationException; - - /* - //////////////////////////////////////////////////// - // Public API, write methods, serializing Java objects - //////////////////////////////////////////////////// - */ - - /** - * Method for writing given Java object (POJO) as Json. - * Exactly how the object gets written depends on object - * in question (ad on codec, its configuration); for most - * beans it will result in Json object, but for others Json - * array, or String or numeric value (and for nulls, Json - * null literal. - * NOTE: generator must have its object codec - * set to non-null value; for generators created by a mapping - * factory this is the case, for others not. - */ - public abstract void writeObject(Object pojo) - throws IOException, JsonProcessingException; - - /** - * Method for writing given Json tree (expressed as a tree - * where given JsonNode is the root) using this generator. - * This will generally just call - * {@link #writeObject} with given node, but is added - * for convenience and to make code more explicit in cases - * where it deals specifically with trees. - */ - public abstract void writeTree(JsonNode rootNode) - throws IOException, JsonProcessingException; - - /* - //////////////////////////////////////////////////// - // Public API, convenience field write methods - //////////////////////////////////////////////////// - */ - - /** - * Convenience method for outputting a field entry ("member") - * that has a String value. Equivalent to: - *

-     *  writeFieldName(fieldName);
-     *  writeString(value);
-     *
- */ - public final void writeStringField(String fieldName, String value) - throws IOException, JsonGenerationException - { - writeFieldName(fieldName); - writeString(value); - } - - /** - * Convenience method for outputting a field entry ("member") - * that has a boolean value. Equivalent to: - *
-     *  writeFieldName(fieldName);
-     *  writeBoolean(value);
-     *
- */ - public final void writeBooleanField(String fieldName, boolean value) - throws IOException, JsonGenerationException - { - writeFieldName(fieldName); - writeBoolean(value); - } - - /** - * Convenience method for outputting a field entry ("member") - * that has Json literal value null. Equivalent to: - *
-     *  writeFieldName(fieldName);
-     *  writeNull();
-     *
- */ - public final void writeNullField(String fieldName) - throws IOException, JsonGenerationException - { - writeFieldName(fieldName); - writeNull(); - } - - /** - * Convenience method for outputting a field entry ("member") - * that has the specified numeric value. Equivalent to: - *
-     *  writeFieldName(fieldName);
-     *  writeNumber(value);
-     *
- */ - public final void writeNumberField(String fieldName, int value) - throws IOException, JsonGenerationException - { - writeFieldName(fieldName); - writeNumber(value); - } - - /** - * Convenience method for outputting a field entry ("member") - * that has the specified numeric value. Equivalent to: - *
-     *  writeFieldName(fieldName);
-     *  writeNumber(value);
-     *
- */ - public final void writeNumberField(String fieldName, long value) - throws IOException, JsonGenerationException - { - writeFieldName(fieldName); - writeNumber(value); - } - - /** - * Convenience method for outputting a field entry ("member") - * that has the specified numeric value. Equivalent to: - *
-     *  writeFieldName(fieldName);
-     *  writeNumber(value);
-     *
- */ - public final void writeNumberField(String fieldName, double value) - throws IOException, JsonGenerationException - { - writeFieldName(fieldName); - writeNumber(value); - } - - /** - * Convenience method for outputting a field entry ("member") - * that has the specified numeric value. Equivalent to: - *
-     *  writeFieldName(fieldName);
-     *  writeNumber(value);
-     *
- */ - public final void writeNumberField(String fieldName, float value) - throws IOException, JsonGenerationException - { - writeFieldName(fieldName); - writeNumber(value); - } - - /** - * Convenience method for outputting a field entry ("member") - * that has the specified numeric value. - * Equivalent to: - *
-     *  writeFieldName(fieldName);
-     *  writeNumber(value);
-     *
- */ - public final void writeNumberField(String fieldName, BigDecimal value) - throws IOException, JsonGenerationException - { - writeFieldName(fieldName); - writeNumber(value); - } - - /** - * Convenience method for outputting a field entry ("member") - * that contains specified data in base64-encoded form. - * Equivalent to: - *
-     *  writeFieldName(fieldName);
-     *  writeBinary(value);
-     *
- */ - public final void writeBinaryField(String fieldName, byte[] data) - throws IOException, JsonGenerationException - { - writeFieldName(fieldName); - writeBinary(data); - } - - /** - * Convenience method for outputting a field entry ("member") - * (that will contain a Json Array value), and the START_ARRAY marker. - * Equivalent to: - *
-     *  writeFieldName(fieldName);
-     *  writeStartArray();
-     *
- *

- * Note: caller still has to take care to close the array - * (by calling {#link #writeEndArray}) after writing all values - * of the value Array. - */ - public final void writeArrayFieldStart(String fieldName) - throws IOException, JsonGenerationException - { - writeFieldName(fieldName); - writeStartArray(); - } - - /** - * Convenience method for outputting a field entry ("member") - * (that will contain a Json Object value), and the START_OBJECT marker. - * Equivalent to: - *

-     *  writeFieldName(fieldName);
-     *  writeStartObject();
-     *
- *

- * Note: caller still has to take care to close the Object - * (by calling {#link #writeEndObject}) after writing all - * entries of the value Object. - */ - public final void writeObjectFieldStart(String fieldName) - throws IOException, JsonGenerationException - { - writeFieldName(fieldName); - writeStartObject(); - } - - /** - * Convenience method for outputting a field entry ("member") - * that has contents of specific Java object as its value. - * Equivalent to: - *

-     *  writeFieldName(fieldName);
-     *  writeObject(pojo);
-     *
- */ - public final void writeObjectField(String fieldName, Object pojo) - throws IOException, JsonProcessingException - { - writeFieldName(fieldName); - writeObject(pojo); - } - - /* - //////////////////////////////////////////////////// - // Public API, copy-through methods - //////////////////////////////////////////////////// - */ - - /** - * Method for copying contents of the current event that - * the given parser instance points to. - * Note that the method will not copy any other events, - * such as events contained within Json Array or Object structures. - *

- * Calling this method will not advance the given - * parser, although it may cause parser to internally process - * more data (if it lazy loads contents of value events, for example) - */ - public abstract void copyCurrentEvent(JsonParser jp) - throws IOException, JsonProcessingException; - - /** - * Method for copying contents of the current event - * and following events that it encloses - * the given parser instance points to. - *

- * So what constitutes enclosing? Here is the list of - * events that have associated enclosed events that will - * get copied: - *

    - *
  • {@link JsonToken#START_OBJECT}: - * all events up to and including matching (closing) - * {@link JsonToken#END_OBJECT} will be copied - *
  • - *
  • {@link JsonToken#START_ARRAY} - * all events up to and including matching (closing) - * {@link JsonToken#END_ARRAY} will be copied - *
  • - *
  • {@link JsonToken#FIELD_NAME} the logical value (which - * can consist of a single scalar value; or a sequence of related - * events for structured types (Json Arrays, Objects)) will - * be copied along with the name itself. So essentially the - * whole field entry (name and value) will be copied. - *
  • - *
- *

- * After calling this method, parser will point to the - * last event that was copied. This will either be - * the event parser already pointed to (if there were no - * enclosed events), or the last enclosed event copied. - */ - public abstract void copyCurrentStructure(JsonParser jp) - throws IOException, JsonProcessingException; - - /* - //////////////////////////////////////////////////// - // Public API, context access - //////////////////////////////////////////////////// - */ - - /** - * @return Context object that can give information about logical - * position within generated json content. - */ - public abstract JsonStreamContext getOutputContext(); - - /* - //////////////////////////////////////////////////// - // Public API, buffer handling - //////////////////////////////////////////////////// - */ - - /** - * Method called to flush any buffered content to the underlying - * target (output stream, writer), and to flush the target itself - * as well. - */ - public abstract void flush() - throws IOException; - - /** - * Method that can be called to determine whether this generator - * is closed or not. If it is closed, no more output can be done. - */ - public abstract boolean isClosed(); - - /* - //////////////////////////////////////////////////// - // Closeable implementation - //////////////////////////////////////////////////// - */ - - /** - * Method called to close this generator, so that no more content - * can be written. - *

- * Whether the underlying target (stream, writer) gets closed depends - * on whether this generator either manages the target (i.e. is the - * only one with access to the target -- case if caller passes a - * reference to the resource such as File, but not stream); or - * has feature {@link Feature#AUTO_CLOSE_TARGET} enabled. - * If either of above is true, the target is also closed. Otherwise - * (not managing, feature not enabled), target is not closed. - */ - public abstract void close() - throws IOException; - -} diff --git a/src/org/codehaus/jackson/JsonLocation.java b/src/org/codehaus/jackson/JsonLocation.java deleted file mode 100644 index a861b5ce0f..0000000000 --- a/src/org/codehaus/jackson/JsonLocation.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.codehaus.jackson; - -import org.codehaus.jackson.annotate.JsonCreator; -import org.codehaus.jackson.annotate.JsonProperty; - -/** - * Object that encapsulates Location information used for reporting - * parsing (or potentially generation) errors, as well as current location - * within input streams. - */ -public class JsonLocation - implements java.io.Serializable // as per [JACKSON-168] -{ - private static final long serialVersionUID = 1L; - - /** - * Shared immutable "N/A location" that can be returned to indicate - * that no location information is available - * - * @since 1.3 - */ - public final static JsonLocation NA = new JsonLocation("N/A", -1L, -1L, -1, -1); - - final long _totalBytes; - final long _totalChars; - - final int _lineNr; - final int _columnNr; - - /** - * Displayable description for input source: file path, url - */ - final Object _sourceRef; - - public JsonLocation(Object srcRef, long totalChars, int lineNr, int colNr) - { - /* Unfortunately, none of legal encodings are straight single-byte - * encodings. Could determine offset for UTF-16/UTF-32, but the - * most important one is UTF-8... - * so for now, we'll just not report any real byte count - */ - this(srcRef, -1L, totalChars, lineNr, colNr); - } - - @JsonCreator - public JsonLocation(@JsonProperty("sourceRef") Object sourceRef, - @JsonProperty("byteOffset") long totalBytes, - @JsonProperty("charOffset") long totalChars, - @JsonProperty("lineNr") int lineNr, - @JsonProperty("columnNr") int columnNr) - { - _sourceRef = sourceRef; - _totalBytes = totalBytes; - _totalChars = totalChars; - _lineNr = lineNr; - _columnNr = columnNr; - } - - /** - * Reference to the original resource being read, if one available. - * For example, when a parser has been constructed by passing - * a {@link java.io.File} instance, this method would return - * that File. Will return null if no such reference is available, - * for example when {@link java.io.InputStream} was used to - * construct the parser instance. - */ - public Object getSourceRef() { return _sourceRef; } - - /** - * @return Line number of the location (1-based) - */ - public int getLineNr() { return _lineNr; } - - /** - * @return Column number of the location (1-based) - */ - public int getColumnNr() { return _columnNr; } - - /** - * @return Character offset within underlying stream, reader or writer, - * if available; -1 if not. - */ - public long getCharOffset() { return _totalChars; } - - /** - * @return Byte offset within underlying stream, reader or writer, - * if available; -1 if not. - */ - public long getByteOffset() - { - return _totalBytes; - } - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(80); - sb.append("[Source: "); - if (_sourceRef == null) { - sb.append("UNKNOWN"); - } else { - sb.append(_sourceRef.toString()); - } - sb.append("; line: "); - sb.append(_lineNr); - sb.append(", column: "); - sb.append(_columnNr); - sb.append(']'); - return sb.toString(); - } - - @Override - public int hashCode() - { - int hash = (_sourceRef == null) ? 1 : _sourceRef.hashCode(); - hash ^= _lineNr; - hash += _columnNr; - hash ^= (int) _totalChars; - hash += (int) _totalBytes; - return hash; - } - - @Override - public boolean equals(Object other) - { - if (other == this) return true; - if (other == null) return false; - if (!(other instanceof JsonLocation)) return false; - JsonLocation otherLoc = (JsonLocation) other; - - if (_sourceRef == null) { - if (otherLoc._sourceRef != null) return false; - } else if (!_sourceRef.equals(otherLoc._sourceRef)) return false; - - return (_lineNr == otherLoc._lineNr) - && (_columnNr == otherLoc._columnNr) - && (_totalChars == otherLoc._totalChars) - && (getByteOffset() == otherLoc.getByteOffset()) - ; - } -} diff --git a/src/org/codehaus/jackson/JsonNode.java b/src/org/codehaus/jackson/JsonNode.java deleted file mode 100644 index 8505c2ebf4..0000000000 --- a/src/org/codehaus/jackson/JsonNode.java +++ /dev/null @@ -1,417 +0,0 @@ -package org.codehaus.jackson; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.*; - - -/** - * Base class for all JSON nodes, which form the basis of JSON - * Tree Model that Jackson implements. - * One way to think of these nodes is to considere them - * similar to DOM nodes in XML DOM trees. - *

- * As a general design rule, most accessors ("getters") are included - * in this base class, to allow for traversing structure without - * type casts. Most mutators, however, need to be accessed through - * specific sub-classes. This seems sensible because proper type - * information is generally available when building or modifying - * trees, but less often when reading a tree (newly built from - * parsed Json content). - *

- * Actual concrete sub-classes can be found from package - * {@link org.codehaus.jackson.node}. - */ -public abstract class JsonNode - implements Iterable -{ - final static List NO_NODES = Collections.emptyList(); - final static List NO_STRINGS = Collections.emptyList(); - - protected JsonNode() { } - - /* - //////////////////////////////////////////////////// - // Public API, type introspection - //////////////////////////////////////////////////// - */ - - // // First high-level division between values, containers and "missing" - - /** - * Method that returns true for all value nodes: ones that - * are not containers, and that do not represent "missing" nodes - * in the path. Such value nodes represent String, Number, Boolean - * and null values from JSON. - *

- * Note: one and only one of methods {@link #isValueNode}, - * {@link #isContainerNode} and {@link #isMissingNode} ever - * returns true for any given node. - */ - public boolean isValueNode() { return false; } - - /** - * Method that returns true for container nodes: Arrays and Objects. - *

- * Note: one and only one of methods {@link #isValueNode}, - * {@link #isContainerNode} and {@link #isMissingNode} ever - * returns true for any given node. - */ - public boolean isContainerNode() { return false; } - - /** - * Method that returns true for "virtual" nodes which represent - * missing entries constructed by path accessor methods when - * there is no actual node matching given criteria. - *

- * Note: one and only one of methods {@link #isValueNode}, - * {@link #isContainerNode} and {@link #isMissingNode} ever - * returns true for any given node. - */ - public boolean isMissingNode() { return false; } - - // // Then more specific type introspection - // // (along with defaults to be overridden) - - /** - * @return True if this node represents Json Array - */ - public boolean isArray() { return false; } - - /** - * @return True if this node represents Json Object - */ - public boolean isObject() { return false; } - - /** - * Method that can be used to check if the node is a wrapper - * for a POJO ("Plain Old Java Object" aka "bean". - * Returns true only for - * instances of {@link org.codehaus.jackson.node.POJONode}. - * - * @return True if this node wraps a POJO - */ - public boolean isPojo() { return false; } - - /** - * @return True if this node represents a numeric Json - * value - */ - public boolean isNumber() { return false; } - - /** - * @return True if this node represents an integral (integer) - * numeric Json value - */ - public boolean isIntegralNumber() { return false; } - - /** - * @return True if this node represents a non-integral - * numeric Json value - */ - public boolean isFloatingPointNumber() { return false; } - - /** - * @return True if this node represents an integral - * numeric Json value that withs in Java int value space - */ - public boolean isInt() { return false; } - - /** - * @return True if this node represents an integral - * numeric Json value that fits in Java long value space - * (but not int value space, i.e. {@link #isInt} returns false) - */ - public boolean isLong() { return false; } - - public boolean isDouble() { return false; } - public boolean isBigDecimal() { return false; } - public boolean isBigInteger() { return false; } - - public boolean isTextual() { return false; } - - /** - * Method that can be used to check if this node was created from - * Json boolean value (literals "true" and "false"). - */ - public boolean isBoolean() { return false; } - - /** - * Method that can be used to check if this node was created from - * Json liternal null value. - */ - public boolean isNull() { return false; } - - /** - * Method that can be used to check if this node represents - * binary data (Base64 encoded). Although this will be externally - * written as Json String value, {@link #isTextual} will - * return false if this method returns true. - * - * @return True if this node represents base64 encoded binary data - */ - public boolean isBinary() { return false; } - - /** - * Method that can be used for efficient type detection - * when using stream abstraction for traversing nodes. - * Will return the first {@link JsonToken} that equivalent - * stream event would produce (for most nodes there is just - * one token but for structured/container types multiple) - * - * @since 1.3 - */ - public abstract JsonToken asToken(); - - /** - * If this node is a numeric type (as per {@link #isNumber}), - * returns native type that node uses to store the numeric - * value. - */ - public abstract JsonParser.NumberType getNumberType(); - - /* - //////////////////////////////////////////////////// - // Public API, value access - //////////////////////////////////////////////////// - */ - - /** - * Method to use for accessing String values. - * Does NOT do any conversions for non-String value nodes; - * for non-String values (ones for which {@link #isTextual} returns - * false) null will be returned. - * For String values, null is never returned (but empty Strings may be) - * - * @return Textual value this node contains, iff it is a textual - * json node (comes from Json String value entry) - */ - public String getTextValue() { return null; } - - /** - * Method to use for accessing binary content of binary nodes (nodes - * for which {@link #isBinary} returns true); or for Text Nodes - * (ones for which {@link #getTextValue} returns non-null value), - * to read decoded base64 data. - * For other types of nodes, returns null. - * - * @return Binary data this node contains, iff it is a binary - * node; null otherwise - */ - public byte[] getBinaryValue() throws IOException - { - return null; - } - - public boolean getBooleanValue() { return false; } - - /** - * Returns numeric value for this node, if and only if - * this node is numeric ({@link #isNumber} returns true); otherwise - * returns null - * - * @return Number value this node contains, if any (null for non-number - * nodes). - */ - public Number getNumberValue() { return null; } - - public int getIntValue() { return 0; } - public long getLongValue() { return 0L; } - public double getDoubleValue() { return 0.0; } - public BigDecimal getDecimalValue() { return BigDecimal.ZERO; } - public BigInteger getBigIntegerValue() { return BigInteger.ZERO; } - - /** - * Method for accessing value of the specified element of - * an array node. For other nodes, null is always returned. - *

- * For array nodes, index specifies - * exact location within array and allows for efficient iteration - * over child elements (underlying storage is guaranteed to - * be efficiently indexable, i.e. has random-access to elements). - * If index is less than 0, or equal-or-greater than - * node.size(), null is returned; no exception is - * thrown for any index. - * - * @return Node that represent value of the specified element, - * if this node is an array and has specified element. - * Null otherwise. - */ - public JsonNode get(int index) { return null; } - - /** - * Method for accessing value of the specified field of - * an object node. If this node is not an object (or it - * does not have a value for specified field name), or - * if there is no field with such name, null is returned. - * - * @return Node that represent value of the specified field, - * if this node is an object and has value for the specified - * field. Null otherwise. - */ - public JsonNode get(String fieldName) { return null; } - - /** - * Alias for {@link #get(String)}. - * - * @deprecated Use {@link #get(String)} instead. - */ - @Deprecated - public final JsonNode getFieldValue(String fieldName) { return get(fieldName); } - - /** - * Alias for {@link #get(int)}. - * - * @deprecated Use {@link #get(int)} instead. - */ - @Deprecated - public final JsonNode getElementValue(int index) { return get(index); } - - - /** - * Method that will return valid String representation of - * the container value, if the node is a value node - * (method {@link #isValueNode} returns true), otherwise null. - *

- * Note: to serialize nodes of any type, you should call - * {@link #toString} instead. - */ - public abstract String getValueAsText(); - - /* - //////////////////////////////////////////////////// - // Public API, container access - //////////////////////////////////////////////////// - */ - - /** - * Method that returns number of child nodes this node contains: - * for Array nodes, number of child elements, for Object nodes, - * number of fields, and for all other nodes 0. - * - * @return For non-container nodes returns 0; for arrays number of - * contained elements, and for objects number of fields. - */ - public int size() { return 0; } - - /** - * Same as calling {@link #getElements}; implemented so that - * convenience "for-each" loop can be used for looping over elements - * of Json Array constructs. - */ - public final Iterator iterator() { return getElements(); } - - /** - * Method for accessing all value nodes of this Node, iff - * this node is a Json Array or Object node. In case of Object node, - * field names (keys) are not included, only values. - * For other types of nodes, returns empty iterator. - */ - public Iterator getElements() { return NO_NODES.iterator(); } - - /** - * Method for accessing names of all fields for this Node, iff - * this node is a Json Object node. - */ - public Iterator getFieldNames() { return NO_STRINGS.iterator(); } - - /* - //////////////////////////////////////////////////// - // Public API, path handling - //////////////////////////////////////////////////// - */ - - /** - * This method is similar to {@link #get(String)}, except - * that instead of returning null if no such value exists (due - * to this node not being an object, or object not having value - * for the specified field), - * a "missing node" (node that returns true for - * {@link #isMissingNode}) will be returned. This allows for - * convenient and safe chained access via path calls. - */ - public abstract JsonNode path(String fieldName); - - /** - * Alias of {@link #path(String)}. - * - * @deprecated Use {@link #path(String)} instead - */ - @Deprecated - public final JsonNode getPath(String fieldName) { return path(fieldName); } - - /** - * This method is similar to {@link #get(int)}, except - * that instead of returning null if no such element exists (due - * to index being out of range, or this node not being an array), - * a "missing node" (node that returns true for - * {@link #isMissingNode}) will be returned. This allows for - * convenient and safe chained access via path calls. - */ - public abstract JsonNode path(int index); - - /** - * Alias of {@link #path(int)}. - * - * @deprecated Use {@link #path(int)} instead - */ - @Deprecated - public final JsonNode getPath(int index) { return path(index); } - - /* - //////////////////////////////////////////////////// - // Public API, serialization - //////////////////////////////////////////////////// - */ - - /** - * Method that can be called to serialize this node and - * all of its descendants using specified JSON generator. - * - * @deprecated Use methods that are part of {@link JsonGenerator} - * or {@link org.codehaus.jackson.map.ObjectMapper} - * instead. - */ - public abstract void writeTo(JsonGenerator jg) - throws IOException, JsonGenerationException; - - /* - //////////////////////////////////////////////////// - // Public API: converting to/from Streaming API - //////////////////////////////////////////////////// - */ - - - /** - * Method for constructing a {@link JsonParser} instance for - * iterating over contents of the tree that this - * node is root of. - * Functionally equivalent to first serializing tree - * using {@link #writeTo} and then re-parsing but much - * more efficient. - */ - public abstract JsonParser traverse(); - - /* - //////////////////////////////////////////////////// - // Overridden standard methods - //////////////////////////////////////////////////// - */ - - /** - *

- * Note: marked as abstract to ensure all implementation - * classes define it properly. - */ - @Override - public abstract String toString(); - - /** - *

- * Note: marked as abstract to ensure all implementation - * classes define it properly. - */ - @Override - public abstract boolean equals(Object o); -} diff --git a/src/org/codehaus/jackson/JsonParseException.java b/src/org/codehaus/jackson/JsonParseException.java deleted file mode 100644 index 32038eeedd..0000000000 --- a/src/org/codehaus/jackson/JsonParseException.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.codehaus.jackson; - -/** - * Exception type for parsing problems, used when non-well-formed content - * (content that does not conform to JSON syntax as per specification) - * is encountered. - */ -public class JsonParseException - extends JsonProcessingException -{ - final static long serialVersionUID = 123; // Stupid eclipse... - - public JsonParseException(String msg, JsonLocation loc) - { - super(msg, loc); - } - - public JsonParseException(String msg, JsonLocation loc, Throwable root) - { - super(msg, loc, root); - } -} diff --git a/src/org/codehaus/jackson/JsonParser.java b/src/org/codehaus/jackson/JsonParser.java deleted file mode 100644 index ac5aff1f85..0000000000 --- a/src/org/codehaus/jackson/JsonParser.java +++ /dev/null @@ -1,945 +0,0 @@ -/* Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in file LICENSE, included with - * the source code and binary code bundles. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.codehaus.jackson; - -import java.io.*; -import java.math.BigDecimal; -import java.math.BigInteger; - -import org.codehaus.jackson.type.TypeReference; - -/** - * Base class that defines public API for reading JSON content. - * Instances are created using factory methods of - * a {@link JsonFactory} instance. - * - * @author Tatu Saloranta - */ -public abstract class JsonParser - implements Closeable -{ - private final static int MIN_BYTE_I = (int) Byte.MIN_VALUE; - private final static int MAX_BYTE_I = (int) Byte.MAX_VALUE; - - private final static int MIN_SHORT_I = (int) Short.MIN_VALUE; - private final static int MAX_SHORT_I = (int) Short.MAX_VALUE; - - /** - * Enumeration of possible "native" (optimal) types that can be - * used for numbers. - */ - public enum NumberType { - INT, LONG, BIG_INTEGER, FLOAT, DOUBLE, BIG_DECIMAL - }; - - /** - * Enumeration that defines all togglable features for parsers. - */ - public enum Feature { - /** - * Feature that determines whether parser will automatically - * close underlying input source that is NOT owned by the - * parser. If disabled, calling application has to separately - * close the underlying {@link InputStream} and {@link Reader} - * instances used to create the parser. If enabled, parser - * will handle closing, as long as parser itself gets closed: - * this happens when end-of-input is encountered, or parser - * is closed by a call to {@link JsonParser#close}. - *

- * Feature is enabled by default. - */ - AUTO_CLOSE_SOURCE(true) - - /** - * Feature that determines whether parser will allow use - * of Java/C++ style comments (both '/'+'*' and - * '//' varieties) within parsed content or not. - *

- * Since JSON specification does not mention comments as legal - * construct, - * this is a non-standard feature; however, in the wild - * this is extensively used. As such, feature is - * disabled by default for parsers and must be - * explicitly enabled (via factory or parser instance). - *

- * This feature can be changed for parser instances. - */ - ,ALLOW_COMMENTS(false) - - /** - * Feature that determines whether parser will allow use - * of unquoted field names (which is allowed by Javascript, - * but not by JSON specification). - *

- * Since JSON specification requires use of double quotes for - * field names, - * this is a non-standard feature, and as such disabled by - * default. - *

- * This feature can be changed for parser instances. - * - * @since 1.2 - */ - ,ALLOW_UNQUOTED_FIELD_NAMES(false) - - /** - * Feature that determines whether parser will allow use - * of single quotes (apostrophe, character '\'') for - * quoting Strings (names and String values). If so, - * this is in addition to other acceptabl markers. - * but not by JSON specification). - *

- * Since JSON specification requires use of double quotes for - * field names, - * this is a non-standard feature, and as such disabled by - * default. - *

- * This feature can be changed for parser instances. - * - * @since 1.3 - */ - ,ALLOW_SINGLE_QUOTES(false) - - /** - * Feature that determines whether parser will allow - * JSON Strings to contain unquoted control characters - * (ASCII characters with value less than 32, including - * tab and line feed characters) or not. - * If feature is set false, an exception is thrown if such a - * character is encountered. - *

- * Since JSON specification requires quoting for all - * control characters, - * this is a non-standard feature, and as such disabled by - * default. - *

- * This feature can be changed for parser instances. - * - * @since 1.4 - */ - ,ALLOW_UNQUOTED_CONTROL_CHARS(false) - - /** - * Feature that determines whether JSON object field names are - * to be canonicalized using {@link String#intern} or not: - * if enabled, all field names will be intern()ed (and caller - * can count on this being true for all such names); if disabled, - * no intern()ing is done. There may still be basic - * canonicalization (that is, same String will be used to represent - * all identical object property names for a single document). - *

- * Note: this setting only has effect if - * {@link #CANONICALIZE_FIELD_NAMES} is true -- otherwise no - * canonicalization of any sort is done. - * - * @since 1.3 - */ - ,INTERN_FIELD_NAMES(true) - - /** - * Feature that determines whether JSON object field names are - * to be canonicalized (details of how canonicalization is done - * then further specified by - * {@link #INTERN_FIELD_NAMES}). - * - * @since 1.5 - */ - ,CANONICALIZE_FIELD_NAMES(true) - - // 14-Sep-2009, Tatu: This would be [JACKSON-142] implementation: - /* - * Feature that allows parser to recognize set of - * "Not-a-Number" (NaN) tokens as legal floating number - * values (similar to how many other data formats and - * programming language source code allows it). - * Specific subset contains values that - * XML Schema - * (see section 3.2.4.1, Lexical Representation) - * allows (tokens are quoted contents, not including quotes): - *

    - *
  • "INF" (for positive infinity) - *
  • "-INF" (for negative infinity) - *
  • "NaN" (for other not-a-numbers, like result of division by zero) - *
- - ,ALLOW_NON_NUMERIC_NUMBERS(false) - */ - - ; - - final boolean _defaultState; - - /** - * Method that calculates bit set (flags) of all features that - * are enabled by default. - */ - public static int collectDefaults() - { - int flags = 0; - for (Feature f : values()) { - if (f.enabledByDefault()) { - flags |= f.getMask(); - } - } - return flags; - } - - private Feature(boolean defaultState) { - _defaultState = defaultState; - } - - public boolean enabledByDefault() { return _defaultState; } - - public boolean enabledIn(int flags) { return (flags & getMask()) != 0; } - - public int getMask() { return (1 << ordinal()); } - }; - - /* - /*************************************************** - /* Minimal configuration state - /*************************************************** - */ - - /** - * Bit flag composed of bits that indicate which - * {@link org.codehaus.jackson.JsonParser.Feature}s - * are enabled. - */ - protected int _features; - - /* - /*************************************************** - /* Minimal generic state - /*************************************************** - */ - - /** - * Last token retrieved via {@link #nextToken}, if any. - * Null before the first call to nextToken(), - * as well as if token has been explicitly cleared - * (by call to {@link #clearCurrentToken}) - */ - protected JsonToken _currToken; - - /** - * Last cleared token, if any: that is, value that was in - * effect when {@link #clearCurrentToken} was called. - */ - protected JsonToken _lastClearedToken; - - /* - /*************************************************** - /* Construction, init - /*************************************************** - */ - - protected JsonParser() { } - - /** - * Accessor for {@link ObjectCodec} associated with this - * parser, if any. Codec is used by {@link #readValueAs(Class)} - * method (and its variants). - * - * @since 1.3 - */ - public abstract ObjectCodec getCodec(); - - /** - * Setter that allows defining {@link ObjectCodec} associated with this - * parser, if any. Codec is used by {@link #readValueAs(Class)} - * method (and its variants). - * - * @since 1.3 - */ - public abstract void setCodec(ObjectCodec c); - - /* - /*************************************************** - /* Closeable implementation - /*************************************************** - */ - - /** - * Closes the parser so that no further iteration or data access - * can be made; will also close the underlying input source - * if parser either owns the input source, or feature - * {@link Feature#AUTO_CLOSE_SOURCE} is enabled. - * Whether parser owns the input source depends on factory - * method that was used to construct instance (so check - * {@link org.codehaus.jackson.JsonFactory} for details, - * but the general - * idea is that if caller passes in closable resource (such - * as {@link InputStream} or {@link Reader}) parser does NOT - * own the source; but if it passes a reference (such as - * {@link java.io.File} or {@link java.net.URL} and creates - * stream or reader it does own them. - */ - public abstract void close() throws IOException; - - /* - /*************************************************** - /* Public API, configuration - /*************************************************** - */ - - /** - * Method for enabling specified parser feature - * (check {@link Feature} for list of features) - * - * @since 1.2 - */ - public JsonParser enable(Feature f) - { - _features |= f.getMask(); - return this; - } - - /** - * Method for disabling specified feature - * (check {@link Feature} for list of features) - * - * @since 1.2 - */ - public JsonParser disable(Feature f) - { - _features &= ~f.getMask(); - return this; - } - - /** - * Method for enabling or disabling specified feature - * (check {@link Feature} for list of features) - * - * @since 1.2 - */ - public JsonParser configure(Feature f, boolean state) - { - if (state) { - enableFeature(f); - } else { - disableFeature(f); - } - return this; - } - - /** - * Method for checking whether specified {@link Feature} - * is enabled. - * - * @since 1.2 - */ - public boolean isEnabled(Feature f) { - return (_features & f.getMask()) != 0; - } - - /** @deprecated Use {@link #configure} instead - */ - public void setFeature(Feature f, boolean state) { configure(f, state); } - - /** @deprecated Use {@link #enable(Feature)} instead - */ - public void enableFeature(Feature f) { enable(f); } - - /** @deprecated Use {@link #disable(Feature)} instead - */ - public void disableFeature(Feature f) { disable(f); } - - /** @deprecated Use {@link #isEnabled(Feature)} instead - */ - public final boolean isFeatureEnabled(Feature f) { return isEnabled(f); } - - - /* - /*************************************************** - /* Public API, traversal - /*************************************************** - */ - - /** - * Main iteration method, which will advance stream enough - * to determine type of the next token, if any. If none - * remaining (stream has no content other than possible - * white space before ending), null will be returned. - * - * @return Next token from the stream, if any found, or null - * to indicate end-of-input - */ - public abstract JsonToken nextToken() - throws IOException, JsonParseException; - - /** - * Iteration method that will advance stream enough - * to determine type of the next token that is a value type - * (including Json Array and Object start/end markers). - * Or put another way, nextToken() will be called once, - * and if {@link JsonToken#FIELD_NAME} is returned, another - * time to get the value for the field. - * Method is most useful for iterating over value entries - * of Json objects; field name will still be available - * by calling {@link #getCurrentName} when parser points to - * the value. - * - * @return Next non-field-name token from the stream, if any found, - * or null to indicate end-of-input (or, for non-blocking - * parsers, {@link JsonToken#NOT_AVAILABLE} if no tokens were - * available yet) - * - * @since 0.9.7 - */ - public JsonToken nextValue() - throws IOException, JsonParseException - { - /* Implementation should be as trivial as follows; only - * needs to change if we are to skip other tokens (for - * example, if comments were exposed as tokens) - */ - JsonToken t = nextToken(); - if (t == JsonToken.FIELD_NAME) { - t = nextToken(); - } - return t; - } - - /** - * Method that will skip all child tokens of an array or - * object token that the parser currently points to, - * iff stream points to - * {@link JsonToken#START_OBJECT} or {@link JsonToken#START_ARRAY}. - * If not, it will do nothing. - * After skipping, stream will point to matching - * {@link JsonToken#END_OBJECT} or {@link JsonToken#END_ARRAY} - * (possibly skipping nested pairs of START/END OBJECT/ARRAY tokens - * as well as value tokens). - * The idea is that after calling this method, application - * will call {@link #nextToken} to point to the next - * available token, if any. - */ - public abstract JsonParser skipChildren() - throws IOException, JsonParseException; - - /** - * Method that can be called to determine whether this parser - * is closed or not. If it is closed, no new tokens can be - * retrieved by calling {@link #nextToken} (and the underlying - * stream may be closed). Closing may be due to an explicit - * call to {@link #close} or because parser has encountered - * end of input. - */ - public abstract boolean isClosed(); - - /* - /*************************************************** - /* Public API, token accessors - /*************************************************** - */ - - /** - * Accessor to find which token parser currently points to, if any; - * null will be returned if none. - * If return value is non-null, data associated with the token - * is available via other accessor methods. - * - * @return Type of the token this parser currently points to, - * if any: null before any tokens have been read, and - * after end-of-input has been encountered, as well as - * if the current token has been explicitly cleared. - */ - public JsonToken getCurrentToken() { - return _currToken; - } - - /** - * Method for checking whether parser currently points to - * a token (and data for that token is available). - * Equivalent to check for parser.getCurrentToken() != null. - * - * @return True if the parser just returned a valid - * token via {@link #nextToken}; false otherwise (parser - * was just constructed, encountered end-of-input - * and returned null from {@link #nextToken}, or the token - * has been consumed) - */ - public boolean hasCurrentToken() { - return _currToken != null; - } - - - /** - * Method called to "consume" the current token by effectively - * removing it so that {@link #hasCurrentToken} returns false, and - * {@link #getCurrentToken} null). - * Cleared token value can still be accessed by calling - * {@link #getLastClearedToken} (if absolutely needed), but - * usually isn't. - *

- * Method was added to be used by the optional data binder, since - * it has to be able to consume last token used for binding (so that - * it will not be used again). - */ - public void clearCurrentToken() { - if (_currToken != null) { - _lastClearedToken = _currToken; - _currToken = null; - } - } - - /** - * Method that can be called to get the name associated with - * the current token: for {@link JsonToken#FIELD_NAME}s it will - * be the same as what {@link #getText} returns; - * for field values it will be preceding field name; - * and for others (array values, root-level values) null. - */ - public abstract String getCurrentName() - throws IOException, JsonParseException; - - /** - * Method that can be used to access current parsing context reader - * is in. There are 3 different types: root, array and object contexts, - * with slightly different available information. Contexts are - * hierarchically nested, and can be used for example for figuring - * out part of the input document that correspond to specific - * array or object (for highlighting purposes, or error reporting). - * Contexts can also be used for simple xpath-like matching of - * input, if so desired. - */ - public abstract JsonStreamContext getParsingContext(); - - /** - * Method that return the starting location of the current - * token; that is, position of the first character from input - * that starts the current token. - */ - public abstract JsonLocation getTokenLocation(); - - /** - * Method that returns location of the last processed character; - * usually for error reporting purposes. - */ - public abstract JsonLocation getCurrentLocation(); - - /** - * Method that can be called to get the last token that was - * cleared using {@link #clearCurrentToken}. This is not necessarily - * the latest token read. - * Will return null if no tokens have been cleared, - * or if parser has been closed. - */ - public JsonToken getLastClearedToken() { - return _lastClearedToken; - } - - /* - /*************************************************** - /* Public API, access to token information, text - /*************************************************** - */ - - /** - * Method for accessing textual representation of the current token; - * if no current token (before first call to {@link #nextToken}, or - * after encountering end-of-input), returns null. - * Method can be called for any token type. - */ - public abstract String getText() - throws IOException, JsonParseException; - - /** - * Method similar to {@link #getText}, but that will return - * underlying (unmodifiable) character array that contains - * textual value, instead of constructing a String object - * to contain this information. - * Note, however, that: - *

    - *
  • Textual contents are not guaranteed to start at - * index 0 (rather, call {@link #getTextOffset}) to - * know the actual offset - *
  • - *
  • Length of textual contents may be less than the - * length of returned buffer: call {@link #getTextLength} - * for actual length of returned content. - *
  • - *
- *

- * Note that caller MUST NOT modify the returned - * character array in any way -- doing so may corrupt - * current parser state and render parser instance useless. - *

- * The only reason to call this method (over {@link #getText}) - * is to avoid construction of a String object (which - * will make a copy of contents). - */ - public abstract char[] getTextCharacters() - throws IOException, JsonParseException; - - /** - * Accessor used with {@link #getTextCharacters}, to know length - * of String stored in returned buffer. - * - * @return Number of characters within buffer returned - * by {@link #getTextCharacters} that are part of - * textual content of the current token. - */ - public abstract int getTextLength() - throws IOException, JsonParseException; - - /** - * Accessor used with {@link #getTextCharacters}, to know offset - * of the first text content character within buffer. - * - * @return Offset of the first character within buffer returned - * by {@link #getTextCharacters} that is part of - * textual content of the current token. - */ - public abstract int getTextOffset() - throws IOException, JsonParseException; - - /* - /*************************************************** - /* Public API, access to token information, numeric - /*************************************************** - */ - - /** - * Generic number value accessor method that will work for - * all kinds of numeric values. It will return the optimal - * (simplest/smallest possibl) wrapper object that can - * express the numeric value just parsed. - */ - public abstract Number getNumberValue() - throws IOException, JsonParseException; - - /** - * If current token is of type - * {@link JsonToken#VALUE_NUMBER_INT} or - * {@link JsonToken#VALUE_NUMBER_FLOAT}, returns - * one of {@link NumberType} constants; otherwise returns null. - */ - public abstract NumberType getNumberType() - throws IOException, JsonParseException; - - /** - * Numeric accessor that can be called when the current - * token is of type {@link JsonToken#VALUE_NUMBER_INT} and - * it can be expressed as a value of Java byte primitive type. - * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT}; - * if so, it is equivalent to calling {@link #getDoubleValue} - * and then casting; except for possible overflow/underflow - * exception. - *

- * Note: if the resulting integer value falls outside range of - * Java byte, a {@link JsonParseException} - * will be thrown to indicate numeric overflow/underflow. - */ - public byte getByteValue() - throws IOException, JsonParseException - { - int value = getIntValue(); - // So far so good: but does it fit? - if (value < MIN_BYTE_I || value > MAX_BYTE_I) { - throw _constructError("Numeric value ("+getText()+") out of range of Java byte"); - } - return (byte) value; - } - - /** - * Numeric accessor that can be called when the current - * token is of type {@link JsonToken#VALUE_NUMBER_INT} and - * it can be expressed as a value of Java short primitive type. - * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT}; - * if so, it is equivalent to calling {@link #getDoubleValue} - * and then casting; except for possible overflow/underflow - * exception. - *

- * Note: if the resulting integer value falls outside range of - * Java short, a {@link JsonParseException} - * will be thrown to indicate numeric overflow/underflow. - */ - public short getShortValue() - throws IOException, JsonParseException - { - int value = getIntValue(); - if (value < MIN_SHORT_I || value > MAX_SHORT_I) { - throw _constructError("Numeric value ("+getText()+") out of range of Java short"); - } - return (short) value; - } - - /** - * Numeric accessor that can be called when the current - * token is of type {@link JsonToken#VALUE_NUMBER_INT} and - * it can be expressed as a value of Java int primitive type. - * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT}; - * if so, it is equivalent to calling {@link #getDoubleValue} - * and then casting; except for possible overflow/underflow - * exception. - *

- * Note: if the resulting integer value falls outside range of - * Java int, a {@link JsonParseException} - * may be thrown to indicate numeric overflow/underflow. - */ - public abstract int getIntValue() - throws IOException, JsonParseException; - - /** - * Numeric accessor that can be called when the current - * token is of type {@link JsonToken#VALUE_NUMBER_INT} and - * it can be expressed as a Java long primitive type. - * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT}; - * if so, it is equivalent to calling {@link #getDoubleValue} - * and then casting to int; except for possible overflow/underflow - * exception. - *

- * Note: if the token is an integer, but its value falls - * outside of range of Java long, a {@link JsonParseException} - * may be thrown to indicate numeric overflow/underflow. - */ - public abstract long getLongValue() - throws IOException, JsonParseException; - - /** - * Numeric accessor that can be called when the current - * token is of type {@link JsonToken#VALUE_NUMBER_INT} and - * it can not be used as a Java long primitive type due to its - * magnitude. - * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT}; - * if so, it is equivalent to calling {@link #getDecimalValue} - * and then constructing a {@link BigInteger} from that value. - */ - public abstract BigInteger getBigIntegerValue() - throws IOException, JsonParseException; - - /** - * Numeric accessor that can be called when the current - * token is of type {@link JsonToken#VALUE_NUMBER_FLOAT} and - * it can be expressed as a Java float primitive type. - * It can also be called for {@link JsonToken#VALUE_NUMBER_INT}; - * if so, it is equivalent to calling {@link #getLongValue} - * and then casting; except for possible overflow/underflow - * exception. - *

- * Note: if the value falls - * outside of range of Java float, a {@link JsonParseException} - * will be thrown to indicate numeric overflow/underflow. - */ - public abstract float getFloatValue() - throws IOException, JsonParseException; - - /** - * Numeric accessor that can be called when the current - * token is of type {@link JsonToken#VALUE_NUMBER_FLOAT} and - * it can be expressed as a Java double primitive type. - * It can also be called for {@link JsonToken#VALUE_NUMBER_INT}; - * if so, it is equivalent to calling {@link #getLongValue} - * and then casting; except for possible overflow/underflow - * exception. - *

- * Note: if the value falls - * outside of range of Java double, a {@link JsonParseException} - * will be thrown to indicate numeric overflow/underflow. - */ - public abstract double getDoubleValue() - throws IOException, JsonParseException; - - /** - * Numeric accessor that can be called when the current - * token is of type {@link JsonToken#VALUE_NUMBER_FLOAT} or - * {@link JsonToken#VALUE_NUMBER_INT}. No under/overflow exceptions - * are ever thrown. - */ - public abstract BigDecimal getDecimalValue() - throws IOException, JsonParseException; - - /** - * Convenience accessor that can be called when the current - * token is {@link JsonToken#VALUE_TRUE} or - * {@link JsonToken#VALUE_FALSE}. - *

- * Note: if the token is not of above-mentioned boolean types, - an integer, but its value falls - * outside of range of Java long, a {@link JsonParseException} - * may be thrown to indicate numeric overflow/underflow. - * - * @since 1.3 - */ - public boolean getBooleanValue() - throws IOException, JsonParseException - { - if (_currToken == JsonToken.VALUE_TRUE) return true; - if (_currToken == JsonToken.VALUE_FALSE) return false; - throw new JsonParseException("Current token ("+_currToken+") not of boolean type", getCurrentLocation()); - } - - /** - * Accessor that can be called if (and only if) the current token - * is {@link JsonToken#VALUE_EMBEDDED_OBJECT}. For other token types, - * null is returned. - *

- * Note: only some specialized parser implementations support - * embedding of objects (usually ones that are facades on top - * of non-streaming sources, such as object trees). - * - * @since 1.3 - */ - public Object getEmbeddedObject() - throws IOException, JsonParseException - { - // By default we will always return null - return null; - } - - /* - /*************************************************** - /* Public API, access to token information, binary - /*************************************************** - */ - - /** - * Method that can be used to read (and consume -- results - * may not be accessible using other methods after the call) - * base64-encoded binary data - * included in the current textual json value. - * It works similar to getting String value via {@link #getText} - * and decoding result (except for decoding part), - * but should be significantly more performant. - *

- * Note that non-decoded textual contents of the current token - * are not guaranteed to be accessible after this method - * is called. Current implementation, for example, clears up - * textual content during decoding. - * Decoded binary content, however, will be retained until - * parser is advanced to the next event. - * - * @param b64variant Expected variant of base64 encoded - * content (see {@link Base64Variants} for definitions - * of "standard" variants). - * - * @return Decoded binary data - */ - public abstract byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException; - - /** - * Convenience alternative to {@link #getBinaryValue(Base64Variant)} - * that defaults to using - * {@link Base64Variants#getDefaultVariant} as the default encoding. - */ - public byte[] getBinaryValue() throws IOException, JsonParseException - { - return getBinaryValue(Base64Variants.getDefaultVariant()); - } - - /* - /*************************************************** - /* Public API, optional data binding functionality - /*************************************************** - */ - - /** - * Method to deserialize Json content into a non-container - * type (it can be an array type, however): typically a bean, array - * or a wrapper type (like {@link java.lang.Boolean}). - * Note: method can only be called if the parser has - * an object codec assigned; this is true for parsers constructed - * by {@link org.codehaus.jackson.map.MappingJsonFactory} but - * not for {@link JsonFactory} (unless its setCodec - * method has been explicitly called). - *

- * This method may advance the event stream, for structured types - * the current token will be the closing end marker (END_ARRAY, - * END_OBJECT) of the bound structure. For non-structured Json types - * (and for {@link JsonToken#VALUE_EMBEDDED_OBJECT}) - * stream is not advanced. - *

- * Note: this method should NOT be used if the result type is a - * container ({@link java.util.Collection} or {@link java.util.Map}. - * The reason is that due to type erasure, key and value types - * can not be introspected when using this method. - */ - public T readValueAs(Class valueType) - throws IOException, JsonProcessingException - { - ObjectCodec codec = getCodec(); - if (codec == null) { - throw new IllegalStateException("No ObjectCodec defined for the parser, can not deserialize JSON into Java objects"); - } - return codec.readValue(this, valueType); - } - - /** - * Method to deserialize Json content into a Java type, reference - * to which is passed as argument. Type is passed using so-called - * "super type token" - * and specifically needs to be used if the root type is a - * parameterized (generic) container type. - * Note: method can only be called if the parser has - * an object codec assigned; this is true for parsers constructed - * by {@link org.codehaus.jackson.map.MappingJsonFactory} but - * not for {@link JsonFactory} (unless its setCodec - * method has been explicitly called). - *

- * This method may advance the event stream, for structured types - * the current token will be the closing end marker (END_ARRAY, - * END_OBJECT) of the bound structure. For non-structured Json types - * (and for {@link JsonToken#VALUE_EMBEDDED_OBJECT}) - * stream is not advanced. - */ - @SuppressWarnings("unchecked") - public T readValueAs(TypeReference valueTypeRef) - throws IOException, JsonProcessingException - { - ObjectCodec codec = getCodec(); - if (codec == null) { - throw new IllegalStateException("No ObjectCodec defined for the parser, can not deserialize JSON into Java objects"); - } - /* Ugh. Stupid Java type erasure... can't just chain call,s - * must cast here also. - */ - return (T) codec.readValue(this, valueTypeRef); - } - - /** - * Method to deserialize Json content into equivalent "tree model", - * represented by root {@link JsonNode} of resulting model. - * For Json Arrays it will an array node (with child nodes), - * for objects object node (with child nodes), and for other types - * matching leaf node type - */ - public JsonNode readValueAsTree() - throws IOException, JsonProcessingException - { - ObjectCodec codec = getCodec(); - if (codec == null) { - throw new IllegalStateException("No ObjectCodec defined for the parser, can not deserialize JSON into JsonNode tree"); - } - return codec.readTree(this); - } - - /* - /*************************************************** - /* Internal methods - /*************************************************** - */ - - /** - * Helper method for constructing {@link JsonParseException}s - * based on current state of the parser - */ - protected JsonParseException _constructError(String msg) - { - return new JsonParseException(msg, getCurrentLocation()); - } -} diff --git a/src/org/codehaus/jackson/JsonProcessingException.java b/src/org/codehaus/jackson/JsonProcessingException.java deleted file mode 100644 index 329b4717dc..0000000000 --- a/src/org/codehaus/jackson/JsonProcessingException.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.codehaus.jackson; - -/** - * Intermediate base class for all problems encountered when - * processing (parsing, generating) JSON content - * that are not pure I/O problems. - * Regular {@link java.io.IOException}s will be passed through as is. - * Sub-class of {@link java.io.IOException} for convenience. - */ -public class JsonProcessingException - extends java.io.IOException -{ - final static long serialVersionUID = 123; // Stupid eclipse... - - protected JsonLocation mLocation; - - protected JsonProcessingException(String msg, JsonLocation loc, Throwable rootCause) - { - /* Argh. IOException(Throwable,String) is only available starting - * with JDK 1.6... - */ - super(msg); - if (rootCause != null) { - initCause(rootCause); - } - mLocation = loc; - } - - protected JsonProcessingException(String msg) - { - super(msg); - } - - protected JsonProcessingException(String msg, JsonLocation loc) - { - this(msg, loc, null); - } - - protected JsonProcessingException(String msg, Throwable rootCause) - { - this(msg, null, rootCause); - } - - protected JsonProcessingException(Throwable rootCause) - { - this(null, null, rootCause); - } - - public JsonLocation getLocation() - { - return mLocation; - } - - /** - * Default method overridden so that we can add location information - */ - @Override - public String getMessage() - { - String msg = super.getMessage(); - if (msg == null) { - msg = "N/A"; - } - JsonLocation loc = getLocation(); - if (loc != null) { - StringBuilder sb = new StringBuilder(); - sb.append(msg); - sb.append('\n'); - sb.append(" at "); - sb.append(loc.toString()); - return sb.toString(); - } - return msg; - } - - @Override - public String toString() { - return getClass().getName()+": "+getMessage(); - } -} diff --git a/src/org/codehaus/jackson/JsonStreamContext.java b/src/org/codehaus/jackson/JsonStreamContext.java deleted file mode 100644 index ae1127befc..0000000000 --- a/src/org/codehaus/jackson/JsonStreamContext.java +++ /dev/null @@ -1,112 +0,0 @@ -/* Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in file LICENSE, included with - * the source code and binary code bundles. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.codehaus.jackson; - -/** - * Shared base class for streaming processing contexts used during - * reading and writing of Json content using Streaming API. - * This context is also exposed to applications: - * context object can be used by applications to get an idea of - * relative position of the parser/generator within json content - * being processed. This allows for some contextual processing: for - * example, output within Array context can differ from that of - * Object context. - */ -public abstract class JsonStreamContext -{ - // // // Type constants used internally - - protected final static int TYPE_ROOT = 0; - protected final static int TYPE_ARRAY = 1; - protected final static int TYPE_OBJECT = 2; - - protected int _type; - - /** - * Index of the currently processed entry. Starts with -1 to signal - * that no entries have been started, and gets advanced each - * time a new entry is started, either by encountering an expected - * separator, or with new values if no separators are expected - * (the case for root context). - */ - protected int _index; - - /* - ////////////////////////////////////////////////// - // Life-cycle - ////////////////////////////////////////////////// - */ - - public JsonStreamContext(int type) - { - _type = type; - _index = -1; - } - - /* - ////////////////////////////////////////////////// - // Public API, accessors - ////////////////////////////////////////////////// - */ - - public abstract JsonStreamContext getParent(); - - /** - * Method that returns true if this context is an Array context; - * that is, content is being read from or written to a Json Array. - */ - public final boolean inArray() { return _type == TYPE_ARRAY; } - - /** - * Method that returns true if this context is a Root context; - * that is, content is being read from or written to without - * enclosing array or object structure. - */ - public final boolean inRoot() { return _type == TYPE_ROOT; } - - /** - * Method that returns true if this context is an Object context; - * that is, content is being read from or written to a Json Object. - */ - public final boolean inObject() { return _type == TYPE_OBJECT; } - - public final String getTypeDesc() { - switch (_type) { - case TYPE_ROOT: return "ROOT"; - case TYPE_ARRAY: return "ARRAY"; - case TYPE_OBJECT: return "OBJECT"; - } - return "?"; - } - - /** - * @return Number of entries that are complete and started. - */ - public final int getEntryCount() - { - return _index + 1; - } - - /** - * @return Index of the currently processed entry, if any - */ - public final int getCurrentIndex() - { - return (_index < 0) ? 0 : _index; - } - - public abstract String getCurrentName(); -} diff --git a/src/org/codehaus/jackson/JsonToken.java b/src/org/codehaus/jackson/JsonToken.java deleted file mode 100644 index 329434f473..0000000000 --- a/src/org/codehaus/jackson/JsonToken.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.codehaus.jackson; - -/** - * Enumeration for basic token types used for returning results - * of parsing JSON content. - */ -public enum JsonToken -{ - /* Some notes on implementation: - * - * - Entries are to be ordered such that start/end array/object - * markers come first, then field name marker (if any), and - * finally scalar value tokens. This is assumed by some - * typing checks. - */ - - /** - * NOT_AVAILABLE can be returned if {@link JsonParser} - * implementation can not currently return the requested - * token (usually next one), or even if any will be - * available, but that may be able to determine this in - * future. This is the case with non-blocking parsers -- - * they can not block to wait for more data to parse and - * must return something. - * - * @since 0.9.7 - */ - NOT_AVAILABLE(null), - - /** - * START_OBJECT is returned when encountering '{' - * which signals starting of an Object value. - */ - START_OBJECT("{"), - - /** - * START_OBJECT is returned when encountering '}' - * which signals ending of an Object value - */ - END_OBJECT("}"), - - /** - * START_OBJECT is returned when encountering '[' - * which signals starting of an Array value - */ - START_ARRAY("["), - - /** - * START_OBJECT is returned when encountering ']' - * which signals ending of an Array value - */ - END_ARRAY("]"), - - /** - * FIELD_NAME is returned when a String token is encountered - * as a field name (same lexical value, different function) - */ - FIELD_NAME(null), - - /** - * Placeholder token returned when the input source has a concept - * of embedded Object that are not accessible as usual structure - * (of starting with {@link #START_OBJECT}, having values, ending with - * {@link #END_OBJECT}), but as "raw" objects. - *

- * Note: this token is never returned by regular JSON readers, but - * only by readers that expose other kinds of source (like - * {@link JsonNode}-based JSON trees, Maps, Lists and such). - * - * @since 1.1 - */ - VALUE_EMBEDDED_OBJECT(null), - - /** - * VALUE_STRING is returned when a String token is encountered - * in value context (array element, field value, or root-level - * stand-alone value) - */ - VALUE_STRING(null), - - /** - * VALUE_NUMBER_INT is returned when an integer numeric token is - * encountered in value context: that is, a number that does - * not have floating point or exponent marker in it (consists - * only of an optional sign, followed by one or more digits) - */ - VALUE_NUMBER_INT(null), - - /** - * VALUE_NUMBER_INT is returned when a numeric token other - * that is not an integer is encountered: that is, a number that does - * have floating point or exponent marker in it, in addition - * to one or more digits. - */ - VALUE_NUMBER_FLOAT(null), - - /** - * VALUE_TRUE is returned when encountering literal "true" in - * value context - */ - VALUE_TRUE("true"), - - /** - * VALUE_FALSE is returned when encountering literal "false" in - * value context - */ - VALUE_FALSE("false"), - - /** - * VALUE_NULL is returned when encountering literal "null" in - * value context - */ - VALUE_NULL("null") - ; - - final String _serialized; - - final char[] _serializedChars; - - final byte[] _serializedBytes; - - /** - * @param Textual representation for this token, if there is a - * single static representation; null otherwise - */ - JsonToken(String token) - { - if (token == null) { - _serialized = null; - _serializedChars = null; - _serializedBytes = null; - } else { - _serialized = token; - _serializedChars = token.toCharArray(); - // It's all in ascii, can just case... - int len = _serializedChars.length; - _serializedBytes = new byte[len]; - for (int i = 0; i < len; ++i) { - _serializedBytes[i] = (byte) _serializedChars[i]; - } - } - } - - public String asString() { return _serialized; } - public char[] asCharArray() { return _serializedChars; } - public byte[] asByteArray() { return _serializedBytes; } - - public boolean isNumeric() { - return (this == VALUE_NUMBER_INT) || (this == VALUE_NUMBER_FLOAT); - } - - /** - * Method that can be used to check whether this token represents - * a valid non-structured value. This means all tokens other than - * Object/Array start/end markers all field names. - */ - public boolean isScalarValue() { - return ordinal() >= VALUE_STRING.ordinal(); - } -} diff --git a/src/org/codehaus/jackson/ObjectCodec.java b/src/org/codehaus/jackson/ObjectCodec.java deleted file mode 100644 index 3cb7d9a095..0000000000 --- a/src/org/codehaus/jackson/ObjectCodec.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.codehaus.jackson; - -import java.io.IOException; - -import org.codehaus.jackson.type.JavaType; -import org.codehaus.jackson.type.TypeReference; - -/** - * Abstract class that defines the interface that {@link JsonParser} and - * {@link JsonGenerator} use to serialize and deserialize regular - * Java objects (POJOs aka Beans). - *

- * The standard implementation of this class is - * {@link org.codehaus.jackson.map.ObjectMapper}. - */ -public abstract class ObjectCodec -{ - protected ObjectCodec() { } - - /* - ///////////////////////////////////////////////// - // API for serialization (Object-to-JSON) - ///////////////////////////////////////////////// - */ - - /** - * Method to deserialize JSON content into a non-container - * type (it can be an array type, however): typically a bean, array - * or a wrapper type (like {@link java.lang.Boolean}). - *

- * Note: this method should NOT be used if the result type is a - * container ({@link java.util.Collection} or {@link java.util.Map}. - * The reason is that due to type erasure, key and value types - * can not be introspected when using this method. - */ - public abstract T readValue(JsonParser jp, Class valueType) - throws IOException, JsonProcessingException; - - /** - * Method to deserialize JSON content into a Java type, reference - * to which is passed as argument. Type is passed using so-called - * "super type token" (see ) - * and specifically needs to be used if the root type is a - * parameterized (generic) container type. - */ - public abstract T readValue(JsonParser jp, TypeReference valueTypeRef) - throws IOException, JsonProcessingException; - - /** - * Method to deserialize JSON content as tree expressed - * using set of {@link JsonNode} instances. Returns - * root of the resulting tree (where root can consist - * of just a single node if the current event is a - * value event, not container). - */ - public abstract T readValue(JsonParser jp, JavaType valueType) - throws IOException, JsonProcessingException; - - /** - * Method to deserialize JSON content as tree expressed - * using set of {@link JsonNode} instances. Returns - * root of the resulting tree (where root can consist - * of just a single node if the current event is a - * value event, not container). - */ - public abstract JsonNode readTree(JsonParser jp) - throws IOException, JsonProcessingException; - - /* - ///////////////////////////////////////////////// - // API for de-serialization (Json-to-Object) - ///////////////////////////////////////////////// - */ - - /** - * Method to serialize given Java Object, using generator - * provided. - */ - public abstract void writeValue(JsonGenerator jgen, Object value) - throws IOException, JsonProcessingException; - - /** - * Method to serialize given Json Tree, using generator - * provided. - */ - public abstract void writeTree(JsonGenerator jgen, JsonNode rootNode) - throws IOException, JsonProcessingException; - - /* - ///////////////////////////////////////////////// - // API for Tree Model handling - ///////////////////////////////////////////////// - */ - - /** - * Method for construct root level Object nodes - * for Tree Model instances. - * - * @since 1.2 - */ - public abstract JsonNode createObjectNode(); - - /** - * Method for construct root level Array nodes - * for Tree Model instances. - * - * @since 1.2 - */ - public abstract JsonNode createArrayNode(); - - /** - * Method for constructing a {@link JsonParser} for reading - * contents of a JSON tree, as if it was external serialized - * JSON content. - * - * @since 1.3 - */ - public abstract JsonParser treeAsTokens(JsonNode n); - - /* - * Method for constructing a {@link JsonGenerator} that can - * be used to add content to a JSON tree. - * - * @param containerNode Container node to add contents to via created generator. - * If node is not a container node (as per {@link JsonNode#isContainerNode}), - * {@link IllegalArgumentException} will be thrown - * -c public abstract JsonGenerator treeFromTokens(JsonNode containerNode) - throws IllegalArgumentException; - */ - - /** - * Convenience method for converting given JSON tree into instance of specified - * value type. This is equivalent to first constructing a {@link JsonParser} to - * iterate over contents of the tree, and using that parser for data binding. - * - * @since 1.3 - */ - public abstract T treeToValue(JsonNode n, Class valueType) - throws IOException, JsonProcessingException; -} diff --git a/src/org/codehaus/jackson/PrettyPrinter.java b/src/org/codehaus/jackson/PrettyPrinter.java deleted file mode 100644 index 1bd8c86499..0000000000 --- a/src/org/codehaus/jackson/PrettyPrinter.java +++ /dev/null @@ -1,166 +0,0 @@ -package org.codehaus.jackson; - -import java.io.IOException; - -/** - * Interface for objects that implement pretty printer functionality, such - * as indentation. - * Pretty printers are used to add white space in output JSON content, - * to make results more human readable. Usually this means things like adding - * linefeeds and indentation. - */ -public interface PrettyPrinter -{ - /* - ////////////////////////////////////////////////////// - // First methods that act both as events, and expect - // output for correct functioning (i.e something gets - // output even when not pretty-printing) - ////////////////////////////////////////////////////// - */ - - // // // Root-level handling: - - /** - * Method called after a root-level value has been completely - * output, and before another value is to be output. - *

- * Default - * handling (without pretty-printing) will output a space, to - * allow values to be parsed correctly. Pretty-printer is - * to output some other suitable and nice-looking separator - * (tab(s), space(s), linefeed(s) or any combination thereof). - */ - public void writeRootValueSeparator(JsonGenerator jg) - throws IOException, JsonGenerationException; - - // // Object handling - - /** - * Method called when an Object value is to be output, before - * any fields are output. - *

- * Default handling (without pretty-printing) will output - * the opening curly bracket. - * Pretty-printer is - * to output a curly bracket as well, but can surround that - * with other (white-space) decoration. - */ - public void writeStartObject(JsonGenerator jg) - throws IOException, JsonGenerationException; - - /** - * Method called after an Object value has been completely output - * (minus closing curly bracket). - *

- * Default handling (without pretty-printing) will output - * the closing curly bracket. - * Pretty-printer is - * to output a curly bracket as well, but can surround that - * with other (white-space) decoration. - * - * @param nrOfEntries Number of direct members of the array that - * have been output - */ - public void writeEndObject(JsonGenerator jg, int nrOfEntries) - throws IOException, JsonGenerationException; - - /** - * Method called after an object entry (field:value) has been completely - * output, and before another value is to be output. - *

- * Default handling (without pretty-printing) will output a single - * comma to separate the two. Pretty-printer is - * to output a comma as well, but can surround that with other - * (white-space) decoration. - */ - public void writeObjectEntrySeparator(JsonGenerator jg) - throws IOException, JsonGenerationException; - - /** - * Method called after an object field has been output, but - * before the value is output. - *

- * Default handling (without pretty-printing) will output a single - * colon to separate the two. Pretty-printer is - * to output a colon as well, but can surround that with other - * (white-space) decoration. - */ - public void writeObjectFieldValueSeparator(JsonGenerator jg) - throws IOException, JsonGenerationException; - - // // // Array handling - - /** - * Method called when an Array value is to be output, before - * any member/child values are output. - *

- * Default handling (without pretty-printing) will output - * the opening bracket. - * Pretty-printer is - * to output a bracket as well, but can surround that - * with other (white-space) decoration. - */ - public void writeStartArray(JsonGenerator jg) - throws IOException, JsonGenerationException; - - /** - * Method called after an Array value has been completely output - * (minus closing bracket). - *

- * Default handling (without pretty-printing) will output - * the closing bracket. - * Pretty-printer is - * to output a bracket as well, but can surround that - * with other (white-space) decoration. - * - * @param nrOfValues Number of direct members of the array that - * have been output - */ - public void writeEndArray(JsonGenerator jg, int nrOfValues) - throws IOException, JsonGenerationException; - - /** - * Method called after an array value has been completely - * output, and before another value is to be output. - *

- * Default handling (without pretty-printing) will output a single - * comma to separate the two. Pretty-printer is - * to output a comma as well, but can surround that with other - * (white-space) decoration. - */ - public void writeArrayValueSeparator(JsonGenerator jg) - throws IOException, JsonGenerationException; - - /* - ////////////////////////////////////////////////////// - // Then events that by default do not produce any output - // but that are often overridden to add white space - // in pretty-printing mode - ////////////////////////////////////////////////////// - */ - - /** - * Method called after array start marker has been output, - * and right before the first value is to be output. - * It is not called for arrays with no values. - *

- * Default handling does not output anything, but pretty-printer - * is free to add any white space decoration. - */ - public void beforeArrayValues(JsonGenerator jg) - throws IOException, JsonGenerationException; - - /** - * Method called after object start marker has been output, - * and right before the field name of the first entry is - * to be output. - * It is not called for objects without entries. - *

- * Default handling does not output anything, but pretty-printer - * is free to add any white space decoration. - */ - public void beforeObjectEntries(JsonGenerator jg) - throws IOException, JsonGenerationException; -} - diff --git a/src/org/codehaus/jackson/VERSION b/src/org/codehaus/jackson/VERSION deleted file mode 100644 index b2ce1b591e..0000000000 --- a/src/org/codehaus/jackson/VERSION +++ /dev/null @@ -1,795 +0,0 @@ -Version: 1.5.4 - -Release date: - 25-Jun-2010 - -Description: - Fourth patch release for 1.5 - - Fixes: - - * [JACKSON-296]: Add support for JAXB/@XmlElementRef(s), fix related - issues uncovered (wrt. handling of polymorphic collection fields) - (reported by Ryan H) - * [JACKSON-311]: Problems handling polymorphic type information for - 'untyped' (Object) bean properties, default typing - (reported by Eric S) - ------------------------------------------------------------------------- -== History: == ------------------------------------------------------------------------- - -1.5.3 [31-May-2010] - - Fixes: - - * [JACKSON-285]: Problem with @JsonCreator annotated constructor that - also uses @JsonDeserialize annotations - - Improvements: - - * [JACKSON-284]: Reduce scope of sync block in - SerializerCache.getReadOnlyLookupMap() - * Partial fix for [JACKSON-289]: allow JSON Array with single-character - Strings to be bound to char[] during deserialization - (suggested by Brian O) - -1.5.2 [25-Apr-2010] - - Fixes: - - * [JACKSON-273]: Yet another OSGi issue, "org.codehaus.jackson.map.util" - not exported by mapper module, needed by jax-rs module. - (reported by Lukasz D) - * [JACKSON-281]: JsonGenerator.writeObject() only supports subset of - wrapper types (when not specifying ObjectCodec) - (reported by Aron A) - - (and all fixes from 1.4.x branch up to 1.4.4) - -1.5.1 [09-Apr-2010] - - Fixes: - - * [JACKSON-265]: problems with generic type handling for serialization - (reported by Fabrice D) - * [JACKSON-269]: missing OSGi export by mapper (o.c.j.m.jsontype.impl), - needed by jackson-xc module - (reported by Raymond F) - - (and all fixes from 1.4.x branch up to 1.4.3) - - -1.5.0 [14-Mar-2010] - - Fixes: - - * [JACKSON-246] JAXB property name determination not working correctly. - (reported by Lars C) - - Improvements: - - * [JACKSON-160] Factory Creator methods now handle polymorphic - construction correctly, allowing manual polymorphic deserialization - * [JACKSON-218] Extended support for Joda date/time types like - LocalDate, LocalDateTime and DateMidnight - * [JACKSON-220] @JsonSerialize.using() was not working properly for - non-Bean types (Collections, Maps, wrappers) - * [JACKSON-236] Allow deserialization of timestamps-as-Strings (not - just timestamps as JSON integer numbers). - (requested by Chris C) - * [JACKSON-255] Allow setter override even with incompatible type - (as long as only one setter per class, so there is no ambiguity) - * [JACKSON-256] AnnotationIntrospector.findSerializationInclusion - was not combining values correctly for JAXB annotations. - (reported by John L) - - New features: - - * [JACKSON-91] Polymorphic Type Handling: automatic handling of - polymorphic types, based on annotations (@JsonTypeInfo) and/or - global settings (ObjectMapper.enableDefaultTyping()) - * [JACKSON-175] Add "org.codehaus.jackson.util.TokenBuffer", used for - much more efficient type conversions (and other internal buffering) - * [JACKSON-195] Add methods to ObjectMapper to allow specification of - root object serialization type. - * [JACKSON-221] Add 'ObjectMapper.writeValueAsBytes()' convenience - method to simplify a common usage pattern - * [JACKSON-229] TypeFactory should have methods to construct parametric - types programmatically (TypeFactory.parametricType()) - * [JACKSON-232] Add 'SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION' - to disable inclusion of non-annotated properties with explicit views - (suggested by Andrei V) - * [JACKSON-234] Add support for JSONP, by adding JSONPObject wrapper - that serializes as expected. - * [JACKSON-241] Add a mechanism for adding new "untouchable" types for - JAX-RS JSON provider, to allow excluding types from being handled - (added method "JacksonJsonProvider.addUntouchable()") - * [JACKSON-244] Allow specifying specific minimum visibility levels for - auto-detecting getters, setters, fields and creators - (requested by Pierre-Yves R) - * [JACKSON-245] Add configuration setting in JAX-RS provider to allow - automatic JSONP wrapping (provider.setJSONPFunctionName()) - * [JACKSON-259] Add JsonParser.Feature to allow disabling field name - canonicalization (JsonParser.Feature.CANONICALIZE_FIELD_NAMES) - - Backwards incompatible changes: - - * Moved following serializers out of BasicSerializerFactory - JdkSerializers: ClassSerializer (into JdkSerializers), - NullSerializer (separate class) - * Add one parameter to StdDeserializer.handleUnknownProperty: - addition was required for handling polymorphic cases that - can use nested JsonParser instances. - * Fixed issues in generic type handling (was not resolving all named - types completely) - * Annotation changes: - * Moved "NoClass" into "org.codehaus.jackson.map.annotate" package - * Removed @JsonUseSerializer and @JsonUseDeserializer annotations - (which has been deprecated for 1.1; replaced by - @JsonSerialize.using and @JsonDeserialize.using, respectively) - * @JsonGetter and @JsonSetter are marked as deprecated, since - @JsonProperty can (and should) be used instead. - -1.4.4 [25-Apr-2010] - - Fixes: - - * [JACKSON-263] BooleanNode.asToken() incorrectly returns 'true' token - for all nodes (not just 'false' ones) - (reported by Gennadiy S) - * [JACKSON-266] Deserialization issues when binding data from JsonNode - (reported by Martin T) - -1.4.3 [18-Feb-2010] - - Fixes: - - * [JACKSON-237]: NPE in deserialization due to race condition - (reported by Benjamin D) - - -1.4.2 [31-Jan-2010] - - Fixes: - - * [JACKSON-238]: Fix to ensure custom serializers can override - default serializers (like DOM, Joda serializers) - (reported by Pablo L) - * other fixes from 1.3.4 release - -1.4.1 [10-Jan-2010] - - Fixes: - - fixes from 1.3.x branch up to 1.3.3. - -1.4.0 [19-Dec-2009] - - Improvements: - - * [JACKSON-38] Allow serializing/deserializing DOM trees (Node, Document) - (suggested by Scott D) - * [JACKSON-89] Make ignored field/creator-backed properties quietly - skippable during deserialization (that is, without having to explicitly - declare such properties as ignorable as per [JACKSON-77]) - * [JACKSON-161] Added basic support for Joda, ser/deser DateTime class - * [JACKSON-170] Serialize Creator properties before other properties - * [JACKSON-196] Schema generation does not respect the annotation - configured serializer on a bean property - (reported by Gil M) - * [JACKSON-208] Add feature (JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS) - to allow unquoted control characters (esp. tabs) in Strings and - field names - (requested by Mark S) - * [JACKSON-216] Jackson JAXB annotation handler does not use @XmlElement.type - property for figuring out actual type - (reported by Mike R) - - New features: - - * [JACKSON-77] Add class annotation @JsonIgnoreProperties to allow - for ignoring specific set of properties for serialization/deserialization - * [JACKSON-90] Added @JsonPropertyOrder, which allows for specifying - order in which properties are serialized. - * [JACKSON-138] Implement JsonView; ability to suppress subsets of - properties, based on view definition. Views are defined using @JsonView - annotation. - * [JACKSON-191] Add access to basic statistics on number of cached - serializers, deserializers (and methods to flush these caches) - * [JACKSON-192] Added basic delegate implementations (JsonParserDelegate, - JsonGeneratorDelegate) to make it easier to override core parser and - generate behavior - * [JACKSON-201] Allow serialization of "empty beans" (classes without - getters), if SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS is - disabled; or if class has recognized Jackson annotation - (suggested by Mike P) - - Other: - - * Removed "BasicSerializerFactory.StringLikeSerializer" that was - deprecated for 1.0, replaced by public "ToStringSerializer" - -1.3.4 [31-Jan-2010] - - Fixes: - - * [JACKSON-225], [JACKSON-227], missing null checks/conversions when - adding entries to ArrayNode and ObjectNode - (reported by Kenny M) - * [JACKSON-230]: wrong NumberType reported for big ints, longs - (reported by Henning S) - * [JACKSON-231]: ArrayDeserializer for byte[] should be able to - use VALUE_EMBEDDED_OBJECT (if Object is byte[]) - -1.3.3 [21-Dec-2009] - - Fixes: - - * [JACKSON-214] Enum types with sub-classes failed to serialize - (reported by Elliot S) - * [JACKSON-215] Add JAX-RS provider annotations on JacksonJaxbJsonProvider - (suggested by Matthew R) - * [JACKSON-220] JsonSerialize.using() not recognized for Collection and - Map types (and similarly for JsonDeserialize) - -1.3.2 [02-Dec-2009] - - Fixes: - - * [JACKSON-103] (additional work) Groovy setMetaClass() setter caused - problems when deserializing (although serialization was fixed earlier) - (reported by Stephen F) - * [JACKSON-187] Issues with GAE security model, Class.getEnclosingMethod() - * [JACKSON-188] Jackson not working on Google App Engine (GAE) due to - unintended dependency from JacksonJsonProvider to JAXB API classes - (reported by Jeff S) - * [JACKSON-206] Support parsing dates of form "1984-11-13T00:00:00" - -1.3.1 [23-Nov-2009] - - Fixes: - - * [JACKSON-190] Problems deserializing certain nested generic types - (reported by Nathan C) - * [JACKSON-194] ObjectMapper class loading issues on Android - (reported by Martin L) - * [JACKSON-197] Remove 2 debug messages that print out to System.err - (reported by Edward T) - * [JACKSON-200] java.sql.Date deserialization not working well - (reported by Steve L) - * [JACKSON-202] Non-public fields not deserialized properly with - JAXB annotations - (reported by Mike P) - * [JACKSON-203] Date deserializers should map empty String to null - (reported by Steve L) - -1.3.0 [30-Oct-2009] - - Fixes: - - * [JACKSON-150] Some JAXB-required core types (XMLGregorianCalendar, - Duration, QName, DataHandler) were not completely supported - * [JACKSON-155] Failed to serialize java.io.File (with infinite - recursion) - (reported by Gabe S) - * [JACKSON-167] Map and Collection sub-classes seem to lose generic - information for deserialization - * [JACKSON-177] Problems with Hibernate, repackaged cglib - (reported by Ted B) - * [JACKSON-179] Single-long-arg factory Creators were not working - (reported by Brian M) - * [JACKSON-183] Root-level 'JsonDeserialize' annotation was not handled - completely; 'as' setting was not taking effect - (reported by Nick P) - - Improvements: - - * [JACKSON-152] Add "ObjectMapper.writeValueAsString()" convenience - method to simplify serializing JSON into String. - * [JACKSON-153] Allow use of @JsonCreator with Map types too - * [JACKSON-158] Bean serializer now checks for direct self-references - (partial, trivial cycle detection) - * [JACKSON-164] Improve null handling for JsonGenerator.writeStringValue - (suggested by Benjamin Darfler) - * [JACKSON-165] Add JsonParser.getBooleanValue() convenience method - (suggested by Benjamin Darfler) - * [JACKSON-166] Add ability to control auto-detection of - "is getters" (boolean isXxx()) methods separate from regular getters - * [JACKSON-168] Make JsonLocation serializable (and deserializable) - (suggested by Shay B) - * [JACKSON-182] Improved handling of SerializationConfig.AUTO_DETECT_GETTERS - with JAXB annotations (uses Jackson-specified default, not JAXB defaults) - - New features: - - * [JACKSON-129] Allow constructing JsonParser to read from JsonNode - (tree representation) - * [JACKSON-154] Added JsonDeserialize.keyUsing and .contentUsing, - to allow for overriding key and content/value deserializers for - properties of structured (array, Collection, Map) types - * [JACKSON-159] Added 'org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider' - to improve use of Jackson as JSON converter for JAX-RS services. - * [JACKSON-173] Add "JsonParser.Feature.ALLOW_SINGLE_QUOTES" to - handle some more invalid JSON content - (requested by Brian M) - * [JACKSON-174] Add "ObjectMapper.convertValue()" convenience method - for simple Object-to-Object conversions, using Jackson's data binding - functionality - * [JACKSON-176] Added 'JsonGenerator.Feature.WRITE_NUMBER_AS_STRINGS' - as a work-around for Javascript problems with big longs (due to - always representing numbers as 64-bit doubles internally) - (requested by Doug D) - * [JACKSON-180] Added 'JsonParser.Feature.INTERN_FIELD_NAMES' to allow - disabling field name intern()ing. - (suggested by Jeff Y) - * [JACKSON-181] Added convenience methods in TypeFactory to allow - dynamically constructed fully typed structured types (map, collection - array types), similar to using TypeReference but without inner classes - * Added method in AnnotationIntrospector to find declared namespace - for JAXB annotations, needed for XML compatibility (future features) - - Other: - - * Removed obsolete class 'org.codehaus.jackson.map.type.TypeReference' - (obsoleted by 'org.codehaus.jackson.type.TypeReference) -- was supposed - to have been removed by 1.0 but had not been. - * Added support to handle 'java.util.regex.Pattern' - -1.2.1 [03-Oct-2009] - - Problems fixed: - - * [JACKSON-162] OSGi packaging problems for xc package. - (reported by Troy Waldrep) - * [JACKSON-171] Self-referential types cause infinite recursion when - using only JAXB annotation introspector - (reported by Randy L) - -1.2.0 [02-Aug-2009] - - Improvements: - - * Added "-use" flag for generating javadocs - (suggested by Dain S) - * [JACKSON-136] JsonParser and JsonGenerator should implement - java.io.Closeable (since they already have close() method) - (suggested by Dain S) - * [JACKSON-148] Changed configuration methods to allow chaining, - by returning 'this' (instead of 'void') - - New features: - - * [JACKSON-33] Allow use of "non-default constructors" and - multiple-argument factory methods for constructing beans to - deserialize - * [JACKSON-69] Support parsing non-standard JSON where Object keys are not quoted - * [JACKSON-76] Mix-in annotations: allow dynamic attachment of - annotations to existing classes, for purposes of configuring - serialization/deserialization behavior - * [JACKSON-92] Allow use of @JsonCreator for constructors and - static methods that take a single deserializable type as argument - (so-called delegating creators) - * [JACKSON-114] Add feature and annotations to make serialization use - static (declared) type over concrete (actual/runtime) type - * [JACKSON-131] Allow constructing and passing of non-shared - SerializationConfig/DeserializationConfig instances to ObjectMapper - * [JACKSON-135] Add basic JsonNode construction support in ObjectMapper - * [JACKSON-147] Add global deserialization feature for suppressing error - reporting for unknown properties - * [JACKSON-149] Add ser/deser features - (DeserializationConfig.Feature.USE_ANNOTATIONS, - SerializationConfig.Feature.USE_ANNOTATIONS) to allow disabling - use of annotations for serialization and/or deserialization config - -1.1.2 [31-Jul-2009] - - Fixes: - - * [JACKSON-143] NPE on ArrayNode.equals() when comparing empty array - node to non-empty array node - (reported by Gregory G) - * [JACKSON-144] Static "getter-like" methods mistaken for getters (for - serialization) - (reported by Dan S) - -1.1.1 [18-Jul-2009] - - Fixes: - - * [JACKSON-139] Non-numeric double values (NaN, Infinity) are serialized - as invalid JSON tokens - (reported by Peter H) - * Core jar incorrectly included much of "mapper" classes (in addition - to core classes) - * Now compiles again using JDK 1.5 javac (1.1.0 didn't) - -1.1.0 [22-Jun-2009] - - Fixes: - - * [JACKSON-109] Allow deserializing into generics Bean classes - (like Wrapper) not just generic Maps and Collections - * [JACKSON-121] Problems deserializing Date values of some ISO-8601 - variants (like one using 'Z' to indicate GMT timezone) - * [JACKSON-122] Annotated serializers and deserializers had to - be public classes with public default constructor; not any more. - - Improvements: - - * [JACKSON-111] Added "jackson-xc" jar to contains XML Compatibility - extensions. - - New features: - - * [JACKSON-70] Add support for generating JSON Schema - * [JACKSON-98] Allow serializing/deserializing field-accessible properties, - in addition to method-accessible ones. - * [JACKSON-105] Allow suppressing output of "default values"; which - means value of a property when bean is constructed using the default - no-arg constructor - (requested by Christoph S) - * [JACKSON-119] Add (optional) support for using JAXB annotations - (by using JaxbAnnotationIntrospector) - (requested by Ryan H) - * [JACKSON-120] Add annotations @JsonSerialize, @JsonDeserialize, - to streamline annotation by replacing host of existing annotations. - * [JACKSON-123] Add "chaining" AnnotationIntrospector (implemented - as inner class, AnnotationIntrospector.Pair) that allows combining - functionality of 2 introspectors. - -1.0.1 [04-Jun-2009] - - Fixes: - - * [JACKSON-104] Build fails on JDK 1.5, assorted other minor issues - (reported by Oleksander A) - * [JACKSON-121] Problems deserializing Date values of some ISO-8601 - variants (like one using 'Z' to indicate GMT timezone) - -1.0.0 [09-May-2009] - - Fixes: - - * [JACKSON-103] Serializing Groovy objects; need to exclude getter method - "getMetaClass" from serialization to prevent infinite recursion - (reported by Ray T) - - Improvements: - - * Removed JAX-RS META-INF/services - based auto-registration for - JAX-RS MessageBodyReader/MessageBodyWriter, because it could - conflict with other application/json content handlers. - -0.9.9-6 [27-Apr-2009] - - Improvements: - - * Improved jax-rs provider integration with jersey; now properly - auto-registers as handler for json media type(s), and allows - for defining custom ObjectMapper to be injected. - -0.9.9-5 [20-Apr-2009] - - New features: - - * [JACKSON-88]: Support for "Setter-less" collection (and Map) types - - Improvements: - - * [JACKSON-100]: Allow specifying that BigInteger should be used instead - of Integer or Long for "generic" integral numeric types (Object, Number) - (DeserializationConfig.Feature.USE_BIG_INTEGER_FOR_INTS) - * [JACKSON-101]: Allow disabling of access modifier overrides - (SerializationgConfig.Feature.CAN_OVERRIDE_ACCESS_MODIFIERS) - to support more security-constrainted running environments. - -0.9.9-4 [14-Apr-2009] - - Fixes: - - * [JACKSON-94] Added missing "JsonParser.readValueAsTree()" method. - * JacksonJsonProvider was using strict equality comparison against - JSON type; instead needs to use "isCompatible". There were other - similar problems - (reported by Stephen D) - * [JACKSON-97] Generic types (with bound wildcards) caused problems - when Class introspector could not figure out that a concrete method - was overriding/implementing generic method; as well as having - problems with synthetic bridge methods. - - Improvements: - - * [JACKSON-95] Added support for deserializing simple exceptions - (Throwable and its sub-classes): anything with a String constructor - (assumed to take "message") should work to some degree. - * [JACKSON-99] IOExceptions should not be wrapped during object - mapping. - (reported by Eldar A) - - New features: - - * [JACKSON-85]: Make Date deserialization (more) configurable (add - DeserializationConfig.setDateFormat()) - * [JACKSON-93]: Allow overriding the default ClassIntrospector. - * [JACKSON-96]: Allow enabling pretty-printing with data binding, - through SerializationConfig object. - -0.9.9-3 [03-Apr-2009] - - Fixes: - - * [JACKSON-79]: Primitive value deserialization fragile wrt nulls - * [JACKSON-81]: Data binding code could lead to unnecessary blocking - because it tried to advance parser (and stream) after binding - (reported by Eldar A) - - New features: - - * [JACKSON-61]: Allow suppressing writing of bean properties with null values - (requested by Justin F) - * [JACKSON-63]: Create CustomDeserializerFactory to allow for adding - custom deserializers for non-structured/generic types. - * [JACKSON-75]: Add "any setter" method; ability to catch otherwise - unknown (unmapped) properties and call a method with name+value. - * [JACKSON-80]: Add @JsonValue annotation, to specify that a Bean value - is to be serialized as value returned by annotated method: can for - example annotate "toString()" method. - * [JACKSON-84]: Added JsonGenerator.writeRawValue methods to augment - existing JsonGenerator.writeRaw() method - (requested by Scott A) - * [JACKSON-86]: Added JsonParser.isClosed() and JsonGenerator.isClosed() - methods. - * [JACKSON-87]: Added ability to customized Date/Calendar serialization, - both by toggling between timestamp (number) and textual (ISO-8601), - and by specifying alternate DateFormat to use. - -0.9.9-2 [19-Mar-2009]: - - Fixes: - - * [JACKSON-75]: Didn't have Deserializer for Number.class. - - Improvements: - - * [JACKSON-68]: Add DeserializationProblemListener, and - DeserializationConfig.addHandler to add instances to ObjectMapper. - * [JACKSON-71]: Add support ser/deser of Class.class. - * [JACKSON-72]: Allow specifying that BigDecimal should be used instead - of Double for "generic" numeric types (Object, Number) - (DeserializationConfig.Feature.USE_BIG_DECIMAL_FOR_FLOATS) - * [JACKSON-73]: Refactored ser/deser configuration settings into - separate configuration classes. - * [JACKSON-78]: Should be able to deserialize ints into Booleans (0 == false) - - New features: - - * [JACKSON-45]: Add convenience methods to help writing custom - serializers - (requested by Scott A) - -0.9.9 [02-Mar-2009]: - - Fixes: - - * [JACKSON-59]: NPE with String[] serializer - (reported by Kevin G) - * [JACKSON-62]: NPE with JsonMappingException if source exception used - null message. - (reported by Justin F) - * [JACKSON-64]: Handling of property name (with @JsonGetter, @JsonSetter) - made bit more intuitive; uses bean naming convention if no explicit - name given. - - Improvements: - - * [JACKSON-60]: Method annotations did not follow intuitive expectations - of inheritability; now do. - * [JACKSON-65]: Need to support typing using "java.lang.reflect.Type", to - help integration with frameworks. - * [JACKSON-66]: ObjectMapper now has "canSerialize" and "canDeserialize" - methods to help frameworks figure out what is supported. - - New features: - - * [JACKSON-52]: Allow disabling name-based auto-detection of - getter methods - (requested by Justin F) - * [JACKSON-58]: Allow defining custom global Enum serializer - (to, for example, make Enums be serialized using Enum.toString(), - or lower-case name or such) - * [JACKSON-67]: Add JAX-RS provider based on Jackson that can handle - JSON content type; initially as a separate jar. - - Other: - - * [JACKSON-22]: all contributors now have submitted contributor - agreement, stored under 'DEV/agreements-received' in svn trunk. - -0.9.8 [18-Feb-2009]: - - Fixes: - - * [JACKSON-49]: Incorrect bounds check for Float values resulted in - exception when trying to serializer 0.0f. - - New features: - - * [JACKSON-32]: add annotations to configure serialization process - (@JsonClass/@JsonContentClass/@JsonKeyClass; @JsonUseSerializer, - @JsonUseDeserializer, @JsonIgnore) - * [JACKSON-36]: add annotations to define property names that differ - from bean naming convention (@JsonGetter/@JsonSetter) - - Improvements: - - * [JACKSON-47]: Change DeserializerProvider.findValueDeserializer to - take "referrer" information. This is needed to be able to give - contextual mappings where a given type may be deserialized differently - (by different deserializer, and possibly to a different java class) - depending on where the reference is from. - * [JACKSON-48]: Integrate ObjectMapper with JsonGenerator, JsonParser; - add MappingJsonFactory. - (suggested by Scott A) - * [JACKSON-50]: JsonNode.getElements() and .iterator() now work for - ObjectNodes too, not just ArrayNodes. Also added convenience factory - methods to allow constructing child nodes directly from container - nodes. - * [JACKSON-53]: iBatis proxied value classes didn't work; fixed by - prevent CGLib-generated "getCallbacks" from getting called. - (reportd by Justin F) - * [JACKSON-55]: Added support for reference-path-tracking in - JsonMappingException, made serializers populate it: this to make - it easier to trouble-shoot nested serialization problems - * [JACKSON-56]: Added support for RFC-1123 date format, along with - simpler "standard" format; and can add more as need be. - -0.9.7 [04-Feb-2009]: - - Improvements: - - * [JACKSON-34]: Improved packaging by adding an intermediate directory - in source tarball, to not mess up the current directory (and to indicate - version number as well) - * [JACKSON-37]: Make Jackson run on Android, by ensuring that there are - no hard linkages to classes that Android SDK doesn't have (the only - reference that was there, to XMLGregorianCalendar, was changed to - soft linkage) - * [JACKSON-42]: Add new JsonNode sub-class, BinaryNode, to represent - base64 encoded binary content. - - New features: - - * [JACKSON-6]: Implement JsonParser.getBinaryValue() so that one can - now also read Base64-encoded binary, not just write. - * [JACKSON-40]: Add JsonParser.nextValue() for more convenient - iteration. - * [JACKSON-46]: Allow disabling quoting of field names by disabling - feature 'JsonGenerator.feature.QUOTE_FIELD_NAMES' - (requested by Scott Anderson) - -0.9.6 [14-Jan-2009]: - - Bug fixes: - - * Serialization of some core types (boolean/java.lang.Boolean, - long/java.lang.Long) was not working due to incorrectly mapped - serializers. - - New features: - - * [JACKSON-31]: Complete rewrite of ObjectMapper's deserialization: - now supports Beans, typed (generics-aware) Lists/Maps/arrays. - - Improvements: - - * [JACKSON-24]: Add efficient byte-array - based parser factory - method to JsonFactory (has maybe 5% improvement over wrapping - in ByteArrayInputStream). - * [JACKSON-29]: Split classes in 2 jars: core that has parser and - generator APIs and implementations; and mapper jar that has object - and tree mapper code. - * [JACKSON-30]: Renamed "JavaTypeMapper" as "ObjectMapper", and - "JsonTypeMapper" as "TreeMapper"; new names should be more intuitive - to indicate their purpose. Will leave simple implementations of - old classes to allow for gradual migration of existing code. - -0.9.5 [10-Dec-2008]: - - Bug fixes: - - * [JACKSON-25]: Problems with Maven pom for lgpl version - (report by Ray R) - note: backported to 0.9.4 Codehaus Maven repo - - Improvements: - - * [JACKSON-13]: JavaTypeMapper can now take JsonFactory argument, and - thus is able to construct JsonParser/JsonGenerator instances as necessary - * [JACKSON-17]: Handling of unknown types now configurable with - JavaTypeMapper serialization (see JsonSerializerProvider for methods) - * [JACKSON-20]: Handling of nulls (key, value) configurable with - JavaTypeMapper serialization (see JsonSerializerProvider for methods) - * [JACKSON-26]: Add convenience JsonGenerator.writeXxxField() methods - to simplify json generation. - - New features: - - * [JACKSON-27]: Allow automatic closing of incomplete START_ARRAY and - START_OBJECT events, when JsonGenerator.close() is called. - -0.9.4 [26-Nov-2008]: - - Bug fixes: - - * [JACKSON-16]: JavaDocs regarding whether Jackson is to close underlying - streams, readers and writers, were incorrect. Additionally added - parser/generator features to allow specifying whether automatic closing - is to be done by Jackson: feature is enabled by default, both for - backwards compatibility, and because it seems like the right setting. - * [JACKSON-18]: ArrayIndexOutOfBounds on IntNode, due to off-by-one - problem with comparisons - (reported by Michael D) - * Fixed a problem with CR (\r) handling; was sometimes skipping - characters (problematic if there's no indentation). - * Multiple UTF-8 decoding fixes: was specifically not working for - names. - - Improvements: - - * More complete JavaDoc comments for core public classes. - * Internal cleanup of core parsing, to unify handling of Object and - Array entries - -0.8.0 - 0.9.3 [between 17-Oct-2007 and 05-Sep-2008]: - - Changes: - - * [JACKSON-5]: Symbol table construction was not thread-safe for - utf-8 encoded content (new bug with 0.9.2, not present with earlier) - (reported by Tudor B) - * [JACKSON-8]: Serialization of BigDecimal broken with JavaTypeMapper - (reported by Johannes L) - * [JACKSON-9]: Add support for (non-standard) Json comments. - (requested by Mike G) - * [JACKSON-11]: Implement base64/binary methods for json generator. - * [JACKSON-14]: Problems with generic collections, serializer - method signatures (due to lack of covariance wrt collection types) - * [JACKSON-15]: Add copy-through methods to JsonGenerator for - pass-through copying of content (copyCurrentEvent, copyCurrentStructure) - * [JACKSON-23]: Add OSGi manifest headers for jars (to run on OSGi container). - * Added generic "feature" mechanism to parsers, writers; features are - togglable (on/off) things with well-defined default values, implemented - as Enums. - - * [JACKSON-1]: JsonNode now implements Iterable so that - it is possible use Java 5 foreach loop over array/object nodes. - (suggested by Michael M) - * [JACKSON-4] Added JsonParser.skipChildren() method. - * UTF-16/32 handling was not completely correct, was erroneously - skipping first 2/4 bytes in some cases (even when no BOM included). - Also, related unit tests added/fixed. - * JsonGenerator.useDefaultPrettyPrinter()/.setPrettyPrinter() - allow for pretty printing (indentation). - (thanks to Ziad M for suggestion, sample code) - - * Implicit conversions for numbers could sometimes lose accuracy, - if floating-point number was first accessed as int/long, and then - as a BigDecimal. - * One Nasty NPE fixed from NameCanonicalizer (which was added in 0.9.2) - - * Java type mapper had a bug in Collection mapping (mismatched - calls between writeStartArray and writeEndObject!) - (reported by Mike E) - * Java type mapper had a bug which prevented custom mappers (as - well as slower interface-based introspection) from working. - (reported by Mike E) - * Numeric value parsing had some problems - * JavaTypeMapper and JsonTypeMapper had a bug which resulted - in NullPointerException when stream ends, instead of returning - null to indicate it. - (reported by Augusto C) - * JavaTypeMapper did not implicitly flush generator after mapping - objects: it should, and now will (note: JsonTypeMapper not directly - affected, flushing still needed) - (suggested by Maciej P) diff --git a/src/org/codehaus/jackson/annotate/JacksonAnnotation.java b/src/org/codehaus/jackson/annotate/JacksonAnnotation.java deleted file mode 100644 index 25bf61e27a..0000000000 --- a/src/org/codehaus/jackson/annotate/JacksonAnnotation.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Meta-annotation (annotations used on other annotations) - * used for marking all annotations that are - * part of Jackson package. Can be used for recognizing all - * Jackson annotations generically, and in future also for - * passing other generic annotation configuration. - */ -@Target({ElementType.ANNOTATION_TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface JacksonAnnotation -{ - // for now, a pure tag annotation, no parameters -} diff --git a/src/org/codehaus/jackson/annotate/JsonAnySetter.java b/src/org/codehaus/jackson/annotate/JsonAnySetter.java deleted file mode 100644 index 04aa3cadbb..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonAnySetter.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Marker annotation that can be used to define a non-static, - * single-argument method, to be used as a "fallback" handler - * for all otherwise unrecognized properties found from Json content. - * It is similar to {@link javax.xml.bind.annotation.XmlAnyElement} - * in behavior; and can only be used to denote a single property - * per type. - *

- * If used, all otherwise unmapped key-value pairs from Json Object - * structs are added to the property (of type Map or bean). - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonAnySetter -{ -} diff --git a/src/org/codehaus/jackson/annotate/JsonAutoDetect.java b/src/org/codehaus/jackson/annotate/JsonAutoDetect.java deleted file mode 100644 index 9c82265078..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonAutoDetect.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.reflect.Member; -import java.lang.reflect.Modifier; - -/** - * Class annotation that can be used to define which kinds of Methods - * are to be detected by auto-detection. - * Auto-detection means using name conventions - * and/or signature templates to find methods to use for data binding. - * For example, so-called "getters" can be auto-detected by looking for - * public member methods that return a value, do not take argument, - * and have prefix "get" in their name. - *

- * Pseudo-value NONE means that all auto-detection is disabled - * for the specific class that annotation is applied to (including - * its super-types, but only when resolving that class). - * Pseudo-value ALWAYS means that auto-detection is enabled - * for all method types for the class in similar way. - *

- * The default value is ALWAYS: that is, by default, auto-detection - * is enabled for all classes unless instructed otherwise. - *

- * Starting with version 1.5, it is also possible to use more fine-grained - * definitions, to basically define minimum visibility level needed. Defaults - * are different for different types (getters need to be public; setters can - * have any access modifier, for example). - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonAutoDetect -{ - /** - * Enumeration for possible visibility thresholds (minimum visibility) - * that can be used to limit which methods (and fields) are - * auto-detected. - * - * @since 1.5 - */ - public enum Visibility { - /** - * Value that means that all kinds of access modifiers are acceptable, - * from private to public. - */ - ANY, - /** - * Value that means that any other access modifier other than 'private' - * is considered auto-detectable. - */ - NON_PRIVATE, - /** - * Value that means access modifiers 'protected' and 'public' are - * auto-detectable (and 'private' and "package access" == no modifiers - * are not) - */ - PROTECTED_AND_PUBLIC, - /** - * Value to indicate that only 'public' access modifier is considered - * auto-detectable. - */ - PUBLIC_ONLY, - /** - * Value that indicates that no access modifiers are auto-detectable: - * this can be used to explicitly disable auto-detection for specified - * types. - */ - NONE, - - /** - * Value that indicates that default visibility level (whatever it is, - * depends on context) is to be used. This usually means that inherited - * value (from parent visibility settings) is to be used. - */ - DEFAULT; - - public boolean isVisible(Member m) { - switch (this) { - case ANY: - return true; - case NONE: - return false; - case NON_PRIVATE: - return !Modifier.isPrivate(m.getModifiers()); - case PROTECTED_AND_PUBLIC: - if (Modifier.isProtected(m.getModifiers())) { - return true; - } - // fall through to public case: - case PUBLIC_ONLY: - return Modifier.isPublic(m.getModifiers()); - } - return false; - } - } - - /** - * Types of property elements (getters, setters, fields, creators) that - * can be auto-detected. - * NOTE: as of 1.5, it is recommended that instead of defining this property, - * distinct visibility properties are used instead. This because levels - * used with this method are not explicit, but global defaults that differ for different - * methods. As such, this property can be considered deprecated and - * only retained for backwards compatibility. - */ - JsonMethod[] value() default { JsonMethod.ALL }; - - /** - * Minimum visibility required for auto-detecting regular getter methods. - * - * @since 1.5 - */ - Visibility getterVisibility() default Visibility.DEFAULT; - - /** - * Minimum visibility required for auto-detecting is-getter methods. - * - * @since 1.5 - */ - Visibility isGetterVisibility() default Visibility.DEFAULT; - - /** - * Minimum visibility required for auto-detecting setter methods. - * - * @since 1.5 - */ - Visibility setterVisibility() default Visibility.DEFAULT; - - /** - * Minimum visibility required for auto-detecting Creator methods, - * except for no-argument constructors (which are always detected - * no matter what). - * - * @since 1.5 - */ - Visibility creatorVisibility() default Visibility.DEFAULT; - - /** - * Minimum visibility required for auto-detecting member fields. - * - * @since 1.5 - */ - Visibility fieldVisibility() default Visibility.DEFAULT; -} diff --git a/src/org/codehaus/jackson/annotate/JsonClass.java b/src/org/codehaus/jackson/annotate/JsonClass.java deleted file mode 100644 index c0725e2eb2..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonClass.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation that can be used with "setter" methods to - * indicate the actual type to use for deserializing value - * of the associated logical property. - * This is usually done if the declared type is abstract or too generic; - * annotation can denote actual concrete type to instantiate when - * deserializing the property. - *

- * The indicated type must be compatible with the declared - * type. For deserialization (setters) this means that - * it has to be a sub-type or implementation of - * the declared type. - * If this constraint is violated, an exception (usually - * {@link IllegalArgumentException}) can be thrown by runtime. - *

- * Note that for container types (arrays, Lists/Collections/Maps) this - * indicates the type of container itself; for contained Objects, use - * {@link JsonContentClass} instead (or for Map keys, - * {@link JsonKeyClass}). - * - * @deprecated As of version 1.1, use {@link org.codehaus.jackson.map.annotate.JsonDeserialize#as} instead - */ -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonClass -{ - /** - * Class that is the type to use for deserializating value of - * the property associated - * with the annotated method. - */ - public Class value(); -} diff --git a/src/org/codehaus/jackson/annotate/JsonContentClass.java b/src/org/codehaus/jackson/annotate/JsonContentClass.java deleted file mode 100644 index ada548162e..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonContentClass.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation that can be used to mark "setter" methods to indicate the - * actual type of values contained in a container type that is value - * of the property associated with the method. - * (phew! that's a mouthful!). - * This is usually done if the declared element type is abstract or - * too generic; annotation can denote actual concrete type to - * instantiate when deserializing contents of the container. - * To define type of the actual container itself, use - * {@link JsonClass} instead. - *

- * Note that the indicated type must be compatible with the declared - * type; that is, it has to be a sub-type or implementation of - * the declared type. This is usually the case; and if it wasn't - * then the call to associated "setter" method would fail with - * a type-mismatch exception. - * - * @deprecated As of version 1.1, use {@link org.codehaus.jackson.map.annotate.JsonDeserialize#contentAs} instead - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonContentClass -{ - /** - * Class that is the expected concrete value type of the container - * (which is value of the property associated - * with the annotated method). Will be used by deserializer to - * instantiate the type, using - *

- * Note: if a non-property method is annotated with this annotation, - * deserializer will throw an exception to denote invalid annotation. - */ - public Class value(); -} diff --git a/src/org/codehaus/jackson/annotate/JsonCreator.java b/src/org/codehaus/jackson/annotate/JsonCreator.java deleted file mode 100644 index 72feac8b7f..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonCreator.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Marker annotation that can be used to define constructors and factory - * methods as one to use for instantiating new instances of the associated - * class. - */ -@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonCreator -{ - // no values, since there's no property -} diff --git a/src/org/codehaus/jackson/annotate/JsonGetter.java b/src/org/codehaus/jackson/annotate/JsonGetter.java deleted file mode 100644 index 19a6fe6254..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonGetter.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Marker annotation that can be used to define a non-static, - * no-argument value-returning (non-void) method to be used as a "getter" - * for a logical property, - * as an alternative to recommended - * {@link JsonProperty} annotation (which was introduced in version 1.1). - *

- * Getter means that when serializing Object instance of class that has - * this method (possibly inherited from a super class), a call is made - * through the method, and return value will be serialized as value of - * the property. - * - * @deprecated Use {@link JsonProperty} instead (deprecated since version 1.5) - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonGetter -{ - /** - * Defines name of the logical property this - * method is used to access ("get"); empty String means that - * name should be derived from the underlying method (using - * standard Bean name detection rules) - */ - String value() default ""; -} diff --git a/src/org/codehaus/jackson/annotate/JsonIgnore.java b/src/org/codehaus/jackson/annotate/JsonIgnore.java deleted file mode 100644 index dcdcbadfd7..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonIgnore.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Marker annotation -* that indicates that the annotated method or field is to be ignored by -* introspection-based - * serialization and deserialization functionality. That is, it should - * not be consider a "getter", "setter" or "creator". - *

- * For example, - * a "getter" method that would otherwise denote - * a property (like, say, "getValue" to suggest property "value") - * to serialize, would be ignored and no such property would - * be output unless another annotation defines alternative method - * to use. - *

- * This annotation works purely on method-by-method (or field-by-field) basis; - * annotation on one method or field does not imply ignoring other methods - * or fields. - * Specifically, marking a "setter" candidate does not change handling - * of matching "getter" method (or vice versa). - *

- * Annotation is usually used just a like a marker annotation, that - * is, without explicitly defining 'value' argument (which defaults - * to true): but argument can be explicitly defined. - * This can be done to override an existing JsonIgnore by explictly - * defining one with 'false' argument. - *

- * Annotation is similar to {@link javax.xml.bind.annotation.XmlTransient} - */ -@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonIgnore -{ - /** - * Optional argument that defines whether this annotation is active - * or not. The only use for value 'false' if for overriding purposes - * (which is not needed often); most likely it is needed for use - * with "mix-in annotations" (aka "annotation overrides"). - * For most cases, however, default value of "true" is just fine - * and should be omitted. - */ - boolean value() default true; -} diff --git a/src/org/codehaus/jackson/annotate/JsonIgnoreProperties.java b/src/org/codehaus/jackson/annotate/JsonIgnoreProperties.java deleted file mode 100644 index aa825e8ec3..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonIgnoreProperties.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation that can be used to either suppress serialization of - * properties (during serialization), or ignore processing of - * JSON properties read (during deserialization). - *

- * Example: - *

- * // to prevent specified fields from being serialized or deserialized
- * // (i.e. not include in JSON output; or being set even if they were included)
- * \@JsonIgnoreProperties({ "internalId", "secretKey" })
- * // To ignore any unknown properties in JSON input without exception:
- * \@JsonIgnoreProperties(ignoreUnknown=true)
- *
- *

- * Only applicable to classes, not for properties (getters, setters, fields). - * - * @since 1.4 - */ -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonIgnoreProperties -{ - /** - * Names of properties to ignore. - */ - public String[] value() default { }; - - /** - * Property that defines whether it is ok to just ignore any - * unrecognized properties during deserialization. - * If true, all properties that are unrecognized -- that is, - * there are no setters or creators that accept them -- are - * ignored without warnings (although handlers for unknown - * properties, if any, will still be called) without - * exception. - *

- * Does not have any effect on serialization. - */ - public boolean ignoreUnknown() default false; -} diff --git a/src/org/codehaus/jackson/annotate/JsonKeyClass.java b/src/org/codehaus/jackson/annotate/JsonKeyClass.java deleted file mode 100644 index 456eb133f9..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonKeyClass.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation that can be used to mark "setter" methods to indicate the - * actual type of key Objects for the Map type that is value - * of the property associated with the method. - * This is usually done if the declared element type is abstract or - * too generic; annotation can denote actual concrete type to - * instantiate when deserializing contents of the container. - * To define type of the actual container itself, use - * {@link JsonClass} instead. - *

- * Note that the indicated type must be compatible with the declared - * type; that is, it has to be a sub-type or implementation of - * the declared type. This is usually the case; and if it wasn't - * then the call to associated "setter" method would fail with - * a type-mismatch exception. - *

- * Note: while any class can be indicated as the Key class, there - * must be a registered Key Deserializer for the type. - * - * @deprecated As of version 1.1, use {@link org.codehaus.jackson.map.annotate.JsonDeserialize#keyAs} instead - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonKeyClass -{ - /** - * Class that is the expected concrete value type of the container - * (which is value of the property associated - * with the annotated method). Will be used by deserializer to - * instantiate the type, using - *

- * Note: if a non-property method is annotated with this annotation, - * deserializer will throw an exception to denote invalid annotation. - */ - public Class value(); -} diff --git a/src/org/codehaus/jackson/annotate/JsonMethod.java b/src/org/codehaus/jackson/annotate/JsonMethod.java deleted file mode 100644 index 2588b1f34d..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonMethod.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.codehaus.jackson.annotate; - -/** - * Enumeration used to define kinds of methods that annotations like - * {@link JsonAutoDetect} apply to. - *

- * In addition to actual method types (GETTER, SETTER, CREATOR; and - * sort-of-method, FIELD), 2 pseudo-types - * are defined for convenience: ALWAYS and NONE. These - * can be used to indicate, all or none of available method types (respectively), - * for use by annotations that takes JsonMethod argument. - */ -public enum JsonMethod -{ - /** - * Getters are methods used to get a POJO field value for serialization, - * or, under certain conditions also for de-serialization. Latter - * can be used for effectively setting Collection or Map values - * in absence of setters, iff returned value is not a copy but - * actual value of the logical property. - *

- * Since version 1.3, this does NOT include "is getters" (methods - * that return boolean and named 'isXxx' for property 'xxx'); instead, - * {@link #IS_GETTER} is used}. - */ - GETTER, - - /** - * Setters are methods used to set a POJO value for deserialization. - */ - SETTER, - - /** - * Creators are constructors and (static) factory methods used to - * construct POJO instances for deserialization - */ - CREATOR, - - /** - * Field refers to fields of regular Java objects. Although - * they are not really methods, addition of optional field-discovery - * in version 1.1 meant that there was need to enable/disable - * their auto-detection, and this is the place to add it in. - * - * @since 1.1 - */ - FIELD, - - /** - * "Is getters" are getter-like methods that are named "isXxx" - * (instead of "getXxx" for getters) and return boolean value - * (either primitive, or {@link java.lang.Boolean}). - * - * @since 1.3 - */ - IS_GETTER, - - /** - * This pseudo-type indicates that none of real types is included - */ - NONE, - - /** - * This pseudo-type indicates that all of real types are included - */ - ALL - ; - - private JsonMethod() { } - - public boolean creatorEnabled() { - return (this == CREATOR) || (this == ALL); - } - - public boolean getterEnabled() { - return (this == GETTER) || (this == ALL); - } - - public boolean isGetterEnabled() { - return (this == IS_GETTER) || (this == ALL); - } - - public boolean setterEnabled() { - return (this == SETTER) || (this == ALL); - } - - public boolean fieldEnabled() { - return (this == FIELD) || (this == ALL); - } -} diff --git a/src/org/codehaus/jackson/annotate/JsonProperty.java b/src/org/codehaus/jackson/annotate/JsonProperty.java deleted file mode 100644 index fdad341be7..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonProperty.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Marker annotation that can be used to define a non-static - * method as a "setter" or "getter" for a logical property - * (depending on its signature), - * or non-static object field to be used (serialized, deserialized) as - * a logical property. - *

- * Default value ("") indicates that the field name is used - * as the property name without any modifications, but it - * can be specified to non-empty value to specify different - * name. Property name refers to name used externally, as - * the field name in Json objects. - *

- * NOTE: since version 1.1, annotation has also been applicable - * to fields (not with 1.0). - *

- * NOTE: since version 1.2, annotation has also been applicable - * to (constructor) parameters - */ -@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonProperty -{ - /** - * Defines name of the logical property, i.e. Json object field - * name to use for the property: if empty String (which is the - * default), will use name of the field that is annotated. - */ - String value() default ""; -} diff --git a/src/org/codehaus/jackson/annotate/JsonPropertyOrder.java b/src/org/codehaus/jackson/annotate/JsonPropertyOrder.java deleted file mode 100644 index f3b43c85ce..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonPropertyOrder.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation that can be used to define ordering (possibly partial) to use - * when serializing object properties. Properties included in annotation - * declaration will be serialized first (in defined order), followed by - * any properties not included in the definition. - * Annotation definition will override any implicit orderings (such as - * guarantee that Creator-properties are serialized before non-creator - * properties) - *

- * Examples: - *

- *  // ensure that "id" and "name" are output before other properties
- *  \@JsonPropertyOrder({ "id", "name" })
- *  // order any properties that don't have explicit setting using alphabetic order
- *  \@JsonPropertyOrder(alphabetic=true)
- *
- *

- * This annotation has no effect on deserialization. - * - * @since 1.4 - */ -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonPropertyOrder -{ - /** - * Order in which properties of annotated object are to be serialized in. - */ - public String[] value() default { }; - - /** - * Property that defines what to do regarding ordering of properties - * not explicitly included in annotation instance. If set to true, - * they will be alphabetically ordered; if false, order is - * undefined (default setting) - */ - public boolean alphabetic() default false; -} diff --git a/src/org/codehaus/jackson/annotate/JsonSetter.java b/src/org/codehaus/jackson/annotate/JsonSetter.java deleted file mode 100644 index d7ed4c3eb7..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonSetter.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Marker annotation that can be used to define a non-static, - * single-argument method to be used as a "setter" for a logical property - * as an alternative to recommended - * {@link JsonProperty} annotation (which was introduced in version 1.1). - *

- * Setter means that when a property with matching name is encountered in - * JSON content, this method will be used to set value of the property. - * - * @deprecated Use {@link JsonProperty} instead (deprecated since version 1.5) - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonSetter -{ - /** - * Optional default argument that defines logical property this - * method is used to modify ("set"). - */ - String value() default ""; -} diff --git a/src/org/codehaus/jackson/annotate/JsonSubTypes.java b/src/org/codehaus/jackson/annotate/JsonSubTypes.java deleted file mode 100644 index 857401a26b..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonSubTypes.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - - -/** - * Annotation used with {@link JsonTypeInfo} to indicate sub types of serializable - * polymorphic types, and to associate logical names used within JSON content - * (which is more portable than using physical Java class names). - * - * @since 1.5 - */ -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonSubTypes { - /** - * Subtypes of the annotated type (annotated class, or property value type - * associated with the annotated method). These will be checked recursively - * so that types can be defined by only including direct subtypes. - */ - public Type[] value(); - - /** - * Definition of a subtype, along with optional name. If name is missing, class - * of the type will be checked for {@link JsonTypeName} annotation; and if that - * is also missing or empty, a default - * name will be constructed by type id mechanism. - * Default name is usually based on class name. - */ - public @interface Type { - /** - * Class of the subtype - */ - public Class value(); - - /** - * Logical type name used as the type identifier for the class - */ - public String name() default ""; - } -} diff --git a/src/org/codehaus/jackson/annotate/JsonTypeInfo.java b/src/org/codehaus/jackson/annotate/JsonTypeInfo.java deleted file mode 100644 index 7d90f0a6b4..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonTypeInfo.java +++ /dev/null @@ -1,174 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation used for configuring details of if and how type information is - * used with JSON serialization and deserialization, to preserve information - * about actual class of Object instances. This is necessarily for polymorphic - * types, and may also be needed to link abstract declared types and matching - * concrete implementation. - *

- * Some examples of typical annotations: - *

- *  // Include Java class name ("com.myempl.ImplClass") as JSON property "class"
- *  \@JsonTypeInfo(use=Id.CLASS, include=As.PROPERTY, property="class")
- *  
- *  // Include logical type name (defined in impl classes) as wrapper; 2 annotations
- *  \@JsonTypeInfo(use=Id.NAME, include=As.WRAPPER_OBJECT)
- *  \@JsonSubTypes({com.myemp.Impl1.class, com.myempl.Impl2.class})
- *
- * Alternatively you can also define fully customized type handling by using - * {@link org.codehaus.jackson.map.annotate.JsonTypeResolver} annotation. - * - * @see org.codehaus.jackson.map.annotate.JsonTypeResolver - * @since 1.5 - * - * @author tatu - */ -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonTypeInfo -{ - /* - ******************************************************************* - * Value enumerations used for properties - ******************************************************************* - */ - - /** - * Definition of different type identifiers that can be included in JSON - * during serialization, and used for deserialization. - */ - public enum Id { - /** - * This means that no explicit type metadata is included, and typing is - * purely done using contextual information possibly augmented with other - * annotations. - *

- * Note: no {@link org.codehaus.jackson.map.jsontype.TypeIdResolver} - * is constructed if this value is used. - */ - NONE(null), - - /** - * Means that fully-qualified Java class name is used as the type identifier. - */ - CLASS("@class"), - - /** - * Means that Java class name with minimal path is used as the type identifier. - * Minimal means that only class name, and that part of preceding Java - * package name is included that is needed to construct fully-qualified name - * given fully-qualified name of the declared supertype. - * For example, for supertype "com.foobar.Base", and concrete type - * "com.foo.Impl", only "Impl" would be included; and for "com.foo.impl.Impl2" - * only "impl.Impl2" would be included. - *

- * If all related classes are in the same Java package, this option can reduce - * amount of type information overhead, especially for small types. - * However, please note that using this alternative is inherently risky since it - * assumes that the - * supertype can be reliably detected. Given that it is based on declared type - * (since ultimate supertype, java.lang.Object would not be very - * useful reference point), this may not always work as expected. - */ - MINIMAL_CLASS("@c"), - - /** - * Means that logical type name is used as type information; name will then need - * to be separately resolved to actual concrete type (Class). - */ - NAME("@type"), - - /** - * Means that typing mechanism uses customized handling, with possibly - * custom configuration. This means that semantics of other properties is - * not defined by Jackson package, but by the custom implementation. - */ - CUSTOM(null) - ; - - private final String _defaultPropertyName; - - private Id(String defProp) { - _defaultPropertyName = defProp; - } - - public String getDefaultPropertyName() { return _defaultPropertyName; } - } - - /** - * Definition of standard type inclusion mechanisms for type metadata. - * Used for standard metadata types, except for {@link Id#NONE}. - * May or may not be used for custom types ({@link Id#CUSTOM}). - */ - public enum As { - /** - * Inclusion mechanism that uses a single configurable property, included - * along with actual data (POJO properties) as a separate meta-property. - *

- * Default choice for inclusion. - */ - PROPERTY, - - /** - * Inclusion mechanism that wraps typed JSON value (POJO - * serialized as JSON) in - * a JSON Object that has a single entry, - * where field name is serialized type identifier, - * and value is the actual JSON value. - *

- * Note: can only be used if type information can be serialized as - * String. This is true for standard type metadata types, but not - * necessarily for custom types. - */ - WRAPPER_OBJECT, - - /** - * Inclusion mechanism that wraps typed JSON value (POJO - * serialized as JSON) in - * a 2-element JSON array: first element is the serialized - * type identifier, and second element the serialized POJO - * as JSON Object. - */ - WRAPPER_ARRAY, - ; - } - - /* - ******************************************************************* - * Annotation properties - ******************************************************************* - */ - - /** - * What kind of type metadata is to be used for serializing and deserializing - * type information for instances of annotated type (and its subtypes - * unless overridden) - */ - public Id use(); - - /** - * What mechanism is used for including type metadata (if any; for - * {@link Id#NONE} nothing is included). Default - *

- * Note that for type metadata type of {@link Id#CUSTOM}, - * this setting may or may not have any effect. - */ - public As include() default As.PROPERTY; - - /** - * Property names used when type inclusion method ({@link As#PROPERTY}) is used - * (or possibly when using type metadata of type {@link Id#CUSTOM}). - *

- * Default property name used if this property is not explicitly defined - * (or is set to empty String) is based on - * type metadata type ({@link #use}) used. - */ - public String property() default ""; -} diff --git a/src/org/codehaus/jackson/annotate/JsonTypeName.java b/src/org/codehaus/jackson/annotate/JsonTypeName.java deleted file mode 100644 index 228fbcf825..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonTypeName.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - - -/** - * Annotation used for binding logical name that the annotated class - * has. Used with {@link JsonTypeInfo} (and specifically its - * {@link JsonTypeInfo#use} property) to establish relationship - * between type names and types. - * - * @since 1.5 - * - * @author tatu - */ -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonTypeName { - /** - * Logical type name for annotated type. If missing (or defined as Empty String), - * defaults to using non-qualified class name as the type. - */ - public String value() default ""; -} diff --git a/src/org/codehaus/jackson/annotate/JsonValue.java b/src/org/codehaus/jackson/annotate/JsonValue.java deleted file mode 100644 index 53b1be5363..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonValue.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Marker annotation similar to - * {@link javax.xml.bind.annotation.XmlValue} - * that indicates that results of the annotated "getter" method - * (which means signature must be that of getters; non-void return - * type, no args) is to be used as the single value to serialize - * for the instance. Usually value will be of a simple scalar type - * (String or Number), but it can be any serializable type (Collection, - * Map or Bean). - *

- * At most one method of a Class can be annotated with this annotation; - * if more than one is found, an exception may be thrown. - * Also, if method signature is not compatible with Getters, an exception - * may be thrown. - * Whether exception is thrown or not is an implementation detail (due - * to filtering during introspection, some annotations may be skipped) - * and applications should not rely on specific behavior. - *

- * A typical use case is that of annotating toString() - * method so that returned String value is Object's Json serialization. - *

- * Boolean argument is only used so that sub-classes can "disable" - * annotation if necessary. - */ -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonValue -{ - /** - * Optional argument that defines whether this annotation is active - * or not. The only use for value 'false' if for overriding purposes. - * Overriding may be necessary when used - * with "mix-in annotations" (aka "annotation overrides"). - * For most cases, however, default value of "true" is just fine - * and should be omitted. - */ - boolean value() default true; -} diff --git a/src/org/codehaus/jackson/annotate/JsonWriteNullProperties.java b/src/org/codehaus/jackson/annotate/JsonWriteNullProperties.java deleted file mode 100644 index 7b797ff564..0000000000 --- a/src/org/codehaus/jackson/annotate/JsonWriteNullProperties.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.codehaus.jackson.annotate; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation that can be used to define whether object properties - * that have null values are to be written out when serializing - * content as JSON. This affects Bean and Map serialization. - *

- * Annotation can be used with Classes (all instances of - * given class) and Methods. - *

- * Default value for this property is 'true', meaning that null - * properties are written. - */ -@Target({ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@JacksonAnnotation -public @interface JsonWriteNullProperties -{ - /** - * Whether properties for beans of annotated type will always be - * written (true), or only if not null (false). - */ - boolean value() default true; -} diff --git a/src/org/codehaus/jackson/impl/ByteSourceBootstrapper.java b/src/org/codehaus/jackson/impl/ByteSourceBootstrapper.java deleted file mode 100644 index cabc30c252..0000000000 --- a/src/org/codehaus/jackson/impl/ByteSourceBootstrapper.java +++ /dev/null @@ -1,351 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.*; - -import org.codehaus.jackson.*; -import org.codehaus.jackson.io.*; -import org.codehaus.jackson.sym.BytesToNameCanonicalizer; -import org.codehaus.jackson.sym.CharsToNameCanonicalizer; - -/** - * This class is used to determine the encoding of byte stream - * that is to contain JSON content. Rules are fairly simple, and - * defined in JSON specification (RFC-4627 or newer), except - * for BOM handling, which is a property of underlying - * streams. - */ -public final class ByteSourceBootstrapper -{ - /* - /********************************************* - /* Configuration - /********************************************* - */ - - final IOContext _context; - - final InputStream _in; - - /* - /********************************************* - /* Input buffering - /********************************************* - */ - - final byte[] _inputBuffer; - - private int _inputPtr; - - private int _inputEnd; - - /** - * Flag that indicates whether buffer above is to be recycled - * after being used or not. - */ - private final boolean _bufferRecyclable; - - /* - /********************************************* - /* Input location - /********************************************* - */ - - /** - * Current number of input units (bytes or chars) that were processed in - * previous blocks, - * before contents of current input buffer. - *

- * Note: includes possible BOMs, if those were part of the input. - */ - protected int _inputProcessed; - - /* - /********************************************* - /* Data gathered - /********************************************* - */ - - boolean _bigEndian = true; - int _bytesPerChar = 0; // 0 means "dunno yet" - - /* - /********************************************* - /* Life-cycle - /********************************************* - */ - - public ByteSourceBootstrapper(IOContext ctxt, InputStream in) - { - _context = ctxt; - _in = in; - _inputBuffer = ctxt.allocReadIOBuffer(); - _inputEnd = _inputPtr = 0; - _inputProcessed = 0; - _bufferRecyclable = true; - } - - public ByteSourceBootstrapper(IOContext ctxt, byte[] inputBuffer, int inputStart, int inputLen) - { - _context = ctxt; - _in = null; - _inputBuffer = inputBuffer; - _inputPtr = inputStart; - _inputEnd = (inputStart + inputLen); - // Need to offset this for correct location info - _inputProcessed = -inputStart; - _bufferRecyclable = false; - } - - /** - * Method that should be called after constructing an instace. - * It will figure out encoding that content uses, to allow - * for instantiating a proper scanner object. - */ - public JsonEncoding detectEncoding() - throws IOException, JsonParseException - { - boolean foundEncoding = false; - - // First things first: BOM handling - /* Note: we can require 4 bytes to be read, since no - * combination of BOM + valid JSON content can have - * shorter length (shortest valid JSON content is single - * digit char, but BOMs are chosen such that combination - * is always at least 4 chars long) - */ - if (ensureLoaded(4)) { - int quad = (_inputBuffer[_inputPtr] << 24) - | ((_inputBuffer[_inputPtr+1] & 0xFF) << 16) - | ((_inputBuffer[_inputPtr+2] & 0xFF) << 8) - | (_inputBuffer[_inputPtr+3] & 0xFF); - - if (handleBOM(quad)) { - foundEncoding = true; - } else { - /* If no BOM, need to auto-detect based on first char; - * this works since it must be 7-bit ascii (wrt. unicode - * compatible encodings, only ones JSON can be transferred - * over) - */ - // UTF-32? - if (checkUTF32(quad)) { - foundEncoding = true; - } else if (checkUTF16(quad >>> 16)) { - foundEncoding = true; - } - } - } else if (ensureLoaded(2)) { - int i16 = ((_inputBuffer[_inputPtr] & 0xFF) << 8) - | (_inputBuffer[_inputPtr+1] & 0xFF); - if (checkUTF16(i16)) { - foundEncoding = true; - } - } - - JsonEncoding enc; - - /* Not found yet? As per specs, this means it must be UTF-8. */ - if (!foundEncoding) { - enc = JsonEncoding.UTF8; - } else if (_bytesPerChar == 2) { - enc = _bigEndian ? JsonEncoding.UTF16_BE : JsonEncoding.UTF16_LE; - } else if (_bytesPerChar == 4) { - enc = _bigEndian ? JsonEncoding.UTF32_BE : JsonEncoding.UTF32_LE; - } else { - throw new RuntimeException("Internal error"); // should never get here - } - _context.setEncoding(enc); - return enc; - } - - public Reader constructReader() - throws IOException - { - JsonEncoding enc = _context.getEncoding(); - switch (enc) { - case UTF32_BE: - case UTF32_LE: - return new UTF32Reader(_context, _in, _inputBuffer, _inputPtr, _inputEnd, - _context.getEncoding().isBigEndian()); - - case UTF16_BE: - case UTF16_LE: - case UTF8: // only in non-common case where we don't want to do direct mapping - { - // First: do we have a Stream? If not, need to create one: - InputStream in = _in; - - if (in == null) { - in = new ByteArrayInputStream(_inputBuffer, _inputPtr, _inputEnd); - } else { - /* Also, if we have any read but unused input (usually true), - * need to merge that input in: - */ - if (_inputPtr < _inputEnd) { - in = new MergedStream(_context, in, _inputBuffer, _inputPtr, _inputEnd); - } - } - return new InputStreamReader(in, enc.getJavaName()); - } - } - throw new RuntimeException("Internal error"); // should never get here - } - - public JsonParser constructParser(int features, ObjectCodec codec, BytesToNameCanonicalizer rootByteSymbols, CharsToNameCanonicalizer rootCharSymbols) - throws IOException, JsonParseException - { - JsonEncoding enc = detectEncoding(); - - // As per [JACKSON-259], may want to fully disable canonicalization: - boolean canonicalize = JsonParser.Feature.CANONICALIZE_FIELD_NAMES.enabledIn(features); - boolean intern = JsonParser.Feature.INTERN_FIELD_NAMES.enabledIn(features); - if (enc == JsonEncoding.UTF8) { - /* and without canonicalization, byte-based approach is not performance; just use std UTF-8 reader - * (which is ok for larger input; not so hot for smaller; but this is not a common case) - */ - if (canonicalize) { - BytesToNameCanonicalizer can = rootByteSymbols.makeChild(canonicalize, intern); - return new Utf8StreamParser(_context, features, _in, codec, can, _inputBuffer, _inputPtr, _inputEnd, _bufferRecyclable); - } - } - return new ReaderBasedParser(_context, features, constructReader(), codec, rootCharSymbols.makeChild(canonicalize, intern)); - } - - /* - /********************************************* - /* Internal methods, parsing - /********************************************* - */ - - /** - * @return True if a BOM was succesfully found, and encoding - * thereby recognized. - */ - private boolean handleBOM(int quad) - throws IOException - { - /* Handling of (usually) optional BOM (required for - * multi-byte formats); first 32-bit charsets: - */ - switch (quad) { - case 0x0000FEFF: - _bigEndian = true; - _inputPtr += 4; - _bytesPerChar = 4; - return true; - case 0xFFFE0000: // UCS-4, LE? - _inputPtr += 4; - _bytesPerChar = 4; - _bigEndian = false; - return true; - case 0x0000FFFE: // UCS-4, in-order... - reportWeirdUCS4("2143"); // throws exception - case 0xFEFF0000: // UCS-4, in-order... - reportWeirdUCS4("3412"); // throws exception - } - // Ok, if not, how about 16-bit encoding BOMs? - int msw = quad >>> 16; - if (msw == 0xFEFF) { // UTF-16, BE - _inputPtr += 2; - _bytesPerChar = 2; - _bigEndian = true; - return true; - } - if (msw == 0xFFFE) { // UTF-16, LE - _inputPtr += 2; - _bytesPerChar = 2; - _bigEndian = false; - return true; - } - // And if not, then UTF-8 BOM? - if ((quad >>> 8) == 0xEFBBBF) { // UTF-8 - _inputPtr += 3; - _bytesPerChar = 1; - _bigEndian = true; // doesn't really matter - return true; - } - return false; - } - - private boolean checkUTF32(int quad) - throws IOException - { - /* Handling of (usually) optional BOM (required for - * multi-byte formats); first 32-bit charsets: - */ - if ((quad >> 8) == 0) { // 0x000000?? -> UTF32-BE - _bigEndian = true; - } else if ((quad & 0x00FFFFFF) == 0) { // 0x??000000 -> UTF32-LE - _bigEndian = false; - } else if ((quad & ~0x00FF0000) == 0) { // 0x00??0000 -> UTF32-in-order - reportWeirdUCS4("3412"); - } else if ((quad & ~0x0000FF00) == 0) { // 0x0000??00 -> UTF32-in-order - reportWeirdUCS4("2143"); - } else { - // Can not be valid UTF-32 encoded JSON... - return false; - } - // Not BOM (just regular content), nothing to skip past: - //_inputPtr += 4; - _bytesPerChar = 4; - return true; - } - - private boolean checkUTF16(int i16) - { - if ((i16 & 0xFF00) == 0) { // UTF-16BE - _bigEndian = true; - } else if ((i16 & 0x00FF) == 0) { // UTF-16LE - _bigEndian = false; - } else { // nope, not UTF-16 - return false; - } - // Not BOM (just regular content), nothing to skip past: - //_inputPtr += 2; - _bytesPerChar = 2; - return true; - } - - /* - /********************************************* - /* Internal methods, problem reporting - /********************************************* - */ - - private void reportWeirdUCS4(String type) - throws IOException - { - throw new CharConversionException("Unsupported UCS-4 endianness ("+type+") detected"); - } - - /* - /********************************************* - /* Internal methods, raw input access - /********************************************* - */ - - protected boolean ensureLoaded(int minimum) - throws IOException - { - /* Let's assume here buffer has enough room -- this will always - * be true for the limited used this method gets - */ - int gotten = (_inputEnd - _inputPtr); - while (gotten < minimum) { - int count; - - if (_in == null) { // block source - count = -1; - } else { - count = _in.read(_inputBuffer, _inputEnd, _inputBuffer.length - _inputEnd); - } - if (count < 1) { - return false; - } - _inputEnd += count; - gotten += count; - } - return true; - } -} - diff --git a/src/org/codehaus/jackson/impl/DefaultPrettyPrinter.java b/src/org/codehaus/jackson/impl/DefaultPrettyPrinter.java deleted file mode 100644 index 2424c34499..0000000000 --- a/src/org/codehaus/jackson/impl/DefaultPrettyPrinter.java +++ /dev/null @@ -1,264 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.*; -import java.util.Arrays; - -import org.codehaus.jackson.*; - -/** - * Default {@link PrettyPrinter} implementation that uses 2-space - * indentation with platform-default linefeeds. - * Usually this class is not instantiated directly, but instead - * method {@link JsonGenerator#useDefaultPrettyPrinter} is - * used, which will use an instance of this class for operation. - */ -public class DefaultPrettyPrinter - implements PrettyPrinter -{ - // // // Config, indentation - - /** - * By default, let's use only spaces to separate array values. - */ - protected Indenter _arrayIndenter = new FixedSpaceIndenter(); - - /** - * By default, let's use linefeed-adding indenter for separate - * object entries. We'll further configure indenter to use - * system-specific linefeeds, and 2 spaces per level (as opposed to, - * say, single tabs) - */ - protected Indenter _objectIndenter = new Lf2SpacesIndenter(); - - // // // Config, other white space configuration - - /** - * By default we will add spaces around colons used to - * separate object fields and values. - * If disabled, will not use spaces around colon. - */ - protected boolean _spacesInObjectEntries = true; - - // // // State: - - /** - * Number of open levels of nesting. Used to determine amount of - * indentation to use. - */ - protected int _nesting = 0; - - /* - //////////////////////////////////////////////////////////// - // Life-cycle (construct, configure) - //////////////////////////////////////////////////////////// - */ - - public DefaultPrettyPrinter() { } - - public void indentArraysWith(Indenter i) - { - _arrayIndenter = (i == null) ? new NopIndenter() : i; - } - - public void indentObjectsWith(Indenter i) - { - _objectIndenter = (i == null) ? new NopIndenter() : i; - } - - public void spacesInObjectEntries(boolean b) { _spacesInObjectEntries = b; } - /* - //////////////////////////////////////////////////////////// - // PrettyPrinter impl - //////////////////////////////////////////////////////////// - */ - - public void writeRootValueSeparator(JsonGenerator jg) - throws IOException, JsonGenerationException - { - jg.writeRaw(' '); - } - - public void writeStartObject(JsonGenerator jg) - throws IOException, JsonGenerationException - { - jg.writeRaw('{'); - if (!_objectIndenter.isInline()) { - ++_nesting; - } - } - - public void beforeObjectEntries(JsonGenerator jg) - throws IOException, JsonGenerationException - { - _objectIndenter.writeIndentation(jg, _nesting); - } - - /** - * Method called after an object field has been output, but - * before the value is output. - *

- * Default handling (without pretty-printing) will output a single - * colon to separate the two. Pretty-printer is - * to output a colon as well, but can surround that with other - * (white-space) decoration. - */ - public void writeObjectFieldValueSeparator(JsonGenerator jg) - throws IOException, JsonGenerationException - { - if (_spacesInObjectEntries) { - jg.writeRaw(" : "); - } else { - jg.writeRaw(':'); - } - } - - /** - * Method called after an object entry (field:value) has been completely - * output, and before another value is to be output. - *

- * Default handling (without pretty-printing) will output a single - * comma to separate the two. Pretty-printer is - * to output a comma as well, but can surround that with other - * (white-space) decoration. - */ - public void writeObjectEntrySeparator(JsonGenerator jg) - throws IOException, JsonGenerationException - { - jg.writeRaw(','); - _objectIndenter.writeIndentation(jg, _nesting); - } - - public void writeEndObject(JsonGenerator jg, int nrOfEntries) - throws IOException, JsonGenerationException - { - if (!_objectIndenter.isInline()) { - --_nesting; - } - if (nrOfEntries > 0) { - _objectIndenter.writeIndentation(jg, _nesting); - } else { - jg.writeRaw(' '); - } - jg.writeRaw('}'); - } - - public void writeStartArray(JsonGenerator jg) - throws IOException, JsonGenerationException - { - if (!_arrayIndenter.isInline()) { - ++_nesting; - } - jg.writeRaw('['); - } - - public void beforeArrayValues(JsonGenerator jg) - throws IOException, JsonGenerationException - { - _arrayIndenter.writeIndentation(jg, _nesting); - } - - /** - * Method called after an array value has been completely - * output, and before another value is to be output. - *

- * Default handling (without pretty-printing) will output a single - * comma to separate the two. Pretty-printer is - * to output a comma as well, but can surround that with other - * (white-space) decoration. - */ - public void writeArrayValueSeparator(JsonGenerator jg) - throws IOException, JsonGenerationException - { - jg.writeRaw(','); - _arrayIndenter.writeIndentation(jg, _nesting); - } - - public void writeEndArray(JsonGenerator jg, int nrOfValues) - throws IOException, JsonGenerationException - { - if (!_arrayIndenter.isInline()) { - --_nesting; - } - if (nrOfValues > 0) { - _arrayIndenter.writeIndentation(jg, _nesting); - } else { - jg.writeRaw(' '); - } - jg.writeRaw(']'); - } - - /* - //////////////////////////////////////////////////////////// - // Helper classes - //////////////////////////////////////////////////////////// - */ - - /** - * Dummy implementation that adds no indentation whatsoever - */ - public static class NopIndenter - implements Indenter - { - public NopIndenter() { } - public void writeIndentation(JsonGenerator jg, int level) { } - public boolean isInline() { return true; } - } - - /** - * This is a very simple indenter that only every adds a - * single space for indentation. It is used as the default - * indenter for array values. - */ - public static class FixedSpaceIndenter - implements Indenter - { - public FixedSpaceIndenter() { } - - public void writeIndentation(JsonGenerator jg, int level) - throws IOException, JsonGenerationException - { - jg.writeRaw(' '); - } - - public boolean isInline() { return true; } - } - - /** - * Default linefeed-based indenter uses system-specific linefeeds and - * 2 spaces for indentation per level. - */ - public static class Lf2SpacesIndenter - implements Indenter - { - final static String SYSTEM_LINE_SEPARATOR; - static { - String lf = null; - try { - lf = System.getProperty("line.separator"); - } catch (Throwable t) { } // access exception? - SYSTEM_LINE_SEPARATOR = (lf == null) ? "\n" : lf; - } - - final static int SPACE_COUNT = 64; - final static char[] SPACES = new char[SPACE_COUNT]; - static { - Arrays.fill(SPACES, ' '); - } - - public Lf2SpacesIndenter() { } - - public boolean isInline() { return false; } - - public void writeIndentation(JsonGenerator jg, int level) - throws IOException, JsonGenerationException - { - jg.writeRaw(SYSTEM_LINE_SEPARATOR); - level += level; // 2 spaces per level - while (level > SPACE_COUNT) { // should never happen but... - jg.writeRaw(SPACES, 0, SPACE_COUNT); - level -= SPACES.length; - } - jg.writeRaw(SPACES, 0, level); - } - } -} diff --git a/src/org/codehaus/jackson/impl/Indenter.java b/src/org/codehaus/jackson/impl/Indenter.java deleted file mode 100644 index 6249f55efa..0000000000 --- a/src/org/codehaus/jackson/impl/Indenter.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.IOException; - -import org.codehaus.jackson.*; - -/** - * Interface that defines objects that can produce indentation used - * to separate object entries and array values. Indentation in this - * context just means insertion of white space, independent of whether - * linefeeds are output. - */ -public interface Indenter -{ - public void writeIndentation(JsonGenerator jg, int level) - throws IOException, JsonGenerationException; - - /** - * @return True if indenter is considered inline (does not add linefeeds), - * false otherwise - */ - public boolean isInline(); -} diff --git a/src/org/codehaus/jackson/impl/JsonGeneratorBase.java b/src/org/codehaus/jackson/impl/JsonGeneratorBase.java deleted file mode 100644 index b05aea5d46..0000000000 --- a/src/org/codehaus/jackson/impl/JsonGeneratorBase.java +++ /dev/null @@ -1,507 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.*; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import org.codehaus.jackson.*; - -/** - * This base class implements part of API that a JSON generator exposes - * to applications, adds shared internal methods that sub-classes - * can use and adds some abstract methods sub-classes must implement. - */ -public abstract class JsonGeneratorBase - extends JsonGenerator -{ - /* - //////////////////////////////////////////////////// - // Configuration - //////////////////////////////////////////////////// - */ - - protected ObjectCodec _objectCodec; - - /** - * Bit flag composed of bits that indicate which - * {@link org.codehaus.jackson.JsonGenerator.Feature}s - * are enabled. - */ - protected int _features; - - /** - * Flag set to indicate that implicit conversion from number - * to JSON String is needed (as per - * {@link org.codehaus.jackson.JsonGenerator.Feature#WRITE_NUMBERS_AS_STRINGS}). - */ - protected boolean _cfgNumbersAsStrings; - - /* - //////////////////////////////////////////////////// - // State - //////////////////////////////////////////////////// - */ - - /** - * Object that keeps track of the current contextual state - * of the generator. - */ - protected JsonWriteContext _writeContext; - - /** - * Flag that indicates whether generator is closed or not. Gets - * set when it is closed by an explicit call - * ({@link #close}). - */ - protected boolean _closed; - - /* - //////////////////////////////////////////////////// - // Life-cycle - //////////////////////////////////////////////////// - */ - - protected JsonGeneratorBase(int features, ObjectCodec codec) - { - super(); - _features = features; - _writeContext = JsonWriteContext.createRootContext(); - _objectCodec = codec; - _cfgNumbersAsStrings = isEnabled(Feature.WRITE_NUMBERS_AS_STRINGS); - } - - /* - //////////////////////////////////////////////////// - // Configuration - //////////////////////////////////////////////////// - */ - - @Override - public JsonGenerator enable(Feature f) { - _features |= f.getMask(); - if (f == Feature.WRITE_NUMBERS_AS_STRINGS) { - _cfgNumbersAsStrings = true; - } - return this; - } - - @Override - public JsonGenerator disable(Feature f) { - _features &= ~f.getMask(); - if (f == Feature.WRITE_NUMBERS_AS_STRINGS) { - _cfgNumbersAsStrings = false; - } - return this; - } - - //public JsonGenerator configure(Feature f, boolean state) { } - - @Override - public final boolean isEnabled(Feature f) { - return (_features & f.getMask()) != 0; - } - - public final JsonGenerator useDefaultPrettyPrinter() - { - return setPrettyPrinter(new DefaultPrettyPrinter()); - } - - public final JsonGenerator setCodec(ObjectCodec oc) { - _objectCodec = oc; - return this; - } - - public final ObjectCodec getCodec() { return _objectCodec; } - - /* - //////////////////////////////////////////////////// - // Public API, accessors - //////////////////////////////////////////////////// - */ - - /** - * Note: co-variant return type. - */ - public final JsonWriteContext getOutputContext() { return _writeContext; } - - /* - //////////////////////////////////////////////////// - // Public API, write methods, structural - //////////////////////////////////////////////////// - */ - - public final void writeStartArray() - throws IOException, JsonGenerationException - { - // Array is a value, need to verify it's allowed - _verifyValueWrite("start an array"); - _writeContext = _writeContext.createChildArrayContext(); - if (_cfgPrettyPrinter != null) { - _cfgPrettyPrinter.writeStartArray(this); - } else { - _writeStartArray(); - } - } - - protected abstract void _writeStartArray() - throws IOException, JsonGenerationException; - - public final void writeEndArray() - throws IOException, JsonGenerationException - { - if (!_writeContext.inArray()) { - _reportError("Current context not an ARRAY but "+_writeContext.getTypeDesc()); - } - if (_cfgPrettyPrinter != null) { - _cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount()); - } else { - _writeEndArray(); - } - _writeContext = _writeContext.getParent(); - } - - protected abstract void _writeEndArray() - throws IOException, JsonGenerationException; - - public final void writeStartObject() - throws IOException, JsonGenerationException - { - _verifyValueWrite("start an object"); - _writeContext = _writeContext.createChildObjectContext(); - if (_cfgPrettyPrinter != null) { - _cfgPrettyPrinter.writeStartObject(this); - } else { - _writeStartObject(); - } - } - - protected abstract void _writeStartObject() - throws IOException, JsonGenerationException; - - public final void writeEndObject() - throws IOException, JsonGenerationException - { - if (!_writeContext.inObject()) { - _reportError("Current context not an object but "+_writeContext.getTypeDesc()); - } - _writeContext = _writeContext.getParent(); - if (_cfgPrettyPrinter != null) { - _cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount()); - } else { - _writeEndObject(); - } - } - - protected abstract void _writeEndObject() - throws IOException, JsonGenerationException; - - public final void writeFieldName(String name) - throws IOException, JsonGenerationException - { - // Object is a value, need to verify it's allowed - int status = _writeContext.writeFieldName(name); - if (status == JsonWriteContext.STATUS_EXPECT_VALUE) { - _reportError("Can not write a field name, expecting a value"); - } - _writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA)); - } - - protected abstract void _writeFieldName(String name, boolean commaBefore) - throws IOException, JsonGenerationException; - - /* - //////////////////////////////////////////////////// - // Public API, write methods, textual - //////////////////////////////////////////////////// - */ - - //public abstract void writeString(String text) throws IOException, JsonGenerationException; - - //public abstract void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException; - - //public abstract void writeRaw(String text) throws IOException, JsonGenerationException; - - //public abstract void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException; - - //public abstract void writeBinary(byte[] data, int offset, int len, boolean includeLFs) throws IOException, JsonGenerationException; - - /* - //////////////////////////////////////////////////// - // Public API, write methods, primitive - //////////////////////////////////////////////////// - */ - - public abstract void writeNumber(int i) - throws IOException, JsonGenerationException; - - public abstract void writeNumber(long l) - throws IOException, JsonGenerationException; - - public abstract void writeNumber(double d) - throws IOException, JsonGenerationException; - - public abstract void writeNumber(float f) - throws IOException, JsonGenerationException; - - public abstract void writeNumber(BigDecimal dec) - throws IOException, JsonGenerationException; - - public abstract void writeBoolean(boolean state) - throws IOException, JsonGenerationException; - - public abstract void writeNull() - throws IOException, JsonGenerationException; - - /* - //////////////////////////////////////////////////// - // Public API, write methods, POJOs, trees - //////////////////////////////////////////////////// - */ - - public void writeObject(Object value) - throws IOException, JsonProcessingException - { - if (value == null) { - // important: call method that does check value write: - writeNull(); - } else { - /* 02-Mar-2009, tatu: we are NOT to call _verifyValueWrite here, - * because that will be done when codec actually serializes - * contained POJO. If we did call it it would advance state - * causing exception later on - */ - if (_objectCodec != null) { - _objectCodec.writeValue(this, value); - return; - } - _writeSimpleObject(value); - } - } - - public void writeTree(JsonNode rootNode) - throws IOException, JsonProcessingException - { - // As with 'writeObject()', we are not check if write would work - if (rootNode == null) { - writeNull(); - } else { - if (_objectCodec == null) { - throw new IllegalStateException("No ObjectCodec defined for the generator, can not serialize JsonNode-based trees"); - } - _objectCodec.writeTree(this, rootNode); - } - } - - /* - //////////////////////////////////////////////////// - // Public API, low-level output handling - //////////////////////////////////////////////////// - */ - - public abstract void flush() throws IOException; - - public void close() throws IOException - { - _closed = true; - } - - public boolean isClosed() { return _closed; } - - /* - //////////////////////////////////////////////////// - // Public API, copy-through methods - //////////////////////////////////////////////////// - */ - - public final void copyCurrentEvent(JsonParser jp) - throws IOException, JsonProcessingException - { - switch(jp.getCurrentToken()) { - case START_OBJECT: - writeStartObject(); - break; - case END_OBJECT: - writeEndObject(); - break; - case START_ARRAY: - writeStartArray(); - break; - case END_ARRAY: - writeEndArray(); - break; - case FIELD_NAME: - writeFieldName(jp.getCurrentName()); - break; - case VALUE_STRING: - writeString(jp.getTextCharacters(), jp.getTextOffset(), jp.getTextLength()); - break; - case VALUE_NUMBER_INT: - switch (jp.getNumberType()) { - case INT: - writeNumber(jp.getIntValue()); - break; - case BIG_INTEGER: - writeNumber(jp.getBigIntegerValue()); - break; - default: - writeNumber(jp.getLongValue()); - } - break; - case VALUE_NUMBER_FLOAT: - switch (jp.getNumberType()) { - case BIG_DECIMAL: - writeNumber(jp.getDecimalValue()); - break; - case FLOAT: - writeNumber(jp.getFloatValue()); - break; - default: - writeNumber(jp.getDoubleValue()); - } - break; - case VALUE_TRUE: - writeBoolean(true); - break; - case VALUE_FALSE: - writeBoolean(false); - break; - case VALUE_NULL: - writeNull(); - break; - case VALUE_EMBEDDED_OBJECT: - writeObject(jp.getEmbeddedObject()); - break; - default: - _cantHappen(); - } - } - - public final void copyCurrentStructure(JsonParser jp) - throws IOException, JsonProcessingException - { - JsonToken t = jp.getCurrentToken(); - - // Let's handle field-name separately first - if (t == JsonToken.FIELD_NAME) { - writeFieldName(jp.getCurrentName()); - t = jp.nextToken(); - // fall-through to copy the associated value - } - - switch (t) { - case START_ARRAY: - writeStartArray(); - while (jp.nextToken() != JsonToken.END_ARRAY) { - copyCurrentStructure(jp); - } - writeEndArray(); - break; - case START_OBJECT: - writeStartObject(); - while (jp.nextToken() != JsonToken.END_OBJECT) { - copyCurrentStructure(jp); - } - writeEndObject(); - break; - default: // others are simple: - copyCurrentEvent(jp); - } - } - - /* - //////////////////////////////////////////////////// - // Package methods for this, sub-classes - //////////////////////////////////////////////////// - */ - - protected abstract void _releaseBuffers(); - - protected abstract void _verifyValueWrite(String typeMsg) - throws IOException, JsonGenerationException; - - protected void _reportError(String msg) - throws JsonGenerationException - { - throw new JsonGenerationException(msg); - } - - protected void _cantHappen() - { - throw new RuntimeException("Internal error: should never end up through this code path"); - } - - /** - * Helper method to try to call appropriate write method for given - * untyped Object. At this point, no structural conversions should be done, - * only simple basic types are to be coerced as necessary. - * - * @param value Non-null value to write - */ - protected void _writeSimpleObject(Object value) - throws IOException, JsonGenerationException - { - /* 31-Dec-2009, tatu: Actually, we could just handle some basic - * types even without codec. This can improve interoperability, - * and specifically help with TokenBuffer. - */ - if (value == null) { - writeNull(); - return; - } - if (value instanceof String) { - writeString((String) value); - return; - } - if (value instanceof Number) { - Number n = (Number) value; - if (n instanceof Integer) { - writeNumber(n.intValue()); - return; - } else if (n instanceof Long) { - writeNumber(n.longValue()); - return; - } else if (n instanceof Double) { - writeNumber(n.doubleValue()); - return; - } else if (n instanceof Float) { - writeNumber(n.floatValue()); - return; - } else if (n instanceof Short) { - writeNumber(n.shortValue()); - return; - } else if (n instanceof Byte) { - writeNumber(n.byteValue()); - return; - } else if (n instanceof BigInteger) { - writeNumber((BigInteger) n); - return; - } else if (n instanceof BigDecimal) { - writeNumber((BigDecimal) n); - return; - - // then Atomic types - - } else if (n instanceof AtomicInteger) { - writeNumber(((AtomicInteger) n).get()); - return; - } else if (n instanceof AtomicLong) { - writeNumber(((AtomicLong) n).get()); - return; - } - } else if (value instanceof byte[]) { - writeBinary((byte[]) value); - return; - } else if (value instanceof Boolean) { - writeBoolean(((Boolean) value).booleanValue()); - return; - } else if (value instanceof AtomicBoolean) { - writeBoolean(((AtomicBoolean) value).get()); - return; - } - throw new IllegalStateException("No ObjectCodec defined for the generator, can only serialize simple wrapper types (type passed " - +value.getClass().getName()+")"); - } -} diff --git a/src/org/codehaus/jackson/impl/JsonNumericParserBase.java b/src/org/codehaus/jackson/impl/JsonNumericParserBase.java deleted file mode 100644 index 2b37b1293e..0000000000 --- a/src/org/codehaus/jackson/impl/JsonNumericParserBase.java +++ /dev/null @@ -1,590 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.math.BigDecimal; -import java.math.BigInteger; - -import java.io.*; - -import org.codehaus.jackson.*; -import org.codehaus.jackson.io.IOContext; -import org.codehaus.jackson.io.NumberInput; - -/** - * Another intermediate base class used by all Jackson {@link JsonParser} - * implementations. Contains shared functionality for dealing with - * number parsing aspects, independent of input source decoding. - * - * @author Tatu Saloranta - */ -public abstract class JsonNumericParserBase - extends JsonParserBase -{ - /* Additionally we need to be able to distinguish between - * various numeric representations, since we try to use - * the fastest one that works for given textual representation. - */ - - final protected static int NR_UNKNOWN = 0; - - // First, integer types - - final protected static int NR_INT = 0x0001; - final protected static int NR_LONG = 0x0002; - final protected static int NR_BIGINT = 0x0004; - - // And then floating point types - - final protected static int NR_DOUBLE = 0x008; - final protected static int NR_BIGDECIMAL = 0x0010; - - // Also, we need some numeric constants - - final static BigDecimal BD_MIN_LONG = new BigDecimal(Long.MIN_VALUE); - final static BigDecimal BD_MAX_LONG = new BigDecimal(Long.MAX_VALUE); - - final static BigDecimal BD_MIN_INT = new BigDecimal(Long.MIN_VALUE); - final static BigDecimal BD_MAX_INT = new BigDecimal(Long.MAX_VALUE); - - final static long MIN_INT_L = (long) Integer.MIN_VALUE; - final static long MAX_INT_L = (long) Integer.MAX_VALUE; - - // These are not very accurate, but have to do... (for bounds checks) - - final static double MIN_LONG_D = (double) Long.MIN_VALUE; - final static double MAX_LONG_D = (double) Long.MAX_VALUE; - - final static double MIN_INT_D = (double) Integer.MIN_VALUE; - final static double MAX_INT_D = (double) Integer.MAX_VALUE; - - - // Digits, numeric - final protected static int INT_0 = '0'; - final protected static int INT_1 = '1'; - final protected static int INT_2 = '2'; - final protected static int INT_3 = '3'; - final protected static int INT_4 = '4'; - final protected static int INT_5 = '5'; - final protected static int INT_6 = '6'; - final protected static int INT_7 = '7'; - final protected static int INT_8 = '8'; - final protected static int INT_9 = '9'; - - final protected static int INT_MINUS = '-'; - final protected static int INT_PLUS = '+'; - final protected static int INT_DECIMAL_POINT = '.'; - - final protected static int INT_e = 'e'; - final protected static int INT_E = 'E'; - - final protected static char CHAR_NULL = '\0'; - - /* - //////////////////////////////////////////////////// - // Numeric value holders: multiple fields used for - // for efficiency - //////////////////////////////////////////////////// - */ - - /** - * Bitfield that indicates which numeric representations - * have been calculated for the current type - */ - protected int _numTypesValid = NR_UNKNOWN; - - // First primitives - - protected int _numberInt; - - protected long _numberLong; - - protected double _numberDouble; - - // And then object types - - protected BigInteger _numberBigInt; - - protected BigDecimal _numberBigDecimal; - - // And then other information about value itself - - /** - * Flag that indicates whether numeric value has a negative - * value. That is, whether its textual representation starts - * with minus character. - */ - protected boolean _numberNegative; - - /** - * Length of integer part of the number, in characters - */ - protected int mIntLength; - - /** - * Length of the fractional part (not including decimal - * point or exponent), in characters. - * Not used for pure integer values. - */ - protected int mFractLength; - - /** - * Length of the exponent part of the number, if any, not - * including 'e' marker or sign, just digits. - * Not used for pure integer values. - */ - protected int mExpLength; - - /* - //////////////////////////////////////////////////// - // Life-cycle - //////////////////////////////////////////////////// - */ - - protected JsonNumericParserBase(IOContext ctxt, int features) - { - super(ctxt, features); - } - - protected final JsonToken reset(boolean negative, int intLen, int fractLen, int expLen) - { - _numberNegative = negative; - mIntLength = intLen; - mFractLength = fractLen; - mExpLength = expLen; - _numTypesValid = NR_UNKNOWN; // to force parsing - if (fractLen < 1 && expLen < 1) { // integer - return JsonToken.VALUE_NUMBER_INT; - } - // Nope, floating point - return JsonToken.VALUE_NUMBER_FLOAT; - } - - /* - //////////////////////////////////////////////////// - // Additional methods for sub-classes to implement - //////////////////////////////////////////////////// - */ - - protected abstract JsonToken parseNumberText(int ch) - throws IOException, JsonParseException; - - /* - //////////////////////////////////////////////////// - // Numeric accessors of public API - //////////////////////////////////////////////////// - */ - - public Number getNumberValue() - throws IOException, JsonParseException - { - if (_numTypesValid == NR_UNKNOWN) { - parseNumericValue(NR_UNKNOWN); // will also check event type - } - // Separate types for int types - if (_currToken == JsonToken.VALUE_NUMBER_INT) { - if ((_numTypesValid & NR_INT) != 0) { - return Integer.valueOf(_numberInt); - } - if ((_numTypesValid & NR_LONG) != 0) { - return Long.valueOf(_numberLong); - } - if ((_numTypesValid & NR_BIGINT) != 0) { - return _numberBigInt; - } - // Shouldn't get this far but if we do - return _numberBigDecimal; - } - - /* And then floating point types. But here optimal type - * needs to be big decimal, to avoid losing any data? - */ - if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - return _numberBigDecimal; - } - if ((_numTypesValid & NR_DOUBLE) == 0) { // sanity check - _throwInternal(); - } - return Double.valueOf(_numberDouble); - } - - public NumberType getNumberType() - throws IOException, JsonParseException - { - if (_numTypesValid == NR_UNKNOWN) { - parseNumericValue(NR_UNKNOWN); // will also check event type - } - if (_currToken == JsonToken.VALUE_NUMBER_INT) { - if ((_numTypesValid & NR_INT) != 0) { - return NumberType.INT; - } - if ((_numTypesValid & NR_LONG) != 0) { - return NumberType.LONG; - } - return NumberType.BIG_INTEGER; - } - - /* And then floating point types. Here optimal type - * needs to be big decimal, to avoid losing any data? - * However... using BD is slow, so let's allow returning - * double as type if no explicit call has been made to access - * data as BD? - */ - if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - return NumberType.BIG_DECIMAL; - } - return NumberType.DOUBLE; - } - - public int getIntValue() - throws IOException, JsonParseException - { - if ((_numTypesValid & NR_INT) == 0) { - if (_numTypesValid == NR_UNKNOWN) { // not parsed at all - parseNumericValue(NR_INT); // will also check event type - } - if ((_numTypesValid & NR_INT) == 0) { // wasn't an int natively? - convertNumberToInt(); // let's make it so, if possible - } - } - return _numberInt; - } - - public long getLongValue() - throws IOException, JsonParseException - { - if ((_numTypesValid & NR_LONG) == 0) { - if (_numTypesValid == NR_UNKNOWN) { - parseNumericValue(NR_LONG); - } - if ((_numTypesValid & NR_LONG) == 0) { - convertNumberToLong(); - } - } - return _numberLong; - } - - public BigInteger getBigIntegerValue() - throws IOException, JsonParseException - { - if ((_numTypesValid & NR_BIGINT) == 0) { - if (_numTypesValid == NR_UNKNOWN) { - parseNumericValue(NR_BIGINT); - } - if ((_numTypesValid & NR_BIGINT) == 0) { - convertNumberToBigInteger(); - } - } - return _numberBigInt; - } - - public float getFloatValue() - throws IOException, JsonParseException - { - double value = getDoubleValue(); - /* 22-Jan-2009, tatu: Bounds/range checks would be tricky - * here, so let's not bother even trying... - */ - /* - if (value < -Float.MAX_VALUE || value > MAX_FLOAT_D) { - _reportError("Numeric value ("+getText()+") out of range of Java float"); - } - */ - return (float) value; - } - - public double getDoubleValue() - throws IOException, JsonParseException - { - if ((_numTypesValid & NR_DOUBLE) == 0) { - if (_numTypesValid == NR_UNKNOWN) { - parseNumericValue(NR_DOUBLE); - } - if ((_numTypesValid & NR_DOUBLE) == 0) { - convertNumberToDouble(); - } - } - return _numberDouble; - } - - public BigDecimal getDecimalValue() - throws IOException, JsonParseException - { - if ((_numTypesValid & NR_BIGDECIMAL) == 0) { - if (_numTypesValid == NR_UNKNOWN) { - parseNumericValue(NR_BIGDECIMAL); - } - if ((_numTypesValid & NR_BIGDECIMAL) == 0) { - convertNumberToBigDecimal(); - } - } - return _numberBigDecimal; - } - - - /* - //////////////////////////////////////////////////// - // Conversion from textual to numeric representation - //////////////////////////////////////////////////// - */ - - /** - * Method that will parse actual numeric value out of a syntactically - * valid number value. Type it will parse into depends on whether - * it is a floating point number, as well as its magnitude: smallest - * legal type (of ones available) is used for efficiency. - * - * @param expType Numeric type that we will immediately need, if any; - * mostly necessary to optimize handling of floating point numbers - */ - protected final void parseNumericValue(int expType) - throws JsonParseException - { - // First things first: must be a numeric event - if (_currToken == null || !_currToken.isNumeric()) { - _reportError("Current token ("+_currToken+") not numeric, can not use numeric value accessors"); - } - try { - // Int or float? - if (_currToken == JsonToken.VALUE_NUMBER_INT) { - char[] buf = _textBuffer.getTextBuffer(); - int offset = _textBuffer.getTextOffset(); - int len = mIntLength; - if (_numberNegative) { - ++offset; - } - if (len <= 9) { // definitely fits in int - int i = NumberInput.parseInt(buf, offset, len); - _numberInt = _numberNegative ? -i : i; - _numTypesValid = NR_INT; - return; - } - if (len <= 18) { // definitely fits AND is easy to parse using 2 int parse calls - long l = NumberInput.parseLong(buf, offset, len); - if (_numberNegative) { - l = -l; - } - // [JACKSON-230] Could still fit in int, need to check - if (len == 10) { - if (_numberNegative) { - if (l >= MIN_INT_L) { - _numberInt = (int) l; - _numTypesValid = NR_INT; - return; - } - } else { - if (l <= MAX_INT_L) { - _numberInt = (int) l; - _numTypesValid = NR_INT; - return; - } - } - } - _numberLong = l; - _numTypesValid = NR_LONG; - return; - } - String numStr = _textBuffer.contentsAsString(); - // [JACKSON-230] Some long cases still... - if (NumberInput.inLongRange(buf, offset, len, _numberNegative)) { - // Probably faster to construct a String, call parse, than to use BigInteger - _numberLong = Long.parseLong(numStr); - _numTypesValid = NR_LONG; - return; - } - // nope, need the heavy guns... (rare case) - _numberBigInt = new BigInteger(numStr); - _numTypesValid = NR_BIGINT; - return; - } - - /* Nope: floating point. Here we need to be careful to get - * optimal parsing strategy: choice is between accurate but - * slow (BigDecimal) and lossy but fast (Double). For now - * let's only use BD when explicitly requested -- it can - * still be constructed correctly at any point since we do - * retain textual representation - */ - if (expType == NR_BIGDECIMAL) { - _numberBigDecimal = _textBuffer.contentsAsDecimal(); - _numTypesValid = NR_BIGDECIMAL; - } else { - // Otherwise double has to do - _numberDouble = _textBuffer.contentsAsDouble(); - _numTypesValid = NR_DOUBLE; - } - } catch (NumberFormatException nex) { - // Can this ever occur? Due to overflow, maybe? - _wrapError("Malformed numeric value '"+_textBuffer.contentsAsString()+"'", nex); - } - } - - /* - //////////////////////////////////////////////////// - // Conversions - //////////////////////////////////////////////////// - */ - - protected void convertNumberToInt() - throws IOException, JsonParseException - { - // First, converting from long ought to be easy - if ((_numTypesValid & NR_LONG) != 0) { - // Let's verify it's lossless conversion by simple roundtrip - int result = (int) _numberLong; - if (((long) result) != _numberLong) { - _reportError("Numeric value ("+getText()+") out of range of int"); - } - _numberInt = result; - } else if ((_numTypesValid & NR_BIGINT) != 0) { - // !!! Should check for range... - _numberInt = _numberBigInt.intValue(); - } else if ((_numTypesValid & NR_DOUBLE) != 0) { - // Need to check boundaries - if (_numberDouble < MIN_INT_D || _numberDouble > MAX_INT_D) { - reportOverflowInt(); - } - _numberInt = (int) _numberDouble; - } else if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - if (BD_MIN_INT.compareTo(_numberBigDecimal) > 0 - || BD_MAX_INT.compareTo(_numberBigDecimal) < 0) { - reportOverflowInt(); - } - _numberInt = _numberBigDecimal.intValue(); - } else { - _throwInternal(); // should never get here - } - - _numTypesValid |= NR_INT; - } - - protected void convertNumberToLong() - throws IOException, JsonParseException - { - if ((_numTypesValid & NR_INT) != 0) { - _numberLong = (long) _numberInt; - } else if ((_numTypesValid & NR_BIGINT) != 0) { - // !!! Should check for range... - _numberLong = _numberBigInt.longValue(); - } else if ((_numTypesValid & NR_DOUBLE) != 0) { - // Need to check boundaries - if (_numberDouble < MIN_LONG_D || _numberDouble > MAX_LONG_D) { - reportOverflowLong(); - } - _numberLong = (long) _numberDouble; - } else if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - if (BD_MIN_LONG.compareTo(_numberBigDecimal) > 0 - || BD_MAX_LONG.compareTo(_numberBigDecimal) < 0) { - reportOverflowLong(); - } - _numberLong = _numberBigDecimal.longValue(); - } else { - _throwInternal(); // should never get here - } - - _numTypesValid |= NR_LONG; - } - - protected void convertNumberToBigInteger() - throws IOException, JsonParseException - { - if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - // here it'll just get truncated, no exceptions thrown - _numberBigInt = _numberBigDecimal.toBigInteger(); - } else if ((_numTypesValid & NR_LONG) != 0) { - _numberBigInt = BigInteger.valueOf(_numberLong); - } else if ((_numTypesValid & NR_INT) != 0) { - _numberBigInt = BigInteger.valueOf(_numberInt); - } else if ((_numTypesValid & NR_DOUBLE) != 0) { - _numberBigInt = BigDecimal.valueOf(_numberDouble).toBigInteger(); - } else { - _throwInternal(); // should never get here - } - _numTypesValid |= NR_BIGINT; - } - - protected void convertNumberToDouble() - throws IOException, JsonParseException - { - /* 05-Aug-2008, tatus: Important note: this MUST start with - * more accurate representations, since we don't know which - * value is the original one (others get generated when - * requested) - */ - - if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - _numberDouble = _numberBigDecimal.doubleValue(); - } else if ((_numTypesValid & NR_BIGINT) != 0) { - _numberDouble = _numberBigInt.doubleValue(); - } else if ((_numTypesValid & NR_LONG) != 0) { - _numberDouble = (double) _numberLong; - } else if ((_numTypesValid & NR_INT) != 0) { - _numberDouble = (double) _numberInt; - } else { - _throwInternal(); // should never get here - } - - _numTypesValid |= NR_DOUBLE; - } - - protected void convertNumberToBigDecimal() - throws IOException, JsonParseException - { - /* 05-Aug-2008, tatus: Important note: this MUST start with - * more accurate representations, since we don't know which - * value is the original one (others get generated when - * requested) - */ - - if ((_numTypesValid & NR_DOUBLE) != 0) { - /* Let's actually parse from String representation, - * to avoid rounding errors that non-decimal floating operations - * would incur - */ - _numberBigDecimal = new BigDecimal(getText()); - } else if ((_numTypesValid & NR_BIGINT) != 0) { - _numberBigDecimal = new BigDecimal(_numberBigInt); - } else if ((_numTypesValid & NR_LONG) != 0) { - _numberBigDecimal = BigDecimal.valueOf(_numberLong); - } else if ((_numTypesValid & NR_INT) != 0) { - _numberBigDecimal = BigDecimal.valueOf((long) _numberInt); - } else { - _throwInternal(); // should never get here - } - _numTypesValid |= NR_BIGDECIMAL; - } - - /* - //////////////////////////////////////////////////// - // Exception reporting - //////////////////////////////////////////////////// - */ - - protected void reportUnexpectedNumberChar(int ch, String comment) - throws JsonParseException - { - String msg = "Unexpected character ("+_getCharDesc(ch)+") in numeric value"; - if (comment != null) { - msg += ": "+comment; - } - _reportError(msg); - } - - protected void reportInvalidNumber(String msg) - throws JsonParseException - { - _reportError("Invalid numeric value: "+msg); - } - - - protected void reportOverflowInt() - throws IOException, JsonParseException - { - _reportError("Numeric value ("+getText()+") out of range of int ("+Integer.MIN_VALUE+" - "+Integer.MAX_VALUE+")"); - } - - protected void reportOverflowLong() - throws IOException, JsonParseException - { - _reportError("Numeric value ("+getText()+") out of range of long ("+Long.MIN_VALUE+" - "+Long.MAX_VALUE+")"); - } - -} diff --git a/src/org/codehaus/jackson/impl/JsonParserBase.java b/src/org/codehaus/jackson/impl/JsonParserBase.java deleted file mode 100644 index f2694422ad..0000000000 --- a/src/org/codehaus/jackson/impl/JsonParserBase.java +++ /dev/null @@ -1,666 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.*; - -import org.codehaus.jackson.*; -import org.codehaus.jackson.io.IOContext; -import org.codehaus.jackson.util.ByteArrayBuilder; -import org.codehaus.jackson.util.TextBuffer; - -/** - * Intermediate base class used by all Jackson {@link JsonParser} - * implementations. Contains most common things that are independent - * of actual underlying input source - * - * @author Tatu Saloranta - */ -public abstract class JsonParserBase - extends JsonParser -{ - // Control chars: - final static int INT_TAB = '\t'; - final static int INT_LF = '\n'; - final static int INT_CR = '\r'; - final static int INT_SPACE = 0x0020; - - // Markup - final static int INT_LBRACKET = '['; - final static int INT_RBRACKET = ']'; - final static int INT_LCURLY = '{'; - final static int INT_RCURLY = '}'; - final static int INT_QUOTE = '"'; - final static int INT_BACKSLASH = '\\'; - final static int INT_SLASH = '/'; - final static int INT_COLON = ':'; - final static int INT_COMMA = ','; - final static int INT_ASTERISK = '*'; - final static int INT_APOSTROPHE = '\''; - - // Letters we need - final static int INT_b = 'b'; - final static int INT_f = 'f'; - final static int INT_n = 'n'; - final static int INT_r = 'r'; - final static int INT_t = 't'; - final static int INT_u = 'u'; - - /* - //////////////////////////////////////////////////// - // Generic I/O state - //////////////////////////////////////////////////// - */ - - /** - * I/O context for this reader. It handles buffer allocation - * for the reader. - */ - final protected IOContext _ioContext; - - /** - * Flag that indicates whether parser is closed or not. Gets - * set when parser is either closed by explicit call - * ({@link #close}) or when end-of-input is reached. - */ - protected boolean _closed; - - /* - //////////////////////////////////////////////////// - // Current input data - //////////////////////////////////////////////////// - */ - - // Note: type of actual buffer depends on sub-class, can't include - - /** - * Pointer to next available character in buffer - */ - protected int _inputPtr = 0; - - /** - * Index of character after last available one in the buffer. - */ - protected int _inputEnd = 0; - - /* - //////////////////////////////////////////////////// - // Current input location information - //////////////////////////////////////////////////// - */ - - /** - * Number of characters that were contained in previous blocks - * (blocks that were already processed prior to the current buffer). - */ - protected long _currInputProcessed = 0L; - - /** - * Current row location of current point in input buffer, starting - * from 1 - */ - protected int _currInputRow = 1; - - /** - * Current index of the first character of the current row in input - * buffer. Needed to calculate column position, if necessary; benefit - * of not having column itself is that this only has to be updated - * once per line. - */ - protected int _currInputRowStart = 0; - - /* - //////////////////////////////////////////////////// - // Information about starting location of event - // Reader is pointing to; updated on-demand - //////////////////////////////////////////////////// - */ - - // // // Location info at point when current token was started - - /** - * Total number of characters read before start of current token. - * For big (gigabyte-sized) sizes are possible, needs to be long, - * unlike pointers and sizes related to in-memory buffers. - */ - protected long _tokenInputTotal = 0; - - /** - * Input row on which current token starts, 1-based - */ - protected int _tokenInputRow = 1; - - /** - * Column on input row that current token starts; 0-based (although - * in the end it'll be converted to 1-based) - */ - protected int _tokenInputCol = 0; - - /* - //////////////////////////////////////////////////// - // Parsing state - //////////////////////////////////////////////////// - */ - - /** - * Information about parser context, context in which - * the next token is to be parsed (root, array, object). - */ - protected JsonReadContext _parsingContext; - - /** - * Secondary token related to the current token: used when - * the current token is FIELD_NAME but the - * actual value token is also known. - */ - protected JsonToken _nextToken; - - /** - * Flag that indicates that the current token has not yet - * been fully processed, and needs to be finished for - * some access (or skipped to obtain the next token) - */ - protected boolean _tokenIncomplete = false; - - /* - //////////////////////////////////////////////////// - // Buffer(s) for local name(s) and text content - //////////////////////////////////////////////////// - */ - - /** - * Buffer that contains contents of String values, including - * field names if necessary (name split across boundary, - * contains escape sequence, or access needed to char array) - */ - protected final TextBuffer _textBuffer; - - /** - * Temporary buffer that is needed if field name is accessed - * using {@link #getTextCharacters} method (instead of String - * returning alternatives) - */ - protected char[] _nameCopyBuffer = null; - - /** - * Flag set to indicate whether the field name is available - * from the name copy buffer or not (in addition to its String - * representation being available via read context) - */ - protected boolean _nameCopied = false; - - /** - * ByteArrayBuilder is needed if 'getBinaryValue' is called. If so, - * we better reuse it for remainder of content. - */ - ByteArrayBuilder _byteArrayBuilder = null; - - /** - * We will hold on to decoded binary data, for duration of - * current event, so that multiple calls to - * {@link #getBinaryValue} will not need to decode data more - * than once. - */ - protected byte[] _binaryValue; - - /* - //////////////////////////////////////////////////// - // Life-cycle - //////////////////////////////////////////////////// - */ - - protected JsonParserBase(IOContext ctxt, int features) - { - _ioContext = ctxt; - _features = features; - _textBuffer = ctxt.constructTextBuffer(); - _parsingContext = JsonReadContext.createRootContext(_tokenInputRow, _tokenInputCol); - } - - /* - //////////////////////////////////////////////////// - // Configuration overrides if any - //////////////////////////////////////////////////// - */ - - // from base class: - - //public void enableFeature(Feature f) - //public void disableFeature(Feature f) - //public void setFeature(Feature f, boolean state) - //public boolean isFeatureEnabled(Feature f) - - /* - //////////////////////////////////////////////////// - // Abstract methods needed from sub-classes - //////////////////////////////////////////////////// - */ - - protected abstract void _finishString() throws IOException, JsonParseException; - - /* - //////////////////////////////////////////////////// - // JsonParser impl - //////////////////////////////////////////////////// - */ - - public abstract JsonToken nextToken() - throws IOException, JsonParseException; - - //public final JsonToken nextValue() - - public JsonParser skipChildren() - throws IOException, JsonParseException - { - if (_currToken != JsonToken.START_OBJECT - && _currToken != JsonToken.START_ARRAY) { - return this; - } - int open = 1; - - /* Since proper matching of start/end markers is handled - * by nextToken(), we'll just count nesting levels here - */ - while (true) { - JsonToken t = nextToken(); - if (t == null) { - _handleEOF(); - /* given constraints, above should never return; - * however, FindBugs doesn't know about it and - * complains... so let's add dummy break here - */ - return this; - } - switch (t) { - case START_OBJECT: - case START_ARRAY: - ++open; - break; - case END_OBJECT: - case END_ARRAY: - if (--open == 0) { - return this; - } - break; - } - } - } - - //public JsonToken getCurrentToken() - - //public boolean hasCurrentToken() - - /** - * Method that can be called to get the name associated with - * the current event. - */ - public String getCurrentName() - throws IOException, JsonParseException - { - return _parsingContext.getCurrentName(); - } - - public void close() throws IOException - { - _closed = true; - _closeInput(); - // Also, internal buffer(s) can now be released as well - _releaseBuffers(); - } - - public boolean isClosed() { return _closed; } - - public JsonReadContext getParsingContext() - { - return _parsingContext; - } - - /** - * Method that return the starting location of the current - * token; that is, position of the first character from input - * that starts the current token. - */ - public JsonLocation getTokenLocation() - { - return new JsonLocation(_ioContext.getSourceReference(), - getTokenCharacterOffset(), - getTokenLineNr(), - getTokenColumnNr()); - } - - /** - * Method that returns location of the last processed character; - * usually for error reporting purposes - */ - public JsonLocation getCurrentLocation() - { - int col = _inputPtr - _currInputRowStart + 1; // 1-based - return new JsonLocation(_ioContext.getSourceReference(), - _currInputProcessed + _inputPtr - 1, - _currInputRow, col); - } - - /* - //////////////////////////////////////////////////// - // Public API, access to token information, text - //////////////////////////////////////////////////// - */ - - /** - * Method for accessing textual representation of the current event; - * if no current event (before first call to {@link #nextToken}, or - * after encountering end-of-input), returns null. - * Method can be called for any event. - */ - public String getText() - throws IOException, JsonParseException - { - if (_currToken != null) { // null only before/after document - switch (_currToken) { - case FIELD_NAME: - return _parsingContext.getCurrentName(); - - case VALUE_STRING: - if (_tokenIncomplete) { - _tokenIncomplete = false; - _finishString(); // only strings can be incomplete - } - // fall through - case VALUE_NUMBER_INT: - case VALUE_NUMBER_FLOAT: - return _textBuffer.contentsAsString(); - - default: - return _currToken.asString(); - } - } - return null; - } - - public char[] getTextCharacters() - throws IOException, JsonParseException - { - if (_currToken != null) { // null only before/after document - switch (_currToken) { - - case FIELD_NAME: - if (!_nameCopied) { - String name = _parsingContext.getCurrentName(); - int nameLen = name.length(); - if (_nameCopyBuffer == null) { - _nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen); - } else if (_nameCopyBuffer.length < nameLen) { - _nameCopyBuffer = new char[nameLen]; - } - name.getChars(0, nameLen, _nameCopyBuffer, 0); - _nameCopied = true; - } - return _nameCopyBuffer; - - case VALUE_STRING: - if (_tokenIncomplete) { - _tokenIncomplete = false; - _finishString(); // only strings can be incomplete - } - // fall through - case VALUE_NUMBER_INT: - case VALUE_NUMBER_FLOAT: - return _textBuffer.getTextBuffer(); - - default: - return _currToken.asCharArray(); - } - } - return null; - } - - public int getTextLength() - throws IOException, JsonParseException - { - if (_currToken != null) { // null only before/after document - switch (_currToken) { - - case FIELD_NAME: - return _parsingContext.getCurrentName().length(); - case VALUE_STRING: - if (_tokenIncomplete) { - _tokenIncomplete = false; - _finishString(); // only strings can be incomplete - } - // fall through - case VALUE_NUMBER_INT: - case VALUE_NUMBER_FLOAT: - return _textBuffer.size(); - - default: - return _currToken.asCharArray().length; - } - } - return 0; - } - - public int getTextOffset() - throws IOException, JsonParseException - { - // Most have offset of 0, only some may have other values: - if (_currToken != null) { - switch (_currToken) { - case FIELD_NAME: - return 0; - case VALUE_STRING: - if (_tokenIncomplete) { - _tokenIncomplete = false; - _finishString(); // only strings can be incomplete - } - // fall through - case VALUE_NUMBER_INT: - case VALUE_NUMBER_FLOAT: - return _textBuffer.getTextOffset(); - } - } - return 0; - } - - /* - //////////////////////////////////////////////////// - // Public API, access to token information, binary - //////////////////////////////////////////////////// - */ - - public final byte[] getBinaryValue(Base64Variant b64variant) - throws IOException, JsonParseException - { - if (_currToken != JsonToken.VALUE_STRING) { - _reportError("Current token ("+_currToken+") not VALUE_STRING, can not access as binary"); - } - /* To ensure that we won't see inconsistent data, better clear up - * state... - */ - if (_tokenIncomplete) { - try { - _binaryValue = _decodeBase64(b64variant); - } catch (IllegalArgumentException iae) { - throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage()); - } - /* let's clear incomplete only now; allows for accessing other - * textual content in error cases - */ - _tokenIncomplete = false; - } - return _binaryValue; - } - - protected abstract byte[] _decodeBase64(Base64Variant b64variant) - throws IOException, JsonParseException; - - /* - //////////////////////////////////////////////////// - // Public low-level accessors - //////////////////////////////////////////////////// - */ - - public final long getTokenCharacterOffset() { return _tokenInputTotal; } - public final int getTokenLineNr() { return _tokenInputRow; } - public final int getTokenColumnNr() { return _tokenInputCol+1; } - - /* - //////////////////////////////////////////////////// - // Low-level reading, other - //////////////////////////////////////////////////// - */ - - protected abstract boolean loadMore() throws IOException; - - protected final void loadMoreGuaranteed() - throws IOException - { - if (!loadMore()) { - _reportInvalidEOF(); - } - } - - protected abstract void _closeInput() - throws IOException; - - /** - * Method called to release internal buffers owned by the base - * reader. This may be called along with {@link #_closeInput} (for - * example, when explicitly closing this reader instance), or - * separately (if need be). - */ - protected void _releaseBuffers() throws IOException - { - _textBuffer.releaseBuffers(); - char[] buf = _nameCopyBuffer; - if (buf != null) { - _nameCopyBuffer = null; - _ioContext.releaseNameCopyBuffer(buf); - } - } - - /** - * Method called when an EOF is encountered between tokens. - * If so, it may be a legitimate EOF, but only iff there - * is no open non-root context. - */ - protected void _handleEOF() - throws JsonParseException - { - if (!_parsingContext.inRoot()) { - _reportInvalidEOF(": expected close marker for "+_parsingContext.getTypeDesc()+" (from "+_parsingContext.getStartLocation(_ioContext.getSourceReference())+")"); - } - } - - /* - //////////////////////////////////////////////////// - // Error reporting - //////////////////////////////////////////////////// - */ - - protected void _reportUnexpectedChar(int ch, String comment) - throws JsonParseException - { - String msg = "Unexpected character ("+_getCharDesc(ch)+")"; - if (comment != null) { - msg += ": "+comment; - } - _reportError(msg); - } - - protected void _reportInvalidEOF() - throws JsonParseException - { - _reportInvalidEOF(" in "+_currToken); - } - - protected void _reportInvalidEOF(String msg) - throws JsonParseException - { - _reportError("Unexpected end-of-input"+msg); - } - - protected void _throwInvalidSpace(int i) - throws JsonParseException - { - char c = (char) i; - String msg = "Illegal character ("+_getCharDesc(c)+"): only regular white space (\\r, \\n, \\t) is allowed between tokens"; - _reportError(msg); - } - - /** - * Method called to report a problem with unquoted control character. - * Note: starting with version 1.4, it is possible to suppress - * exception by enabling {@link Feature.ALLOW_UNQUOTED_CONTROL_CHARS}. - */ - protected void _throwUnquotedSpace(int i, String ctxtDesc) - throws JsonParseException - { - // JACKSON-208; possible to allow unquoted control chars: - if (!isEnabled(Feature.ALLOW_UNQUOTED_CONTROL_CHARS) || i >= INT_SPACE) { - char c = (char) i; - String msg = "Illegal unquoted character ("+_getCharDesc(c)+"): has to be escaped using backslash to be included in "+ctxtDesc; - _reportError(msg); - } - } - - protected void _reportMismatchedEndMarker(int actCh, char expCh) - throws JsonParseException - { - String startDesc = ""+_parsingContext.getStartLocation(_ioContext.getSourceReference()); - _reportError("Unexpected close marker '"+((char) actCh)+"': expected '"+expCh+"' (for "+_parsingContext.getTypeDesc()+" starting at "+startDesc+")"); - } - - /* - //////////////////////////////////////////////////// - // Error reporting, generic - //////////////////////////////////////////////////// - */ - - protected final static String _getCharDesc(int ch) - { - char c = (char) ch; - if (Character.isISOControl(c)) { - return "(CTRL-CHAR, code "+ch+")"; - } - if (ch > 255) { - return "'"+c+"' (code "+ch+" / 0x"+Integer.toHexString(ch)+")"; - } - return "'"+c+"' (code "+ch+")"; - } - - protected final void _reportError(String msg) - throws JsonParseException - { - throw _constructError(msg); - } - - protected final void _wrapError(String msg, Throwable t) - throws JsonParseException - { - throw _constructError(msg, t); - } - - protected final void _throwInternal() - { - throw new RuntimeException("Internal error: this code path should never get executed"); - } - - protected final JsonParseException _constructError(String msg, Throwable t) - { - return new JsonParseException(msg, getCurrentLocation(), t); - } - - /* - //////////////////////////////////////////////////// - // Other helper methods for sub-classes - //////////////////////////////////////////////////// - */ - - public ByteArrayBuilder _getByteArrayBuilder() - { - if (_byteArrayBuilder == null) { - _byteArrayBuilder = new ByteArrayBuilder(); - } else { - _byteArrayBuilder.reset(); - } - return _byteArrayBuilder; - } -} diff --git a/src/org/codehaus/jackson/impl/JsonReadContext.java b/src/org/codehaus/jackson/impl/JsonReadContext.java deleted file mode 100644 index a7cc11b4ad..0000000000 --- a/src/org/codehaus/jackson/impl/JsonReadContext.java +++ /dev/null @@ -1,176 +0,0 @@ -package org.codehaus.jackson.impl; - -import org.codehaus.jackson.*; -import org.codehaus.jackson.util.CharTypes; - -/** - * Extension of {@link JsonStreamContext}, which implements - * core methods needed, and also exposes - * more complete API to parser implementation classes. - */ -public final class JsonReadContext - extends JsonStreamContext -{ - // // // Configuration - - protected final JsonReadContext _parent; - - // // // Location information (minus source reference) - - //long mTotalChars; - - protected int _lineNr; - protected int _columnNr; - - protected String _currentName; - - /* - ////////////////////////////////////////////////// - // Simple instance reuse slots; speeds up things - // a bit (10-15%) for docs with lots of small - // arrays/objects (for which allocation was - // visible in profile stack frames) - ////////////////////////////////////////////////// - */ - - JsonReadContext _child = null; - - /* - ////////////////////////////////////////////////// - // Instance construction, reuse - ////////////////////////////////////////////////// - */ - - public JsonReadContext(JsonReadContext parent, - int type, int lineNr, int colNr) - { - super(type); - _parent = parent; - _lineNr = lineNr; - _columnNr = colNr; - } - - protected final void reset(int type, int lineNr, int colNr) - { - _type = type; - _index = -1; - _lineNr = lineNr; - _columnNr = colNr; - _currentName = null; - } - - // // // Factory methods - - public static JsonReadContext createRootContext(int lineNr, int colNr) - { - return new JsonReadContext(null, TYPE_ROOT, lineNr, colNr); - } - - public final JsonReadContext createChildArrayContext(int lineNr, int colNr) - { - JsonReadContext ctxt = _child; - if (ctxt == null) { - return (_child = new JsonReadContext(this, TYPE_ARRAY, lineNr, colNr)); - } - ctxt.reset(TYPE_ARRAY, lineNr, colNr); - return ctxt; - } - - public final JsonReadContext createChildObjectContext(int lineNr, int colNr) - { - JsonReadContext ctxt = _child; - if (ctxt == null) { - return (_child = new JsonReadContext(this, TYPE_OBJECT, lineNr, colNr)); - } - ctxt.reset(TYPE_OBJECT, lineNr, colNr); - return ctxt; - } - - /* - ////////////////////////////////////////////////// - // Abstract method implementation - ////////////////////////////////////////////////// - */ - - public final String getCurrentName() { return _currentName; } - - public final JsonReadContext getParent() { return _parent; } - - /* - ////////////////////////////////////////////////// - // Extended API - ////////////////////////////////////////////////// - */ - - /** - * @return Location pointing to the point where the context - * start marker was found - */ - public final JsonLocation getStartLocation(Object srcRef) - { - /* We don't keep track of offsets at this level (only - * reader does) - */ - long totalChars = -1L; - - return new JsonLocation(srcRef, totalChars, _lineNr, _columnNr); - } - - /* - ////////////////////////////////////////////////// - // State changes - ////////////////////////////////////////////////// - */ - - public final boolean expectComma() - { - /* Assumption here is that we will be getting a value (at least - * before calling this method again), and - * so will auto-increment index to avoid having to do another call - */ - int ix = ++_index; // starts from -1 - return (_type != TYPE_ROOT && ix > 0); - } - - public void setCurrentName(String name) - { - _currentName = name; - } - - /* - ////////////////////////////////////////////////// - // Overridden standard methods - ////////////////////////////////////////////////// - */ - - /** - * Overridden to provide developer readable "JsonPath" representation - * of the context. - */ - public final String toString() - { - StringBuilder sb = new StringBuilder(64); - switch (_type) { - case TYPE_ROOT: - sb.append("/"); - break; - case TYPE_ARRAY: - sb.append('['); - sb.append(getCurrentIndex()); - sb.append(']'); - break; - case TYPE_OBJECT: - sb.append('{'); - if (_currentName != null) { - sb.append('"'); - CharTypes.appendQuoted(sb, _currentName); - sb.append('"'); - } else { - sb.append('?'); - } - sb.append(']'); - break; - } - return sb.toString(); - } -} diff --git a/src/org/codehaus/jackson/impl/JsonWriteContext.java b/src/org/codehaus/jackson/impl/JsonWriteContext.java deleted file mode 100644 index 3d52062f97..0000000000 --- a/src/org/codehaus/jackson/impl/JsonWriteContext.java +++ /dev/null @@ -1,228 +0,0 @@ -package org.codehaus.jackson.impl; - -import org.codehaus.jackson.*; - -/** - * Extension of {@link JsonStreamContext}, which implements - * core methods needed, and also exposes - * more complete API to generator implementation classes. - */ -public abstract class JsonWriteContext - extends JsonStreamContext -{ - // // // Return values for writeValue() - - public final static int STATUS_OK_AS_IS = 0; - public final static int STATUS_OK_AFTER_COMMA = 1; - public final static int STATUS_OK_AFTER_COLON = 2; - public final static int STATUS_OK_AFTER_SPACE = 3; // in root context - public final static int STATUS_EXPECT_VALUE = 4; - public final static int STATUS_EXPECT_NAME = 5; - - protected final JsonWriteContext _parent; - - /* - ////////////////////////////////////////////////// - // Simple instance reuse slots; speed up things - // a bit (10-15%) for docs with lots of small - // arrays/objects - ////////////////////////////////////////////////// - */ - - JsonWriteContext _childArray = null; - - JsonWriteContext _childObject = null; - - /* - ////////////////////////////////////////////////// - // Life-cycle - ////////////////////////////////////////////////// - */ - - protected JsonWriteContext(int type, JsonWriteContext parent) - { - super(type); - _parent = parent; - } - - // // // Factory methods - - public static JsonWriteContext createRootContext() - { - return new RootWContext(); - } - - public final JsonWriteContext createChildArrayContext() - { - JsonWriteContext ctxt = _childArray; - if (ctxt == null) { - _childArray = ctxt = new ArrayWContext(this); - } else { // need to reset settings; parent is already ok - ctxt._index = -1; - } - return ctxt; - } - - public final JsonWriteContext createChildObjectContext() - { - JsonWriteContext ctxt = _childObject; - if (ctxt == null) { - _childObject = ctxt = new ObjectWContext(this); - } else { // need to reset settings; parent is already ok - ctxt._index = -1; - } - return ctxt; - } - - // // // Shared API - - public final JsonWriteContext getParent() { return _parent; } - - // // // API sub-classes are to implement - - /** - * Method that writer is to call before it writes a field name. - * - * @return Index of the field entry (0-based) - */ - public abstract int writeFieldName(String name); - - public abstract int writeValue(); - - // // // Internally used abstract methods - - protected abstract void appendDesc(StringBuilder sb); - - // // // Overridden standard methods - - /** - * Overridden to provide developer writeable "JsonPath" representation - * of the context. - */ - public final String toString() - { - StringBuilder sb = new StringBuilder(64); - appendDesc(sb); - return sb.toString(); - } -} - -/** - * Root context is simple, as only state it keeps is the index of - * the currently active entry. - */ -final class RootWContext - extends JsonWriteContext -{ - public RootWContext() - { - super(TYPE_ROOT, null); - } - - public String getCurrentName() { return null; } - - public int writeFieldName(String name) - { - return STATUS_EXPECT_VALUE; - } - - public int writeValue() - { - // No commas within root context, but need space - ++_index; - return (_index == 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_SPACE; - } - - protected void appendDesc(StringBuilder sb) - { - sb.append("/"); - } -} - -final class ArrayWContext - extends JsonWriteContext -{ - public ArrayWContext(JsonWriteContext parent) - { - super(TYPE_ARRAY, parent); - } - - public String getCurrentName() { return null; } - - public int writeFieldName(String name) - { - return STATUS_EXPECT_VALUE; - } - - public int writeValue() - { - int ix = _index; - ++_index; - return (ix < 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_COMMA; - } - - protected void appendDesc(StringBuilder sb) - { - sb.append('['); - sb.append(getCurrentIndex()); - sb.append(']'); - } -} - -final class ObjectWContext - extends JsonWriteContext -{ - /** - * Name of the field of which value is to be parsed. - */ - protected String _currentName; - - /** - * Flag to indicate that the context just received the - * field name, and is to get a value next - */ - protected boolean _expectValue; - - public ObjectWContext(JsonWriteContext parent) - { - super(TYPE_OBJECT, parent); - _currentName = null; - _expectValue = false; - } - - public String getCurrentName() { return _currentName; } - - public int writeFieldName(String name) - { - if (_currentName != null) { // just wrote a name... - return STATUS_EXPECT_VALUE; - } - _currentName = name; - return (_index < 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_COMMA; - } - - public int writeValue() - { - if (_currentName == null) { - return STATUS_EXPECT_NAME; - } - _currentName = null; - ++_index; - return STATUS_OK_AFTER_COLON; - } - - protected void appendDesc(StringBuilder sb) - { - sb.append('{'); - if (_currentName != null) { - sb.append('"'); - // !!! TODO: Name chars should be escaped? - sb.append(_currentName); - sb.append('"'); - } else { - sb.append('?'); - } - sb.append(']'); - } -} - diff --git a/src/org/codehaus/jackson/impl/ReaderBasedNumericParser.java b/src/org/codehaus/jackson/impl/ReaderBasedNumericParser.java deleted file mode 100644 index d55fea62bc..0000000000 --- a/src/org/codehaus/jackson/impl/ReaderBasedNumericParser.java +++ /dev/null @@ -1,302 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.IOException; -import java.io.Reader; - -import org.codehaus.jackson.io.IOContext; -import org.codehaus.jackson.JsonParseException; -import org.codehaus.jackson.JsonToken; - -/** - * Intermediate class that implements handling of numeric parsing. - * Separate from the actual parser class just to isolate numeric - * parsing: would be nice to use aggregation, but unfortunately - * many parts are hard to implement without direct access to - * underlying buffers. - */ -public abstract class ReaderBasedNumericParser - extends ReaderBasedParserBase -{ - /* - //////////////////////////////////////////////////// - // Life-cycle - //////////////////////////////////////////////////// - */ - - public ReaderBasedNumericParser(IOContext pc, int features, Reader r) - { - super(pc, features, r); - } - - /* - //////////////////////////////////////////////////// - // Textual parsing of number values - //////////////////////////////////////////////////// - */ - - /** - * Initial parsing method for number values. It needs to be able - * to parse enough input to be able to determine whether the - * value is to be considered a simple integer value, or a more - * generic decimal value: latter of which needs to be expressed - * as a floating point number. The basic rule is that if the number - * has no fractional or exponential part, it is an integer; otherwise - * a floating point number. - *

- * Because much of input has to be processed in any case, no partial - * parsing is done: all input text will be stored for further - * processing. However, actual numeric value conversion will be - * deferred, since it is usually the most complicated and costliest - * part of processing. - */ - @Override - protected final JsonToken parseNumberText(int ch) - throws IOException, JsonParseException - { - /* Although we will always be complete with respect to textual - * representation (that is, all characters will be parsed), - * actual conversion to a number is deferred. Thus, need to - * note that no representations are valid yet - */ - boolean negative = (ch == INT_MINUS); - int ptr = _inputPtr; - int startPtr = ptr-1; // to include sign/digit already read - final int inputLen = _inputEnd; - - dummy_loop: - do { // dummy loop, to be able to break out - if (negative) { // need to read the next digit - if (ptr >= _inputEnd) { - break dummy_loop; - } - ch = _inputBuffer[ptr++]; - // First check: must have a digit to follow minus sign - if (ch > INT_9 || ch < INT_0) { - reportUnexpectedNumberChar(ch, "expected digit (0-9) to follow minus sign, for valid numeric value"); - } - /* (note: has been checked for non-negative already, in - * the dispatching code that determined it should be - * a numeric value) - */ - } - - /* First, let's see if the whole number is contained within - * the input buffer unsplit. This should be the common case; - * and to simplify processing, we will just reparse contents - * in the alternative case (number split on buffer boundary) - */ - - int intLen = 1; // already got one - - // First let's get the obligatory integer part: - - int_loop: - while (true) { - if (ptr >= _inputEnd) { - break dummy_loop; - } - ch = (int) _inputBuffer[ptr++]; - if (ch < INT_0 || ch > INT_9) { - break int_loop; - } - // The only check: no leading zeroes - if (++intLen == 2) { // To ensure no leading zeroes - if (_inputBuffer[ptr-2] == '0') { - reportInvalidNumber("Leading zeroes not allowed"); - } - } - } - - int fractLen = 0; - - // And then see if we get other parts - if (ch == INT_DECIMAL_POINT) { // yes, fraction - fract_loop: - while (true) { - if (ptr >= inputLen) { - break dummy_loop; - } - ch = (int) _inputBuffer[ptr++]; - if (ch < INT_0 || ch > INT_9) { - break fract_loop; - } - ++fractLen; - } - // must be followed by sequence of ints, one minimum - if (fractLen == 0) { - reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit"); - } - } - - int expLen = 0; - if (ch == INT_e || ch == INT_E) { // and/or expontent - if (ptr >= inputLen) { - break dummy_loop; - } - // Sign indicator? - ch = (int) _inputBuffer[ptr++]; - if (ch == INT_MINUS || ch == INT_PLUS) { // yup, skip for now - if (ptr >= inputLen) { - break dummy_loop; - } - ch = (int) _inputBuffer[ptr++]; - } - while (ch <= INT_9 && ch >= INT_0) { - ++expLen; - if (ptr >= inputLen) { - break dummy_loop; - } - ch = (int) _inputBuffer[ptr++]; - } - // must be followed by sequence of ints, one minimum - if (expLen == 0) { - reportUnexpectedNumberChar(ch, "Exponent indicator not followed by a digit"); - } - } - - // Got it all: let's add to text buffer for parsing, access - --ptr; // need to push back following separator - _inputPtr = ptr; - int len = ptr-startPtr; - _textBuffer.resetWithShared(_inputBuffer, startPtr, len); - return reset(negative, intLen, fractLen, expLen); - } while (false); - - _inputPtr = negative ? (startPtr+1) : startPtr; - return parseNumberText2(negative); - } - - /** - * Method called to parse a number, when the primary parse - * method has failed to parse it, due to it being split on - * buffer boundary. As a result code is very similar, except - * that it has to explicitly copy contents to the text buffer - * instead of just sharing the main input buffer. - */ - private final JsonToken parseNumberText2(boolean negative) - throws IOException, JsonParseException - { - char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); - int outPtr = 0; - - // Need to prepend sign? - if (negative) { - outBuf[outPtr++] = '-'; - } - - char c; - int intLen = 0; - boolean eof = false; - - // Ok, first the obligatory integer part: - int_loop: - while (true) { - if (_inputPtr >= _inputEnd && !loadMore()) { - // EOF is legal for main level int values - c = CHAR_NULL; - eof = true; - break int_loop; - } - c = _inputBuffer[_inputPtr++]; - if (c < INT_0 || c > INT_9) { - break int_loop; - } - ++intLen; - // Quickie check: no leading zeroes allowed - if (intLen == 2) { - if (outBuf[outPtr-1] == '0') { - reportInvalidNumber("Leading zeroes not allowed"); - } - } - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - outBuf[outPtr++] = c; - } - // Also, integer part is not optional - if (intLen == 0) { - reportInvalidNumber("Missing integer part (next char "+_getCharDesc(c)+")"); - } - - int fractLen = 0; - // And then see if we get other parts - if (c == '.') { // yes, fraction - outBuf[outPtr++] = c; - - fract_loop: - while (true) { - if (_inputPtr >= _inputEnd && !loadMore()) { - eof = true; - break fract_loop; - } - c = _inputBuffer[_inputPtr++]; - if (c < INT_0 || c > INT_9) { - break fract_loop; - } - ++fractLen; - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - outBuf[outPtr++] = c; - } - // must be followed by sequence of ints, one minimum - if (fractLen == 0) { - reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); - } - } - - int expLen = 0; - if (c == 'e' || c == 'E') { // exponent? - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - outBuf[outPtr++] = c; - // Not optional, can require that we get one more char - c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] - : getNextChar("expected a digit for number exponent"); - // Sign indicator? - if (c == '-' || c == '+') { - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - outBuf[outPtr++] = c; - // Likewise, non optional: - c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] - : getNextChar("expected a digit for number exponent"); - } - - exp_loop: - while (c <= INT_9 && c >= INT_0) { - ++expLen; - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - outBuf[outPtr++] = c; - if (_inputPtr >= _inputEnd && !loadMore()) { - eof = true; - break exp_loop; - } - c = _inputBuffer[_inputPtr++]; - } - // must be followed by sequence of ints, one minimum - if (expLen == 0) { - reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit"); - } - } - - // Ok; unless we hit end-of-input, need to push last char read back - if (!eof) { - --_inputPtr; - } - _textBuffer.setCurrentLength(outPtr); - - // And there we have it! - return reset(negative, intLen, fractLen, expLen); - } - -} diff --git a/src/org/codehaus/jackson/impl/ReaderBasedParser.java b/src/org/codehaus/jackson/impl/ReaderBasedParser.java deleted file mode 100644 index 15d5bbad2d..0000000000 --- a/src/org/codehaus/jackson/impl/ReaderBasedParser.java +++ /dev/null @@ -1,1040 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.*; - -import org.codehaus.jackson.*; -import org.codehaus.jackson.io.IOContext; -import org.codehaus.jackson.sym.CharsToNameCanonicalizer; -import org.codehaus.jackson.util.*; - -/** - * This is a concrete implementation of {@link JsonParser}, which is - * based on a {@link java.io.Reader} to handle low-level character - * conversion tasks. - */ -public final class ReaderBasedParser - extends ReaderBasedNumericParser -{ - /* - /*************************************************** - /* Configuration, state - /*************************************************** - */ - - protected ObjectCodec _objectCodec; - - final protected CharsToNameCanonicalizer _symbols; - - /* - /*************************************************** - /* Life-cycle - /*************************************************** - */ - - public ReaderBasedParser(IOContext ioCtxt, int features, Reader r, - ObjectCodec codec, CharsToNameCanonicalizer st) - { - super(ioCtxt, features, r); - _objectCodec = codec; - _symbols = st; - } - - public ObjectCodec getCodec() { - return _objectCodec; - } - - public void setCodec(ObjectCodec c) { - _objectCodec = c; - } - - /* - /*************************************************** - /* Public API, traversal - /*************************************************** - */ - - /** - * @return Next token from the stream, if any found, or null - * to indicate end-of-input - */ - @Override - public JsonToken nextToken() - throws IOException, JsonParseException - { - /* First: field names are special -- we will always tokenize - * (part of) value along with field name to simplify - * state handling. If so, can and need to use secondary token: - */ - if (_currToken == JsonToken.FIELD_NAME) { - return _nextAfterName(); - } - if (_tokenIncomplete) { - _skipString(); // only strings can be partial - } - - int i = _skipWSOrEnd(); - if (i < 0) { // end-of-input - /* 19-Feb-2009, tatu: Should actually close/release things - * like input source, symbol table and recyclable buffers now. - */ - close(); - return (_currToken = null); - } - - /* First, need to ensure we know the starting location of token - * after skipping leading white space - */ - _tokenInputTotal = _currInputProcessed + _inputPtr - 1; - _tokenInputRow = _currInputRow; - _tokenInputCol = _inputPtr - _currInputRowStart - 1; - - // finally: clear any data retained so far - _binaryValue = null; - - // Closing scope? - if (i == INT_RBRACKET) { - if (!_parsingContext.inArray()) { - _reportMismatchedEndMarker(i, '}'); - } - _parsingContext = _parsingContext.getParent(); - return (_currToken = JsonToken.END_ARRAY); - } - if (i == INT_RCURLY) { - if (!_parsingContext.inObject()) { - _reportMismatchedEndMarker(i, ']'); - } - _parsingContext = _parsingContext.getParent(); - return (_currToken = JsonToken.END_OBJECT); - } - - // Nope: do we then expect a comma? - if (_parsingContext.expectComma()) { - if (i != INT_COMMA) { - _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries"); - } - i = _skipWS(); - } - - /* And should we now have a name? Always true for - * Object contexts, since the intermediate 'expect-value' - * state is never retained. - */ - boolean inObject = _parsingContext.inObject(); - if (inObject) { - // First, field name itself: - String name = _parseFieldName(i); - _parsingContext.setCurrentName(name); - _currToken = JsonToken.FIELD_NAME; - i = _skipWS(); - if (i != INT_COLON) { - _reportUnexpectedChar(i, "was expecting a colon to separate field name and value"); - } - i = _skipWS(); - } - - // Ok: we must have a value... what is it? - - JsonToken t; - - switch (i) { - case INT_QUOTE: - _tokenIncomplete = true; - t = JsonToken.VALUE_STRING; - break; - case INT_LBRACKET: - if (!inObject) { - _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); - } - t = JsonToken.START_ARRAY; - break; - case INT_LCURLY: - if (!inObject) { - _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); - } - t = JsonToken.START_OBJECT; - break; - case INT_RBRACKET: - case INT_RCURLY: - // Error: neither is valid at this point; valid closers have - // been handled earlier - _reportUnexpectedChar(i, "expected a value"); - case INT_t: - _matchToken(JsonToken.VALUE_TRUE); - t = JsonToken.VALUE_TRUE; - break; - case INT_f: - _matchToken(JsonToken.VALUE_FALSE); - t = JsonToken.VALUE_FALSE; - break; - case INT_n: - _matchToken(JsonToken.VALUE_NULL); - t = JsonToken.VALUE_NULL; - break; - - case INT_MINUS: - /* Should we have separate handling for plus? Although - * it is not allowed per se, it may be erroneously used, - * and could be indicate by a more specific error message. - */ - case INT_0: - case INT_1: - case INT_2: - case INT_3: - case INT_4: - case INT_5: - case INT_6: - case INT_7: - case INT_8: - case INT_9: - t = parseNumberText(i); - break; - default: - t = _handleUnexpectedValue(i); - break; - } - - if (inObject) { - _nextToken = t; - return _currToken; - } - _currToken = t; - return t; - } - - private final JsonToken _nextAfterName() - { - _nameCopied = false; // need to invalidate if it was copied - JsonToken t = _nextToken; - _nextToken = null; - // Also: may need to start new context? - if (t == JsonToken.START_ARRAY) { - _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); - } else if (t == JsonToken.START_OBJECT) { - _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); - } - return (_currToken = t); - } - - @Override - public void close() throws IOException - { - super.close(); - _symbols.release(); - } - - /* - /*************************************************** - /* Internal methods, secondary parsing - /*************************************************** - */ - - protected final String _parseFieldName(int i) - throws IOException, JsonParseException - { - if (i != INT_QUOTE) { - return _handleUnusualFieldName(i); - } - /* First: let's try to see if we have a simple name: one that does - * not cross input buffer boundary, and does not contain escape - * sequences. - */ - int ptr = _inputPtr; - int hash = 0; - final int inputLen = _inputEnd; - - if (ptr < inputLen) { - final int[] codes = CharTypes.getInputCodeLatin1(); - final int maxCode = codes.length; - - do { - int ch = _inputBuffer[ptr]; - if (ch < maxCode && codes[ch] != 0) { - if (ch == '"') { - int start = _inputPtr; - _inputPtr = ptr+1; // to skip the quote - return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash); - } - break; - } - hash = (hash * 31) + ch; - ++ptr; - } while (ptr < inputLen); - } - - int start = _inputPtr; - _inputPtr = ptr; - return _parseFieldName2(start, hash, INT_QUOTE); - } - - private String _parseFieldName2(int startPtr, int hash, int endChar) - throws IOException, JsonParseException - { - _textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr)); - - /* Output pointers; calls will also ensure that the buffer is - * not shared and has room for at least one more char. - */ - char[] outBuf = _textBuffer.getCurrentSegment(); - int outPtr = _textBuffer.getCurrentSegmentSize(); - - while (true) { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(": was expecting closing '"+((char) endChar)+"' for name"); - } - } - char c = _inputBuffer[_inputPtr++]; - int i = (int) c; - if (i <= INT_BACKSLASH) { - if (i == INT_BACKSLASH) { - /* Although chars outside of BMP are to be escaped as - * an UTF-16 surrogate pair, does that affect decoding? - * For now let's assume it does not. - */ - c = _decodeEscaped(); - } else if (i <= endChar) { - if (i == endChar) { - break; - } - if (i < INT_SPACE) { - _throwUnquotedSpace(i, "name"); - } - } - } - hash = (hash * 31) + i; - // Ok, let's add char to output: - outBuf[outPtr++] = c; - - // Need more room? - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - } - _textBuffer.setCurrentLength(outPtr); - { - TextBuffer tb = _textBuffer; - char[] buf = tb.getTextBuffer(); - int start = tb.getTextOffset(); - int len = tb.size(); - - return _symbols.findSymbol(buf, start, len, hash); - } - } - - /** - * Method called when we see non-white space character other - * than double quote, when expecting a field name. - * In standard mode will just throw an expection; but - * in non-standard modes may be able to parse name. - * - * @since 1.2 - */ - protected final String _handleUnusualFieldName(int i) - throws IOException, JsonParseException - { - // [JACKSON-173]: allow single quotes - if (i == INT_APOSTROPHE && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) { - return _parseApostropheFieldName(); - } - // [JACKSON-69]: allow unquoted names if feature enabled: - if (!isEnabled(Feature.ALLOW_UNQUOTED_FIELD_NAMES)) { - _reportUnexpectedChar(i, "was expecting double-quote to start field name"); - } - final int[] codes = CharTypes.getInputCodeLatin1JsNames(); - final int maxCode = codes.length; - - // Also: first char must be a valid name char, but NOT be number - boolean firstOk; - - if (i < maxCode) { // identifier, and not a number - firstOk = (codes[i] == 0) && (i < INT_0 || i > INT_9); - } else { - firstOk = Character.isJavaIdentifierPart((char) i); - } - if (!firstOk) { - _reportUnexpectedChar(i, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name"); - } - int ptr = _inputPtr; - int hash = 0; - final int inputLen = _inputEnd; - - if (ptr < inputLen) { - do { - int ch = _inputBuffer[ptr]; - if (ch < maxCode) { - if (codes[ch] != 0) { - int start = _inputPtr-1; // -1 to bring back first char - _inputPtr = ptr; - return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash); - } - } else if (!Character.isJavaIdentifierPart((char) ch)) { - int start = _inputPtr-1; // -1 to bring back first char - _inputPtr = ptr; - return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash); - } - hash = (hash * 31) + ch; - ++ptr; - } while (ptr < inputLen); - } - int start = _inputPtr-1; - _inputPtr = ptr; - return _parseUnusualFieldName2(start, hash, codes); - } - - protected final String _parseApostropheFieldName() - throws IOException, JsonParseException - { - // Note: mostly copy of_parseFieldName - int ptr = _inputPtr; - int hash = 0; - final int inputLen = _inputEnd; - - if (ptr < inputLen) { - final int[] codes = CharTypes.getInputCodeLatin1(); - final int maxCode = codes.length; - - do { - int ch = _inputBuffer[ptr]; - if (ch == '\'') { - int start = _inputPtr; - _inputPtr = ptr+1; // to skip the quote - return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash); - } - if (ch < maxCode && codes[ch] != 0) { - break; - } - hash = (hash * 31) + ch; - ++ptr; - } while (ptr < inputLen); - } - - int start = _inputPtr; - _inputPtr = ptr; - - return _parseFieldName2(start, hash, INT_APOSTROPHE); - } - - /** - * Method for handling cases where first non-space character - * of an expected value token is not legal for standard JSON content. - * - * @since 1.3 - */ - protected final JsonToken _handleUnexpectedValue(int i) - throws IOException, JsonParseException - { - // Most likely an error, unless we are to allow single-quote-strings - if (i != INT_APOSTROPHE || !isEnabled(Feature.ALLOW_SINGLE_QUOTES)) { - _reportUnexpectedChar(i, "expected a valid value (number, String, array, object, 'true', 'false' or 'null')"); - } - - /* [JACKSON-173]: allow single quotes. Unlike with regular - * Strings, we'll eagerly parse contents; this so that there's - * no need to store information on quote char used. - * - * Also, no separation to fast/slow parsing; we'll just do - * one regular (~= slow) parsing, to keep code simple - */ - char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); - int outPtr = _textBuffer.getCurrentSegmentSize(); - - while (true) { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(": was expecting closing quote for a string value"); - } - } - char c = _inputBuffer[_inputPtr++]; - i = (int) c; - if (i <= INT_BACKSLASH) { - if (i == INT_BACKSLASH) { - /* Although chars outside of BMP are to be escaped as - * an UTF-16 surrogate pair, does that affect decoding? - * For now let's assume it does not. - */ - c = _decodeEscaped(); - } else if (i <= INT_APOSTROPHE) { - if (i == INT_APOSTROPHE) { - break; - } - if (i < INT_SPACE) { - _throwUnquotedSpace(i, "string value"); - } - } - } - // Need more room? - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - // Ok, let's add char to output: - outBuf[outPtr++] = c; - } - _textBuffer.setCurrentLength(outPtr); - return JsonToken.VALUE_STRING; - } - - /** - * @since 1.2 - */ - private String _parseUnusualFieldName2(int startPtr, int hash, int[] codes) - throws IOException, JsonParseException - { - _textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr)); - char[] outBuf = _textBuffer.getCurrentSegment(); - int outPtr = _textBuffer.getCurrentSegmentSize(); - final int maxCode = codes.length; - - while (true) { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { // acceptable for now (will error out later) - break; - } - } - char c = _inputBuffer[_inputPtr]; - int i = (int) c; - if (i <= maxCode) { - if (codes[i] != 0) { - break; - } - } else if (!Character.isJavaIdentifierPart(c)) { - break; - } - ++_inputPtr; - hash = (hash * 31) + i; - // Ok, let's add char to output: - outBuf[outPtr++] = c; - - // Need more room? - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - } - _textBuffer.setCurrentLength(outPtr); - { - TextBuffer tb = _textBuffer; - char[] buf = tb.getTextBuffer(); - int start = tb.getTextOffset(); - int len = tb.size(); - - return _symbols.findSymbol(buf, start, len, hash); - } - } - - @Override - protected void _finishString() - throws IOException, JsonParseException - { - /* First: let's try to see if we have simple String value: one - * that does not cross input buffer boundary, and does not - * contain escape sequences. - */ - int ptr = _inputPtr; - final int inputLen = _inputEnd; - - if (ptr < inputLen) { - final int[] codes = CharTypes.getInputCodeLatin1(); - final int maxCode = codes.length; - - do { - int ch = _inputBuffer[ptr]; - if (ch < maxCode && codes[ch] != 0) { - if (ch == '"') { - _textBuffer.resetWithShared(_inputBuffer, _inputPtr, (ptr-_inputPtr)); - _inputPtr = ptr+1; - // Yes, we got it all - return; - } - break; - } - ++ptr; - } while (ptr < inputLen); - } - - /* Either ran out of input, or bumped into an escape - * sequence... - */ - _textBuffer.resetWithCopy(_inputBuffer, _inputPtr, (ptr-_inputPtr)); - _inputPtr = ptr; - _finishString2(); - } - - protected void _finishString2() - throws IOException, JsonParseException - { - char[] outBuf = _textBuffer.getCurrentSegment(); - int outPtr = _textBuffer.getCurrentSegmentSize(); - - while (true) { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(": was expecting closing quote for a string value"); - } - } - char c = _inputBuffer[_inputPtr++]; - int i = (int) c; - if (i <= INT_BACKSLASH) { - if (i == INT_BACKSLASH) { - /* Although chars outside of BMP are to be escaped as - * an UTF-16 surrogate pair, does that affect decoding? - * For now let's assume it does not. - */ - c = _decodeEscaped(); - } else if (i <= INT_QUOTE) { - if (i == INT_QUOTE) { - break; - } - if (i < INT_SPACE) { - _throwUnquotedSpace(i, "string value"); - } - } - } - // Need more room? - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - // Ok, let's add char to output: - outBuf[outPtr++] = c; - } - _textBuffer.setCurrentLength(outPtr); - } - - /** - * Method called to skim through rest of unparsed String value, - * if it is not needed. This can be done bit faster if contents - * need not be stored for future access. - */ - protected void _skipString() - throws IOException, JsonParseException - { - _tokenIncomplete = false; - - int inputPtr = _inputPtr; - int inputLen = _inputEnd; - char[] inputBuffer = _inputBuffer; - - while (true) { - if (inputPtr >= inputLen) { - _inputPtr = inputPtr; - if (!loadMore()) { - _reportInvalidEOF(": was expecting closing quote for a string value"); - } - inputPtr = _inputPtr; - inputLen = _inputEnd; - } - char c = inputBuffer[inputPtr++]; - int i = (int) c; - if (i <= INT_BACKSLASH) { - if (i == INT_BACKSLASH) { - /* Although chars outside of BMP are to be escaped as - * an UTF-16 surrogate pair, does that affect decoding? - * For now let's assume it does not. - */ - _inputPtr = inputPtr; - c = _decodeEscaped(); - inputPtr = _inputPtr; - inputLen = _inputEnd; - } else if (i <= INT_QUOTE) { - if (i == INT_QUOTE) { - _inputPtr = inputPtr; - break; - } - if (i < INT_SPACE) { - _inputPtr = inputPtr; - _throwUnquotedSpace(i, "string value"); - } - } - } - } - } - - /** - * Method called to much one of literal tokens we may expect - */ - protected void _matchToken(JsonToken token) - throws IOException, JsonParseException - { - // First char is already matched, need to check the rest - String matchStr = token.asString(); - int i = 1; - - for (int len = matchStr.length(); i < len; ++i) { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(" in a value"); - } - } - char c = _inputBuffer[_inputPtr]; - if (c != matchStr.charAt(i)) { - _reportInvalidToken(matchStr.substring(0, i)); - } - ++_inputPtr; - } - /* Ok, fine; let's not bother checking anything beyond keyword. - * If there's something wrong there, it'll cause a parsing - * error later on. - */ - return; - } - - private void _reportInvalidToken(String matchedPart) - throws IOException, JsonParseException - { - StringBuilder sb = new StringBuilder(matchedPart); - /* Let's just try to find what appears to be the token, using - * regular Java identifier character rules. It's just a heuristic, - * nothing fancy here. - */ - while (true) { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - break; - } - } - char c = _inputBuffer[_inputPtr]; - if (!Character.isJavaIdentifierPart(c)) { - break; - } - ++_inputPtr; - sb.append(c); - } - - _reportError("Unrecognized token '"+sb.toString()+"': was expecting 'null', 'true' or 'false'"); - } - - /* - /*************************************************** - /* Internal methods, other parsing - /*************************************************** - */ - - /** - * We actually need to check the character value here - * (to see if we have \n following \r). - */ - protected final void _skipCR() throws IOException - { - if (_inputPtr < _inputEnd || loadMore()) { - if (_inputBuffer[_inputPtr] == '\n') { - ++_inputPtr; - } - } - ++_currInputRow; - _currInputRowStart = _inputPtr; - } - - protected final void _skipLF() throws IOException - { - ++_currInputRow; - _currInputRowStart = _inputPtr; - } - - private final int _skipWS() - throws IOException, JsonParseException - { - while (_inputPtr < _inputEnd || loadMore()) { - int i = (int) _inputBuffer[_inputPtr++]; - if (i > INT_SPACE) { - if (i != INT_SLASH) { - return i; - } - _skipComment(); - } else if (i != INT_SPACE) { - if (i == INT_LF) { - _skipLF(); - } else if (i == INT_CR) { - _skipCR(); - } else if (i != INT_TAB) { - _throwInvalidSpace(i); - } - } - } - throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries"); - } - - private final int _skipWSOrEnd() - throws IOException, JsonParseException - { - while ((_inputPtr < _inputEnd) || loadMore()) { - int i = (int) _inputBuffer[_inputPtr++]; - if (i > INT_SPACE) { - if (i != INT_SLASH) { - return i; - } - _skipComment(); - } else if (i != INT_SPACE) { - if (i == INT_LF) { - _skipLF(); - } else if (i == INT_CR) { - _skipCR(); - } else if (i != INT_TAB) { - _throwInvalidSpace(i); - } - } - } - // We ran out of input... - _handleEOF(); - return -1; - } - - private final void _skipComment() - throws IOException, JsonParseException - { - if (!isEnabled(Feature.ALLOW_COMMENTS)) { - _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)"); - } - // First: check which comment (if either) it is: - if (_inputPtr >= _inputEnd && !loadMore()) { - _reportInvalidEOF(" in a comment"); - } - char c = _inputBuffer[_inputPtr++]; - if (c == '/') { - _skipCppComment(); - } else if (c == '*') { - _skipCComment(); - } else { - _reportUnexpectedChar(c, "was expecting either '*' or '/' for a comment"); - } - } - - private final void _skipCComment() - throws IOException, JsonParseException - { - // Ok: need the matching '*/' - main_loop: - while ((_inputPtr < _inputEnd) || loadMore()) { - int i = (int) _inputBuffer[_inputPtr++]; - if (i <= INT_ASTERISK) { - if (i == INT_ASTERISK) { // end? - if ((_inputPtr >= _inputEnd) && !loadMore()) { - break main_loop; - } - if (_inputBuffer[_inputPtr] == INT_SLASH) { - ++_inputPtr; - return; - } - continue; - } - if (i < INT_SPACE) { - if (i == INT_LF) { - _skipLF(); - } else if (i == INT_CR) { - _skipCR(); - } else if (i != INT_TAB) { - _throwInvalidSpace(i); - } - } - } - } - _reportInvalidEOF(" in a comment"); - } - - private final void _skipCppComment() - throws IOException, JsonParseException - { - // Ok: need to find EOF or linefeed - while ((_inputPtr < _inputEnd) || loadMore()) { - int i = (int) _inputBuffer[_inputPtr++]; - if (i < INT_SPACE) { - if (i == INT_LF) { - _skipLF(); - break; - } else if (i == INT_CR) { - _skipCR(); - break; - } else if (i != INT_TAB) { - _throwInvalidSpace(i); - } - } - } - } - - protected final char _decodeEscaped() - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(" in character escape sequence"); - } - } - char c = _inputBuffer[_inputPtr++]; - - switch ((int) c) { - // First, ones that are mapped - case INT_b: - return '\b'; - case INT_t: - return '\t'; - case INT_n: - return '\n'; - case INT_f: - return '\f'; - case INT_r: - return '\r'; - - // And these are to be returned as they are - case INT_QUOTE: - case INT_SLASH: - case INT_BACKSLASH: - return c; - - case INT_u: // and finally hex-escaped - break; - - default: - _reportError("Unrecognized character escape "+_getCharDesc(c)); - } - - // Ok, a hex escape. Need 4 characters - int value = 0; - for (int i = 0; i < 4; ++i) { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(" in character escape sequence"); - } - } - int ch = (int) _inputBuffer[_inputPtr++]; - int digit = CharTypes.charToHex(ch); - if (digit < 0) { - _reportUnexpectedChar(ch, "expected a hex-digit for character escape sequence"); - } - value = (value << 4) | digit; - } - return (char) value; - } - - /* - /*************************************************** - /* Binary access - /*************************************************** - */ - - @Override - protected byte[] _decodeBase64(Base64Variant b64variant) - throws IOException, JsonParseException - { - ByteArrayBuilder builder = _getByteArrayBuilder(); - - /* !!! 23-Jan-2009, tatu: There are some potential problems - * with this: - * - * - Escaped chars are not handled. Should they? - */ - - //main_loop: - while (true) { - // first, we'll skip preceding white space, if any - char ch; - do { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - ch = _inputBuffer[_inputPtr++]; - } while (ch <= INT_SPACE); - int bits = b64variant.decodeBase64Char(ch); - if (bits < 0) { // reached the end, fair and square? - if (ch == '"') { - return builder.toByteArray(); - } - throw reportInvalidChar(b64variant, ch, 0); - } - int decodedData = bits; - - // then second base64 char; can't get padding yet, nor ws - - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - ch = _inputBuffer[_inputPtr++]; - bits = b64variant.decodeBase64Char(ch); - if (bits < 0) { - throw reportInvalidChar(b64variant, ch, 1); - } - decodedData = (decodedData << 6) | bits; - - // third base64 char; can be padding, but not ws - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - ch = _inputBuffer[_inputPtr++]; - bits = b64variant.decodeBase64Char(ch); - - // First branch: can get padding (-> 1 byte) - if (bits < 0) { - if (bits != Base64Variant.BASE64_VALUE_PADDING) { - throw reportInvalidChar(b64variant, ch, 2); - } - // Ok, must get padding - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - ch = _inputBuffer[_inputPtr++]; - if (!b64variant.usesPaddingChar(ch)) { - throw reportInvalidChar(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'"); - } - // Got 12 bits, only need 8, need to shift - decodedData >>= 4; - builder.append(decodedData); - continue; - } - // Nope, 2 or 3 bytes - decodedData = (decodedData << 6) | bits; - // fourth and last base64 char; can be padding, but not ws - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - ch = _inputBuffer[_inputPtr++]; - bits = b64variant.decodeBase64Char(ch); - if (bits < 0) { - if (bits != Base64Variant.BASE64_VALUE_PADDING) { - throw reportInvalidChar(b64variant, ch, 3); - } - /* With padding we only get 2 bytes; but we have - * to shift it a bit so it is identical to triplet - * case with partial output. - * 3 chars gives 3x6 == 18 bits, of which 2 are - * dummies, need to discard: - */ - decodedData >>= 2; - builder.appendTwoBytes(decodedData); - } else { - // otherwise, our triple is now complete - decodedData = (decodedData << 6) | bits; - builder.appendThreeBytes(decodedData); - } - } - } - - protected IllegalArgumentException reportInvalidChar(Base64Variant b64variant, char ch, int bindex) - throws IllegalArgumentException - { - return reportInvalidChar(b64variant, ch, bindex, null); - } - - /** - * @param bindex Relative index within base64 character unit; between 0 - * and 3 (as unit has exactly 4 characters) - */ - protected IllegalArgumentException reportInvalidChar(Base64Variant b64variant, char ch, int bindex, String msg) - throws IllegalArgumentException - { - String base; - if (ch <= INT_SPACE) { - base = "Illegal white space character (code 0x"+Integer.toHexString(ch)+") as character #"+(bindex+1)+" of 4-char base64 unit: can only used between units"; - } else if (b64variant.usesPaddingChar(ch)) { - base = "Unexpected padding character ('"+b64variant.getPaddingChar()+"') as character #"+(bindex+1)+" of 4-char base64 unit: padding only legal as 3rd or 4th character"; - } else if (!Character.isDefined(ch) || Character.isISOControl(ch)) { - // Not sure if we can really get here... ? (most illegal xml chars are caught at lower level) - base = "Illegal character (code 0x"+Integer.toHexString(ch)+") in base64 content"; - } else { - base = "Illegal character '"+ch+"' (code 0x"+Integer.toHexString(ch)+") in base64 content"; - } - if (msg != null) { - base = base + ": " + msg; - } - return new IllegalArgumentException(base); - } -} diff --git a/src/org/codehaus/jackson/impl/ReaderBasedParserBase.java b/src/org/codehaus/jackson/impl/ReaderBasedParserBase.java deleted file mode 100644 index a0edd80df2..0000000000 --- a/src/org/codehaus/jackson/impl/ReaderBasedParserBase.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.*; - -import org.codehaus.jackson.*; -import org.codehaus.jackson.io.IOContext; - -/** - * This is a simple low-level input reader base class, used by - * JSON parser. - * The reason for sub-classing (over composition) - * is due to need for direct access to character buffers - * and positions. - * - * @author Tatu Saloranta - */ -public abstract class ReaderBasedParserBase - extends JsonNumericParserBase -{ - /* - //////////////////////////////////////////////////// - // Configuration - //////////////////////////////////////////////////// - */ - - /** - * Reader that can be used for reading more content, if one - * buffer from input source, but in some cases pre-loaded buffer - * is handed to the parser. - */ - protected Reader _reader; - - /* - //////////////////////////////////////////////////// - // Current input data - //////////////////////////////////////////////////// - */ - - /** - * Current buffer from which data is read; generally data is read into - * buffer from input source. - */ - protected char[] _inputBuffer; - - /* - //////////////////////////////////////////////////// - // Life-cycle - //////////////////////////////////////////////////// - */ - - protected ReaderBasedParserBase(IOContext ctxt, int features, Reader r) - { - super(ctxt, features); - _reader = r; - _inputBuffer = ctxt.allocTokenBuffer(); - } - - /* - //////////////////////////////////////////////////// - // Low-level reading, other - //////////////////////////////////////////////////// - */ - - @Override - protected final boolean loadMore() - throws IOException - { - _currInputProcessed += _inputEnd; - _currInputRowStart -= _inputEnd; - - if (_reader != null) { - int count = _reader.read(_inputBuffer, 0, _inputBuffer.length); - if (count > 0) { - _inputPtr = 0; - _inputEnd = count; - return true; - } - // End of input - _closeInput(); - // Should never return 0, so let's fail - if (count == 0) { - throw new IOException("Reader returned 0 characters when trying to read "+_inputEnd); - } - } - return false; - } - - protected char getNextChar(String eofMsg) - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(eofMsg); - } - } - return _inputBuffer[_inputPtr++]; - } - - @Override - protected void _closeInput() throws IOException - { - /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() - * on the underlying Reader, unless we "own" it, or auto-closing - * feature is enabled. - * One downside is that when using our optimized - * Reader (granted, we only do that for UTF-32...) this - * means that buffer recycling won't work correctly. - */ - if (_reader != null) { - if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) { - _reader.close(); - } - _reader = null; - } - } - - /** - * Method called to release internal buffers owned by the base - * reader. This may be called along with {@link #_closeInput} (for - * example, when explicitly closing this reader instance), or - * separately (if need be). - */ - @Override - protected void _releaseBuffers() - throws IOException - { - super._releaseBuffers(); - char[] buf = _inputBuffer; - if (buf != null) { - _inputBuffer = null; - _ioContext.releaseTokenBuffer(buf); - } - } -} diff --git a/src/org/codehaus/jackson/impl/StreamBasedParserBase.java b/src/org/codehaus/jackson/impl/StreamBasedParserBase.java deleted file mode 100644 index a7ac7e539d..0000000000 --- a/src/org/codehaus/jackson/impl/StreamBasedParserBase.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.*; - -import org.codehaus.jackson.io.IOContext; - -/** - * This is a simple low-level input reader base class, used by - * JSON parser. It is used when underlying input source is - * a byte stream such as {@link InputStream}. - * The reason for sub-classing (over composition) - * is due to need for direct access to low-level byte buffers - * and positions. - * - * @author Tatu Saloranta - */ -public abstract class StreamBasedParserBase - extends JsonNumericParserBase -{ - /* - //////////////////////////////////////////////////// - // Configuration - //////////////////////////////////////////////////// - */ - - /** - * Input stream that can be used for reading more content, if one - * in use. May be null, if input comes just as a full buffer, - * or if the stream has been closed. - */ - protected InputStream _inputStream; - - /* - //////////////////////////////////////////////////// - // Current input data - //////////////////////////////////////////////////// - */ - - /** - * Current buffer from which data is read; generally data is read into - * buffer from input source, but in some cases pre-loaded buffer - * is handed to the parser. - */ - protected byte[] _inputBuffer; - - /** - * Flag that indicates whether the input buffer is recycable (and - * needs to be returned to recycler once we are done) or not. - */ - protected boolean _bufferRecyclable; - - /* - //////////////////////////////////////////////////// - // Life-cycle - //////////////////////////////////////////////////// - */ - - protected StreamBasedParserBase(IOContext ctxt, int features, - InputStream in, - byte[] inputBuffer, int start, int end, - boolean bufferRecyclable) - { - super(ctxt, features); - _inputStream = in; - _inputBuffer = inputBuffer; - _inputPtr = start; - _inputEnd = end; - _bufferRecyclable = bufferRecyclable; - } - - /* - //////////////////////////////////////////////////// - // Low-level reading, other - //////////////////////////////////////////////////// - */ - - @Override - protected final boolean loadMore() - throws IOException - { - _currInputProcessed += _inputEnd; - _currInputRowStart -= _inputEnd; - - if (_inputStream != null) { - int count = _inputStream.read(_inputBuffer, 0, _inputBuffer.length); - if (count > 0) { - _inputPtr = 0; - _inputEnd = count; - return true; - } - // End of input - _closeInput(); - // Should never return 0, so let's fail - if (count == 0) { - throw new IOException("Reader returned 0 characters when trying to read "+_inputEnd); - } - } - return false; - } - - @Override - protected void _closeInput() throws IOException - { - /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() - * on the underlying Reader, unless we "own" it, or auto-closing - * feature is enabled. - */ - if (_inputStream != null) { - if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) { - _inputStream.close(); - } - _inputStream = null; - } - } - - /** - * Method called to release internal buffers owned by the base - * reader. This may be called along with {@link #_closeInput} (for - * example, when explicitly closing this reader instance), or - * separately (if need be). - */ - @Override - protected void _releaseBuffers() throws IOException - { - super._releaseBuffers(); - if (_bufferRecyclable) { - byte[] buf = _inputBuffer; - if (buf != null) { - _inputBuffer = null; - _ioContext.releaseReadIOBuffer(buf); - } - } - } -} diff --git a/src/org/codehaus/jackson/impl/Utf8NumericParser.java b/src/org/codehaus/jackson/impl/Utf8NumericParser.java deleted file mode 100644 index bd710d2264..0000000000 --- a/src/org/codehaus/jackson/impl/Utf8NumericParser.java +++ /dev/null @@ -1,190 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.*; - -import org.codehaus.jackson.io.IOContext; -import org.codehaus.jackson.JsonParseException; -import org.codehaus.jackson.JsonToken; - -/** - * Intermediate class that implements handling of numeric parsing, - * when using UTF-8 encoded byte-based input source. - * Separate from the actual parser class just to isolate numeric - * parsing: would be nice to use aggregation, but unfortunately - * many parts are hard to implement without direct access to - * underlying buffers. - */ -public abstract class Utf8NumericParser - extends StreamBasedParserBase -{ - /* - //////////////////////////////////////////////////// - // Life-cycle - //////////////////////////////////////////////////// - */ - - public Utf8NumericParser(IOContext pc, int features, - InputStream in, - byte[] inputBuffer, int start, int end, - boolean bufferRecyclable) - { - super(pc, features, in, inputBuffer, start, end, bufferRecyclable); - } - - /* - //////////////////////////////////////////////////// - // Textual parsing of number values - //////////////////////////////////////////////////// - */ - - /** - * Initial parsing method for number values. It needs to be able - * to parse enough input to be able to determine whether the - * value is to be considered a simple integer value, or a more - * generic decimal value: latter of which needs to be expressed - * as a floating point number. The basic rule is that if the number - * has no fractional or exponential part, it is an integer; otherwise - * a floating point number. - *

- * Because much of input has to be processed in any case, no partial - * parsing is done: all input text will be stored for further - * processing. However, actual numeric value conversion will be - * deferred, since it is usually the most complicated and costliest - * part of processing. - */ - @Override - protected final JsonToken parseNumberText(int c) - throws IOException, JsonParseException - { - char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); - int outPtr = 0; - boolean negative = (c == INT_MINUS); - - // Need to prepend sign? - if (negative) { - outBuf[outPtr++] = '-'; - // Must have something after sign too - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - c = (int) _inputBuffer[_inputPtr++] & 0xFF; - } - - int intLen = 0; - boolean eof = false; - - // Ok, first the obligatory integer part: - int_loop: - while (true) { - if (c < INT_0 || c > INT_9) { - break int_loop; - } - ++intLen; - // Quickie check: no leading zeroes allowed - if (intLen == 2) { - if (outBuf[outPtr-1] == '0') { - reportInvalidNumber("Leading zeroes not allowed"); - } - } - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - outBuf[outPtr++] = (char) c; - if (_inputPtr >= _inputEnd && !loadMore()) { - // EOF is legal for main level int values - c = CHAR_NULL; - eof = true; - break int_loop; - } - c = (int) _inputBuffer[_inputPtr++] & 0xFF; - } - // Also, integer part is not optional - if (intLen == 0) { - reportInvalidNumber("Missing integer part (next char "+_getCharDesc(c)+")"); - } - - int fractLen = 0; - // And then see if we get other parts - if (c == '.') { // yes, fraction - outBuf[outPtr++] = (char) c; - - fract_loop: - while (true) { - if (_inputPtr >= _inputEnd && !loadMore()) { - eof = true; - break fract_loop; - } - c = (int) _inputBuffer[_inputPtr++] & 0xFF; - if (c < INT_0 || c > INT_9) { - break fract_loop; - } - ++fractLen; - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - outBuf[outPtr++] = (char) c; - } - // must be followed by sequence of ints, one minimum - if (fractLen == 0) { - reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); - } - } - - int expLen = 0; - if (c == 'e' || c == 'E') { // exponent? - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - outBuf[outPtr++] = (char) c; - // Not optional, can require that we get one more char - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - c = (int) _inputBuffer[_inputPtr++] & 0xFF; - // Sign indicator? - if (c == '-' || c == '+') { - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - outBuf[outPtr++] = (char) c; - // Likewise, non optional: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - c = (int) _inputBuffer[_inputPtr++] & 0xFF; - } - - exp_loop: - while (c <= INT_9 && c >= INT_0) { - ++expLen; - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - outBuf[outPtr++] = (char) c; - if (_inputPtr >= _inputEnd && !loadMore()) { - eof = true; - break exp_loop; - } - c = (int) _inputBuffer[_inputPtr++] & 0xFF; - } - // must be followed by sequence of ints, one minimum - if (expLen == 0) { - reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit"); - } - } - - // Ok; unless we hit end-of-input, need to push last char read back - if (!eof) { - --_inputPtr; - } - _textBuffer.setCurrentLength(outPtr); - - // And there we have it! - return reset(negative, intLen, fractLen, expLen); - } -} diff --git a/src/org/codehaus/jackson/impl/Utf8StreamParser.java b/src/org/codehaus/jackson/impl/Utf8StreamParser.java deleted file mode 100644 index ca74188c55..0000000000 --- a/src/org/codehaus/jackson/impl/Utf8StreamParser.java +++ /dev/null @@ -1,1826 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.*; - -import org.codehaus.jackson.*; -import org.codehaus.jackson.io.IOContext; -import org.codehaus.jackson.sym.*; -import org.codehaus.jackson.util.*; - -/** - * This is a concrete implementation of {@link JsonParser}, which is - * based on a {@link java.io.InputStream} as the input source. - */ -public final class Utf8StreamParser - extends Utf8NumericParser -{ - final static byte BYTE_LF = (byte) '\n'; - - /* - /*************************************************** - /* Configuration, state - /*************************************************** - */ - - /** - * Codec used for data binding when (if) requested. - */ - protected ObjectCodec _objectCodec; - - /** - * Symbol table that contains field names encountered so far - */ - final protected BytesToNameCanonicalizer _symbols; - - /** - * Temporary buffer used for name parsing. - */ - protected int[] _quadBuffer = new int[32]; - - /* - /*************************************************** - /* Life-cycle - /*************************************************** - */ - - public Utf8StreamParser(IOContext ctxt, int features, InputStream in, - ObjectCodec codec, - BytesToNameCanonicalizer sym, - byte[] inputBuffer, int start, int end, - boolean bufferRecyclable) - { - super(ctxt, features, in, inputBuffer, start, end, bufferRecyclable); - _objectCodec = codec; - _symbols = sym; - // 12-Mar-2010, tatus: Sanity check, related to [JACKSON-259]: - if (!JsonParser.Feature.CANONICALIZE_FIELD_NAMES.enabledIn(features)) { - // should never construct non-canonical utf8/byte parser (instead, use Reader) - _throwInternal(); - } - } - - public ObjectCodec getCodec() { - return _objectCodec; - } - - public void setCodec(ObjectCodec c) { - _objectCodec = c; - } - - /* - /*************************************************** - /* Public API, traversal - /*************************************************** - */ - - /** - * @return Next token from the stream, if any found, or null - * to indicate end-of-input - */ - @Override - public JsonToken nextToken() - throws IOException, JsonParseException - { - /* First: field names are special -- we will always tokenize - * (part of) value along with field name to simplify - * state handling. If so, can and need to use secondary token: - */ - if (_currToken == JsonToken.FIELD_NAME) { - return _nextAfterName(); - } - if (_tokenIncomplete) { - _skipString(); // only strings can be partial - } - - int i = _skipWSOrEnd(); - if (i < 0) { // end-of-input - /* 19-Feb-2009, tatu: Should actually close/release things - * like input source, symbol table and recyclable buffers now. - */ - close(); - return (_currToken = null); - } - - /* First, need to ensure we know the starting location of token - * after skipping leading white space - */ - _tokenInputTotal = _currInputProcessed + _inputPtr - 1; - _tokenInputRow = _currInputRow; - _tokenInputCol = _inputPtr - _currInputRowStart - 1; - - // finally: clear any data retained so far - _binaryValue = null; - - // Closing scope? - if (i == INT_RBRACKET) { - if (!_parsingContext.inArray()) { - _reportMismatchedEndMarker(i, '}'); - } - _parsingContext = _parsingContext.getParent(); - return (_currToken = JsonToken.END_ARRAY); - } - if (i == INT_RCURLY) { - if (!_parsingContext.inObject()) { - _reportMismatchedEndMarker(i, ']'); - } - _parsingContext = _parsingContext.getParent(); - return (_currToken = JsonToken.END_OBJECT); - } - - // Nope: do we then expect a comma? - if (_parsingContext.expectComma()) { - if (i != INT_COMMA) { - _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries"); - } - i = _skipWS(); - } - - /* And should we now have a name? Always true for - * Object contexts, since the intermediate 'expect-value' - * state is never retained. - */ - boolean inObject = _parsingContext.inObject(); - if (inObject) { - // First, field name itself: - Name n = _parseFieldName(i); - _parsingContext.setCurrentName(n.getName()); - _currToken = JsonToken.FIELD_NAME; - i = _skipWS(); - if (i != INT_COLON) { - _reportUnexpectedChar(i, "was expecting a colon to separate field name and value"); - } - i = _skipWS(); - } - - // Ok: we must have a value... what is it? - - JsonToken t; - - switch (i) { - case INT_QUOTE: - _tokenIncomplete = true; - t = JsonToken.VALUE_STRING; - break; - case INT_LBRACKET: - if (!inObject) { - _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); - } - t = JsonToken.START_ARRAY; - break; - case INT_LCURLY: - if (!inObject) { - _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); - } - t = JsonToken.START_OBJECT; - break; - case INT_RBRACKET: - case INT_RCURLY: - // Error: neither is valid at this point; valid closers have - // been handled earlier - _reportUnexpectedChar(i, "expected a value"); - case INT_t: - _matchToken(JsonToken.VALUE_TRUE); - t = JsonToken.VALUE_TRUE; - break; - case INT_f: - _matchToken(JsonToken.VALUE_FALSE); - t = JsonToken.VALUE_FALSE; - break; - case INT_n: - _matchToken(JsonToken.VALUE_NULL); - t = JsonToken.VALUE_NULL; - break; - - case INT_MINUS: - /* Should we have separate handling for plus? Although - * it is not allowed per se, it may be erroneously used, - * and could be indicate by a more specific error message. - */ - case INT_0: - case INT_1: - case INT_2: - case INT_3: - case INT_4: - case INT_5: - case INT_6: - case INT_7: - case INT_8: - case INT_9: - t = parseNumberText(i); - break; - default: - t = _handleUnexpectedValue(i); - } - - if (inObject) { - _nextToken = t; - return _currToken; - } - _currToken = t; - return t; - } - - private final JsonToken _nextAfterName() - { - _nameCopied = false; // need to invalidate if it was copied - JsonToken t = _nextToken; - _nextToken = null; - // Also: may need to start new context? - if (t == JsonToken.START_ARRAY) { - _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); - } else if (t == JsonToken.START_OBJECT) { - _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); - } - return (_currToken = t); - } - - @Override - public void close() throws IOException - { - super.close(); - // Merge found symbols, if any: - _symbols.release(); - } - - /* - /*************************************************** - /* Internal methods, secondary parsing - /*************************************************** - */ - - protected final Name _parseFieldName(int i) - throws IOException, JsonParseException - { - if (i != INT_QUOTE) { - return _handleUnusualFieldName(i); - } - // First: can we optimize out bounds checks? - if ((_inputEnd - _inputPtr) < 9) { // Need 8 chars, plus one trailing (quote) - return slowParseFieldName(); - } - - // If so, can also unroll loops nicely - /* 25-Nov-2008, tatu: This may seem weird, but here we do - * NOT want to worry about UTF-8 decoding. Rather, we'll - * assume that part is ok (if not it will get caught - * later on), and just handle quotes and backslashes here. - */ - final int[] codes = CharTypes.getInputCodeLatin1(); - - int q = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[q] != 0) { - if (q == INT_QUOTE) { // special case, "" - return BytesToNameCanonicalizer.getEmptyName(); - } - return parseFieldName(0, q, 0); // quoting or invalid char - } - - i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { // one byte/char case or broken - return findName(q, 1); - } - return parseFieldName(q, i, 1); - } - q = (q << 8) | i; - i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { // two byte name or broken - return findName(q, 2); - } - return parseFieldName(q, i, 2); - } - q = (q << 8) | i; - i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { // three byte name or broken - return findName(q, 3); - } - return parseFieldName(q, i, 3); - } - q = (q << 8) | i; - i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { // four byte name or broken - return findName(q, 4); - } - return parseFieldName(q, i, 4); - } - return parseMediumFieldName(q, i); - } - - protected Name parseMediumFieldName(int q1, int q2) - throws IOException, JsonParseException - { - // As mentioned earlier, we do ignore UTF-8 aspects at this point - final int[] codes = CharTypes.getInputCodeLatin1(); - - // Ok, got 5 name bytes so far - int i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { // 5 bytes - return findName(q1, q2, 1); - } - return parseFieldName(q1, q2, i, 1); // quoting or invalid char - } - q2 = (q2 << 8) | i; - i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { // 6 bytes - return findName(q1, q2, 2); - } - return parseFieldName(q1, q2, i, 2); - } - q2 = (q2 << 8) | i; - i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { // 7 bytes - return findName(q1, q2, 3); - } - return parseFieldName(q1, q2, i, 3); - } - q2 = (q2 << 8) | i; - i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { // 8 bytes - return findName(q1, q2, 4); - } - return parseFieldName(q1, q2, i, 4); - } - _quadBuffer[0] = q1; - _quadBuffer[1] = q2; - return parseLongFieldName(i); - } - - protected Name parseLongFieldName(int q) - throws IOException, JsonParseException - { - // As explained above, will ignore utf-8 encoding at this point - final int[] codes = CharTypes.getInputCodeLatin1(); - int qlen = 2; - - while (true) { - /* Let's offline if we hit buffer boundary (otherwise would - * need to [try to] align input, which is bit complicated - * and may not always be possible) - */ - if ((_inputEnd - _inputPtr) < 4) { - return parseEscapedFieldName(_quadBuffer, qlen, 0, q, 0); - } - // Otherwise can skip boundary checks for 4 bytes in loop - - int i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { - return findName(_quadBuffer, qlen, q, 1); - } - return parseEscapedFieldName(_quadBuffer, qlen, q, i, 1); - } - - q = (q << 8) | i; - i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { - return findName(_quadBuffer, qlen, q, 2); - } - return parseEscapedFieldName(_quadBuffer, qlen, q, i, 2); - } - - q = (q << 8) | i; - i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { - return findName(_quadBuffer, qlen, q, 3); - } - return parseEscapedFieldName(_quadBuffer, qlen, q, i, 3); - } - - q = (q << 8) | i; - i = _inputBuffer[_inputPtr++] & 0xFF; - if (codes[i] != 0) { - if (i == INT_QUOTE) { - return findName(_quadBuffer, qlen, q, 4); - } - return parseEscapedFieldName(_quadBuffer, qlen, q, i, 4); - } - - // Nope, no end in sight. Need to grow quad array etc - if (qlen >= _quadBuffer.length) { - _quadBuffer = growArrayBy(_quadBuffer, qlen); - } - _quadBuffer[qlen++] = q; - q = i; - } - } - - /** - * Method called when not even first 8 bytes are guaranteed - * to come consequtively. Happens rarely, so this is offlined; - * plus we'll also do full checks for escaping etc. - */ - protected Name slowParseFieldName() - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(": was expecting closing '\"' for name"); - } - } - int i = _inputBuffer[_inputPtr++] & 0xFF; - if (i == INT_QUOTE) { // special case, "" - return BytesToNameCanonicalizer.getEmptyName(); - } - return parseEscapedFieldName(_quadBuffer, 0, 0, i, 0); - } - - private final Name parseFieldName(int q1, int ch, int lastQuadBytes) - throws IOException, JsonParseException - { - return parseEscapedFieldName(_quadBuffer, 0, q1, ch, lastQuadBytes); - } - - private final Name parseFieldName(int q1, int q2, int ch, int lastQuadBytes) - throws IOException, JsonParseException - { - _quadBuffer[0] = q1; - return parseEscapedFieldName(_quadBuffer, 1, q2, ch, lastQuadBytes); - } - - /** - * Slower parsing method which is generally branched to when - * an escape sequence is detected (or alternatively for long - * names, or ones crossing input buffer boundary). In any case, - * needs to be able to handle more exceptional cases, gets - * slower, and hance is offlined to a separate method. - */ - protected Name parseEscapedFieldName(int[] quads, int qlen, int currQuad, int ch, - int currQuadBytes) - throws IOException, JsonParseException - { - /* 25-Nov-2008, tatu: This may seem weird, but here we do - * NOT want to worry about UTF-8 decoding. Rather, we'll - * assume that part is ok (if not it will get caught - * later on), and just handle quotes and backslashes here. - */ - final int[] codes = CharTypes.getInputCodeLatin1(); - - while (true) { - if (codes[ch] != 0) { - if (ch == INT_QUOTE) { // we are done - break; - } - // Unquoted white space? - if (ch != INT_BACKSLASH) { - // As per [JACKSON-208], call can now return: - _throwUnquotedSpace(ch, "name"); - } else { - // Nope, escape sequence - ch = _decodeEscaped(); - } - /* Oh crap. May need to UTF-8 (re-)encode it, if it's - * beyond 7-bit ascii. Gets pretty messy. - * If this happens often, may want to use different name - * canonicalization to avoid these hits. - */ - if (ch > 127) { - // Ok, we'll need room for first byte right away - if (currQuadBytes >= 4) { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = currQuad; - currQuad = 0; - currQuadBytes = 0; - } - if (ch < 0x800) { // 2-byte - currQuad = (currQuad << 8) | (0xc0 | (ch >> 6)); - ++currQuadBytes; - // Second byte gets output below: - } else { // 3 bytes; no need to worry about surrogates here - currQuad = (currQuad << 8) | (0xe0 | (ch >> 12)); - ++currQuadBytes; - // need room for middle byte? - if (currQuadBytes >= 4) { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = currQuad; - currQuad = 0; - currQuadBytes = 0; - } - currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f)); - ++currQuadBytes; - } - // And same last byte in both cases, gets output below: - ch = 0x80 | (ch & 0x3f); - } - } - // Ok, we have one more byte to add at any rate: - if (currQuadBytes < 4) { - ++currQuadBytes; - currQuad = (currQuad << 8) | ch; - } else { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = currQuad; - currQuad = ch; - currQuadBytes = 1; - } - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(" in field name"); - } - } - ch = _inputBuffer[_inputPtr++] & 0xFF; - } - - if (currQuadBytes > 0) { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = currQuad; - } - Name name = _symbols.findName(quads, qlen); - if (name == null) { - name = addName(quads, qlen, currQuadBytes); - } - return name; - } - - /** - * Method called when we see non-white space character other - * than double quote, when expecting a field name. - * In standard mode will just throw an expection; but - * in non-standard modes may be able to parse name. - */ - protected final Name _handleUnusualFieldName(int ch) - throws IOException, JsonParseException - { - // [JACKSON-173]: allow single quotes - if (ch == INT_APOSTROPHE && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) { - return _parseApostropheFieldName(); - } - // [JACKSON-69]: allow unquoted names if feature enabled: - if (!isEnabled(Feature.ALLOW_UNQUOTED_FIELD_NAMES)) { - _reportUnexpectedChar(ch, "was expecting double-quote to start field name"); - } - /* Also: note that although we use a different table here, - * it does NOT handle UTF-8 decoding. It'll just pass those - * high-bit codes as acceptable for later decoding. - */ - final int[] codes = CharTypes.getInputCodeUtf8JsNames(); - // Also: must start with a valid character... - if (codes[ch] != 0) { - _reportUnexpectedChar(ch, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name"); - } - - /* Ok, now; instead of ultra-optimizing parsing here (as with - * regular JSON names), let's just use the generic "slow" - * variant. Can measure its impact later on if need be - */ - int[] quads = _quadBuffer; - int qlen = 0; - int currQuad = 0; - int currQuadBytes = 0; - - while (true) { - // Ok, we have one more byte to add at any rate: - if (currQuadBytes < 4) { - ++currQuadBytes; - currQuad = (currQuad << 8) | ch; - } else { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = currQuad; - currQuad = ch; - currQuadBytes = 1; - } - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(" in field name"); - } - } - ch = _inputBuffer[_inputPtr] & 0xFF; - if (codes[ch] != 0) { - break; - } - ++_inputPtr; - } - - if (currQuadBytes > 0) { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = currQuad; - } - Name name = _symbols.findName(quads, qlen); - if (name == null) { - name = addName(quads, qlen, currQuadBytes); - } - return name; - } - - /* Parsing to support [JACKSON-173]. Plenty of duplicated code; - * main reason being to try to avoid slowing down fast path - * for valid JSON -- more alternatives, more code, generally - * bit slower execution. - */ - protected final Name _parseApostropheFieldName() - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(": was expecting closing '\'' for name"); - } - } - int ch = _inputBuffer[_inputPtr++] & 0xFF; - if (ch == INT_APOSTROPHE) { // special case, '' - return BytesToNameCanonicalizer.getEmptyName(); - } - int[] quads = _quadBuffer; - int qlen = 0; - int currQuad = 0; - int currQuadBytes = 0; - - // Copied from parseEscapedFieldName, with minor mods: - - final int[] codes = CharTypes.getInputCodeLatin1(); - - while (true) { - if (ch == INT_APOSTROPHE) { - break; - } - // additional check to skip handling of double-quotes - if (ch != INT_QUOTE && codes[ch] != 0) { - if (ch != INT_BACKSLASH) { - // Unquoted white space? - // As per [JACKSON-208], call can now return: - _throwUnquotedSpace(ch, "name"); - } else { - // Nope, escape sequence - ch = _decodeEscaped(); - } - /* Oh crap. May need to UTF-8 (re-)encode it, if it's - * beyond 7-bit ascii. Gets pretty messy. - * If this happens often, may want to use different name - * canonicalization to avoid these hits. - */ - if (ch > 127) { - // Ok, we'll need room for first byte right away - if (currQuadBytes >= 4) { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = currQuad; - currQuad = 0; - currQuadBytes = 0; - } - if (ch < 0x800) { // 2-byte - currQuad = (currQuad << 8) | (0xc0 | (ch >> 6)); - ++currQuadBytes; - // Second byte gets output below: - } else { // 3 bytes; no need to worry about surrogates here - currQuad = (currQuad << 8) | (0xe0 | (ch >> 12)); - ++currQuadBytes; - // need room for middle byte? - if (currQuadBytes >= 4) { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = currQuad; - currQuad = 0; - currQuadBytes = 0; - } - currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f)); - ++currQuadBytes; - } - // And same last byte in both cases, gets output below: - ch = 0x80 | (ch & 0x3f); - } - } - // Ok, we have one more byte to add at any rate: - if (currQuadBytes < 4) { - ++currQuadBytes; - currQuad = (currQuad << 8) | ch; - } else { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = currQuad; - currQuad = ch; - currQuadBytes = 1; - } - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(" in field name"); - } - } - ch = _inputBuffer[_inputPtr++] & 0xFF; - } - - if (currQuadBytes > 0) { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = currQuad; - } - Name name = _symbols.findName(quads, qlen); - if (name == null) { - name = addName(quads, qlen, currQuadBytes); - } - return name; - } - - /* - /*************************************************** - /* Internal methods, symbol (name) handling - /*************************************************** - */ - - private final Name findName(int q1, int lastQuadBytes) - throws JsonParseException - { - // Usually we'll find it from the canonical symbol table already - Name name = _symbols.findName(q1); - if (name != null) { - return name; - } - // If not, more work. We'll need add stuff to buffer - _quadBuffer[0] = q1; - return addName(_quadBuffer, 1, lastQuadBytes); - } - - private final Name findName(int q1, int q2, int lastQuadBytes) - throws JsonParseException - { - // Usually we'll find it from the canonical symbol table already - Name name = _symbols.findName(q1, q2); - if (name != null) { - return name; - } - // If not, more work. We'll need add stuff to buffer - _quadBuffer[0] = q1; - _quadBuffer[1] = q2; - return addName(_quadBuffer, 2, lastQuadBytes); - } - - private final Name findName(int[] quads, int qlen, int lastQuad, int lastQuadBytes) - throws JsonParseException - { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = lastQuad; - Name name = _symbols.findName(quads, qlen); - if (name == null) { - return addName(quads, qlen, lastQuadBytes); - } - return name; - } - - /** - * This is the main workhorse method used when we take a symbol - * table miss. It needs to demultiplex individual bytes, decode - * multi-byte chars (if any), and then construct Name instance - * and add it to the symbol table. - */ - private final Name addName(int[] quads, int qlen, int lastQuadBytes) - throws JsonParseException - { - /* Ok: must decode UTF-8 chars. No other validation is - * needed, since unescaping has been done earlier as necessary - * (as well as error reporting for unescaped control chars) - */ - // 4 bytes per quad, except last one maybe less - int byteLen = (qlen << 2) - 4 + lastQuadBytes; - - /* And last one is not correctly aligned (leading zero bytes instead - * need to shift a bit, instead of trailing). Only need to shift it - * for UTF-8 decoding; need revert for storage (since key will not - * be aligned, to optimize lookup speed) - */ - int lastQuad; - - if (lastQuadBytes < 4) { - lastQuad = quads[qlen-1]; - // 8/16/24 bit left shift - quads[qlen-1] = (lastQuad << ((4 - lastQuadBytes) << 3)); - } else { - lastQuad = 0; - } - - // Need some working space, TextBuffer works well: - char[] cbuf = _textBuffer.emptyAndGetCurrentSegment(); - int cix = 0; - - for (int ix = 0; ix < byteLen; ) { - int ch = quads[ix >> 2]; // current quad, need to shift+mask - int byteIx = (ix & 3); - ch = (ch >> ((3 - byteIx) << 3)) & 0xFF; - ++ix; - - if (ch > 127) { // multi-byte - int needed; - if ((ch & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF) - ch &= 0x1F; - needed = 1; - } else if ((ch & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF) - ch &= 0x0F; - needed = 2; - } else if ((ch & 0xF8) == 0xF0) { // 4 bytes; double-char with surrogates and all... - ch &= 0x07; - needed = 3; - } else { // 5- and 6-byte chars not valid xml chars - _reportInvalidInitial(ch); - needed = ch = 1; // never really gets this far - } - if ((ix + needed) > byteLen) { - _reportInvalidEOF(" in field name"); - } - - // Ok, always need at least one more: - int ch2 = quads[ix >> 2]; // current quad, need to shift+mask - byteIx = (ix & 3); - ch2 = (ch2 >> ((3 - byteIx) << 3)); - ++ix; - - if ((ch2 & 0xC0) != 0x080) { - _reportInvalidOther(ch2); - } - ch = (ch << 6) | (ch2 & 0x3F); - if (needed > 1) { - ch2 = quads[ix >> 2]; - byteIx = (ix & 3); - ch2 = (ch2 >> ((3 - byteIx) << 3)); - ++ix; - - if ((ch2 & 0xC0) != 0x080) { - _reportInvalidOther(ch2); - } - ch = (ch << 6) | (ch2 & 0x3F); - if (needed > 2) { // 4 bytes? (need surrogates on output) - ch2 = quads[ix >> 2]; - byteIx = (ix & 3); - ch2 = (ch2 >> ((3 - byteIx) << 3)); - ++ix; - if ((ch2 & 0xC0) != 0x080) { - _reportInvalidOther(ch2 & 0xFF); - } - ch = (ch << 6) | (ch2 & 0x3F); - } - } - if (needed > 2) { // surrogate pair? once again, let's output one here, one later on - ch -= 0x10000; // to normalize it starting with 0x0 - if (cix >= cbuf.length) { - cbuf = _textBuffer.expandCurrentSegment(); - } - cbuf[cix++] = (char) (0xD800 + (ch >> 10)); - ch = 0xDC00 | (ch & 0x03FF); - } - } - if (cix >= cbuf.length) { - cbuf = _textBuffer.expandCurrentSegment(); - } - cbuf[cix++] = (char) ch; - } - - /* Ok. Now we have the character array, and can construct the - * String (as well as check proper composition of semicolons - * for ns-aware mode...) - */ - String baseName = new String(cbuf, 0, cix); - // And finally, un-align if necessary - if (lastQuadBytes < 4) { - quads[qlen-1] = lastQuad; - } - return _symbols.addName(baseName, quads, qlen); - } - - /* - /*************************************************** - /* Internal methods, String value parsing - /*************************************************** - */ - - @Override - protected void _finishString() - throws IOException, JsonParseException - { - int outPtr = 0; - int c; - char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); - - // Here we do want to do full decoding, hence: - final int[] codes = CharTypes.getInputCodeUtf8(); - final byte[] inputBuffer = _inputBuffer; - - main_loop: - while (true) { - // Then the tight ascii non-funny-char loop: - ascii_loop: - while (true) { - int ptr = _inputPtr; - if (ptr >= _inputEnd) { - loadMoreGuaranteed(); - ptr = _inputPtr; - } - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - int max = _inputEnd; - { - int max2 = ptr + (outBuf.length - outPtr); - if (max2 < max) { - max = max2; - } - } - while (ptr < max) { - c = (int) inputBuffer[ptr++] & 0xFF; - if (codes[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - outBuf[outPtr++] = (char) c; - } - _inputPtr = ptr; - } - // Ok: end marker, escape or multi-byte? - if (c == INT_QUOTE) { - break main_loop; - } - - switch (codes[c]) { - case 1: // backslash - c = _decodeEscaped(); - break; - case 2: // 2-byte UTF - c = _decodeUtf8_2(c); - break; - case 3: // 3-byte UTF - if ((_inputEnd - _inputPtr) >= 2) { - c = _decodeUtf8_3fast(c); - } else { - c = _decodeUtf8_3(c); - } - break; - case 4: // 4-byte UTF - c = _decodeUtf8_4(c); - // Let's add first part right away: - outBuf[outPtr++] = (char) (0xD800 | (c >> 10)); - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - c = 0xDC00 | (c & 0x3FF); - // And let the other char output down below - break; - default: - if (c < INT_SPACE) { - // As per [JACKSON-208], call can now return: - _throwUnquotedSpace(c, "string value"); - } else { - // Is this good enough error message? - _reportInvalidChar(c); - } - } - // Need more room? - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - // Ok, let's add char to output: - outBuf[outPtr++] = (char) c; - } - _textBuffer.setCurrentLength(outPtr); - } - - /** - * Method called to skim through rest of unparsed String value, - * if it is not needed. This can be done bit faster if contents - * need not be stored for future access. - */ - protected void _skipString() - throws IOException, JsonParseException - { - _tokenIncomplete = false; - - // Need to be fully UTF-8 aware here: - final int[] codes = CharTypes.getInputCodeUtf8(); - final byte[] inputBuffer = _inputBuffer; - - main_loop: - while (true) { - int c; - - ascii_loop: - while (true) { - int ptr = _inputPtr; - int max = _inputEnd; - if (ptr >= max) { - loadMoreGuaranteed(); - ptr = _inputPtr; - max = _inputEnd; - } - while (ptr < max) { - c = (int) inputBuffer[ptr++] & 0xFF; - if (codes[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - } - _inputPtr = ptr; - } - // Ok: end marker, escape or multi-byte? - if (c == INT_QUOTE) { - break main_loop; - } - - switch (codes[c]) { - case 1: // backslash - _decodeEscaped(); - break; - case 2: // 2-byte UTF - _skipUtf8_2(c); - break; - case 3: // 3-byte UTF - _skipUtf8_3(c); - break; - case 4: // 4-byte UTF - _skipUtf8_4(c); - break; - default: - if (c < INT_SPACE) { - // As per [JACKSON-208], call can now return: - _throwUnquotedSpace(c, "string value"); - } else { - // Is this good enough error message? - _reportInvalidChar(c); - } - } - } - } - - /** - * Method for handling cases where first non-space character - * of an expected value token is not legal for standard JSON content. - * - * @since 1.3 - */ - protected final JsonToken _handleUnexpectedValue(int c) - throws IOException, JsonParseException - { - // Most likely an error, unless we are to allow single-quote-strings - if (c != INT_APOSTROPHE || !isEnabled(Feature.ALLOW_SINGLE_QUOTES)) { - _reportUnexpectedChar(c, "expected a valid value (number, String, array, object, 'true', 'false' or 'null')"); - } - - // Otherwise almost verbatim copy of _finishString() - int outPtr = 0; - char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); - - // Here we do want to do full decoding, hence: - final int[] codes = CharTypes.getInputCodeUtf8(); - final byte[] inputBuffer = _inputBuffer; - - main_loop: - while (true) { - // Then the tight ascii non-funny-char loop: - ascii_loop: - while (true) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - int max = _inputEnd; - { - int max2 = _inputPtr + (outBuf.length - outPtr); - if (max2 < max) { - max = max2; - } - } - while (_inputPtr < max) { - c = (int) inputBuffer[_inputPtr++] & 0xFF; - if (c == INT_APOSTROPHE || codes[c] != 0) { - break ascii_loop; - } - outBuf[outPtr++] = (char) c; - } - } - - // Ok: end marker, escape or multi-byte? - if (c == INT_APOSTROPHE) { - break main_loop; - } - - switch (codes[c]) { - case 1: // backslash - if (c != INT_QUOTE) { // marked as special, isn't here - c = _decodeEscaped(); - } - break; - case 2: // 2-byte UTF - c = _decodeUtf8_2(c); - break; - case 3: // 3-byte UTF - if ((_inputEnd - _inputPtr) >= 2) { - c = _decodeUtf8_3fast(c); - } else { - c = _decodeUtf8_3(c); - } - break; - case 4: // 4-byte UTF - c = _decodeUtf8_4(c); - // Let's add first part right away: - outBuf[outPtr++] = (char) (0xD800 | (c >> 10)); - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - c = 0xDC00 | (c & 0x3FF); - // And let the other char output down below - break; - default: - if (c < INT_SPACE) { - _throwUnquotedSpace(c, "string value"); - } - // Is this good enough error message? - _reportInvalidChar(c); - } - // Need more room? - if (outPtr >= outBuf.length) { - outBuf = _textBuffer.finishCurrentSegment(); - outPtr = 0; - } - // Ok, let's add char to output: - outBuf[outPtr++] = (char) c; - } - _textBuffer.setCurrentLength(outPtr); - - return JsonToken.VALUE_STRING; - } - - /* - /*************************************************** - /* Internal methods, other parsing helper methods - /*************************************************** - */ - - protected void _matchToken(JsonToken token) - throws IOException, JsonParseException - { - // First char is already matched, need to check the rest - byte[] matchBytes = token.asByteArray(); - int i = 1; - - for (int len = matchBytes.length; i < len; ++i) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (matchBytes[i] != _inputBuffer[_inputPtr]) { - _reportInvalidToken(token.asString().substring(0, i)); - } - ++_inputPtr; - } - /* Ok, fine; let's not bother checking anything beyond keyword. - * If there's something wrong there, it'll cause a parsing - * error later on. - */ - return; - } - - private void _reportInvalidToken(String matchedPart) - throws IOException, JsonParseException - { - StringBuilder sb = new StringBuilder(matchedPart); - /* Let's just try to find what appears to be the token, using - * regular Java identifier character rules. It's just a heuristic, - * nothing fancy here (nor fast). - */ - while (true) { - if (_inputPtr >= _inputEnd && !loadMore()) { - break; - } - int i = (int) _inputBuffer[_inputPtr++]; - char c = (char) _decodeCharForError(i); - if (!Character.isJavaIdentifierPart(c)) { - break; - } - ++_inputPtr; - sb.append(c); - } - - _reportError("Unrecognized token '"+sb.toString()+"': was expecting 'null', 'true' or 'false'"); - } - - /* - /*************************************************** - /* Internal methods, ws skipping, escape/unescape - /*************************************************** - */ - - private final int _skipWS() - throws IOException, JsonParseException - { - while (_inputPtr < _inputEnd || loadMore()) { - int i = _inputBuffer[_inputPtr++] & 0xFF; - if (i > INT_SPACE) { - if (i != INT_SLASH) { - return i; - } - _skipComment(); - } else if (i != INT_SPACE) { - if (i == INT_LF) { - _skipLF(); - } else if (i == INT_CR) { - _skipCR(); - } else if (i != INT_TAB) { - _throwInvalidSpace(i); - } - } - } - throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries"); - } - - private final int _skipWSOrEnd() - throws IOException, JsonParseException - { - while ((_inputPtr < _inputEnd) || loadMore()) { - int i = _inputBuffer[_inputPtr++] & 0xFF; - if (i > INT_SPACE) { - if (i != INT_SLASH) { - return i; - } - _skipComment(); - } else if (i != INT_SPACE) { - if (i == INT_LF) { - _skipLF(); - } else if (i == INT_CR) { - _skipCR(); - } else if (i != INT_TAB) { - _throwInvalidSpace(i); - } - } - } - // We ran out of input... - _handleEOF(); - return -1; - } - - private final void _skipComment() - throws IOException, JsonParseException - { - if (!isEnabled(Feature.ALLOW_COMMENTS)) { - _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)"); - } - // First: check which comment (if either) it is: - if (_inputPtr >= _inputEnd && !loadMore()) { - _reportInvalidEOF(" in a comment"); - } - int c = _inputBuffer[_inputPtr++] & 0xFF; - if (c == INT_SLASH) { - _skipCppComment(); - } else if (c == INT_ASTERISK) { - _skipCComment(); - } else { - _reportUnexpectedChar(c, "was expecting either '*' or '/' for a comment"); - } - } - - private final void _skipCComment() - throws IOException, JsonParseException - { - // Need to be UTF-8 aware here to decode content (for skipping) - final int[] codes = CharTypes.getInputCodeComment(); - - // Ok: need the matching '*/' - while ((_inputPtr < _inputEnd) || loadMore()) { - int i = (int) _inputBuffer[_inputPtr++] & 0xFF; - int code = codes[i]; - if (code != 0) { - switch (code) { - case INT_ASTERISK: - if (_inputBuffer[_inputPtr] == INT_SLASH) { - ++_inputPtr; - return; - } - break; - case INT_LF: - _skipLF(); - break; - case INT_CR: - _skipCR(); - break; - default: // e.g. -1 - // Is this good enough error message? - _reportInvalidChar(i); - } - } - } - _reportInvalidEOF(" in a comment"); - } - - private final void _skipCppComment() - throws IOException, JsonParseException - { - // Ok: need to find EOF or linefeed - final int[] codes = CharTypes.getInputCodeComment(); - while ((_inputPtr < _inputEnd) || loadMore()) { - int i = (int) _inputBuffer[_inputPtr++] & 0xFF; - int code = codes[i]; - if (code != 0) { - switch (code) { - case INT_LF: - _skipLF(); - return; - case INT_CR: - _skipCR(); - return; - case INT_ASTERISK: // nop for these comments - break; - default: // e.g. -1 - // Is this good enough error message? - _reportInvalidChar(i); - } - } - } - } - - protected final char _decodeEscaped() - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(" in character escape sequence"); - } - } - int c = (int) _inputBuffer[_inputPtr++]; - - switch ((int) c) { - // First, ones that are mapped - case INT_b: - return '\b'; - case INT_t: - return '\t'; - case INT_n: - return '\n'; - case INT_f: - return '\f'; - case INT_r: - return '\r'; - - // And these are to be returned as they are - case INT_QUOTE: - case INT_SLASH: - case INT_BACKSLASH: - return (char) c; - - case INT_u: // and finally hex-escaped - break; - - default: - _reportError("Unrecognized character escape (\\ followed by "+_getCharDesc(_decodeCharForError(c))+")"); - } - - // Ok, a hex escape. Need 4 characters - int value = 0; - for (int i = 0; i < 4; ++i) { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - _reportInvalidEOF(" in character escape sequence"); - } - } - int ch = (int) _inputBuffer[_inputPtr++]; - int digit = CharTypes.charToHex(ch); - if (digit < 0) { - _reportUnexpectedChar(ch, "expected a hex-digit for character escape sequence"); - } - value = (value << 4) | digit; - } - return (char) value; - } - - protected int _decodeCharForError(int firstByte) - throws IOException, JsonParseException - { - int c = (int) firstByte; - if (c < 0) { // if >= 0, is ascii and fine as is - int needed; - - // Ok; if we end here, we got multi-byte combination - if ((c & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF) - c &= 0x1F; - needed = 1; - } else if ((c & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF) - c &= 0x0F; - needed = 2; - } else if ((c & 0xF8) == 0xF0) { - // 4 bytes; double-char with surrogates and all... - c &= 0x07; - needed = 3; - } else { - _reportInvalidInitial(c & 0xFF); - needed = 1; // never gets here - } - - int d = nextByte(); - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF); - } - c = (c << 6) | (d & 0x3F); - - if (needed > 1) { // needed == 1 means 2 bytes total - d = nextByte(); // 3rd byte - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF); - } - c = (c << 6) | (d & 0x3F); - if (needed > 2) { // 4 bytes? (need surrogates) - d = nextByte(); - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF); - } - c = (c << 6) | (d & 0x3F); - } - } - } - return c; - } - - /* - /*************************************************** - /* Internal methods,UTF8 decoding - /*************************************************** - */ - - private final int _decodeUtf8_2(int c) - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - int d = (int) _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF, _inputPtr); - } - return ((c & 0x1F) << 6) | (d & 0x3F); - } - - private final int _decodeUtf8_3(int c1) - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - c1 &= 0x0F; - int d = (int) _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF, _inputPtr); - } - int c = (c1 << 6) | (d & 0x3F); - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - d = (int) _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF, _inputPtr); - } - c = (c << 6) | (d & 0x3F); - return c; - } - - private final int _decodeUtf8_3fast(int c1) - throws IOException, JsonParseException - { - c1 &= 0x0F; - int d = (int) _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF, _inputPtr); - } - int c = (c1 << 6) | (d & 0x3F); - d = (int) _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF, _inputPtr); - } - c = (c << 6) | (d & 0x3F); - return c; - } - - /** - * @return Character value minus 0x10000; this so that caller - * can readily expand it to actual surrogates - */ - private final int _decodeUtf8_4(int c) - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - int d = (int) _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF, _inputPtr); - } - c = ((c & 0x07) << 6) | (d & 0x3F); - - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - d = (int) _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF, _inputPtr); - } - c = (c << 6) | (d & 0x3F); - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - d = (int) _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF, _inputPtr); - } - - /* note: won't change it to negative here, since caller - * already knows it'll need a surrogate - */ - return ((c << 6) | (d & 0x3F)) - 0x10000; - } - - private final void _skipUtf8_2(int c) - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - c = (int) _inputBuffer[_inputPtr++]; - if ((c & 0xC0) != 0x080) { - _reportInvalidOther(c & 0xFF, _inputPtr); - } - } - - /* Alas, can't heavily optimize skipping, since we still have to - * do validity checks... - */ - private final void _skipUtf8_3(int c) - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - //c &= 0x0F; - c = (int) _inputBuffer[_inputPtr++]; - if ((c & 0xC0) != 0x080) { - _reportInvalidOther(c & 0xFF, _inputPtr); - } - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - c = (int) _inputBuffer[_inputPtr++]; - if ((c & 0xC0) != 0x080) { - _reportInvalidOther(c & 0xFF, _inputPtr); - } - } - - private final void _skipUtf8_4(int c) - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - int d = (int) _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF, _inputPtr); - } - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF, _inputPtr); - } - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - d = (int) _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - _reportInvalidOther(d & 0xFF, _inputPtr); - } - } - - /* - /*************************************************** - /* Internal methods, input loading - /*************************************************** - */ - - /** - * We actually need to check the character value here - * (to see if we have \n following \r). - */ - protected final void _skipCR() throws IOException - { - if (_inputPtr < _inputEnd || loadMore()) { - if (_inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - } - ++_currInputRow; - _currInputRowStart = _inputPtr; - } - - protected final void _skipLF() throws IOException - { - ++_currInputRow; - _currInputRowStart = _inputPtr; - } - - private int nextByte() - throws IOException, JsonParseException - { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - return _inputBuffer[_inputPtr++] & 0xFF; - } - - /* - /*************************************************** - /* Internal methods, error reporting - /*************************************************** - */ - - protected void _reportInvalidChar(int c) - throws JsonParseException - { - // Either invalid WS or illegal UTF-8 start char - if (c < INT_SPACE) { - _throwInvalidSpace(c); - } - _reportInvalidInitial(c); - } - - protected void _reportInvalidInitial(int mask) - throws JsonParseException - { - _reportError("Invalid UTF-8 start byte 0x"+Integer.toHexString(mask)); - } - - protected void _reportInvalidOther(int mask) - throws JsonParseException - { - _reportError("Invalid UTF-8 middle byte 0x"+Integer.toHexString(mask)); - } - - protected void _reportInvalidOther(int mask, int ptr) - throws JsonParseException - { - _inputPtr = ptr; - _reportInvalidOther(mask); - } - - public static int[] growArrayBy(int[] arr, int more) - { - if (arr == null) { - return new int[more]; - } - int[] old = arr; - int len = arr.length; - arr = new int[len + more]; - System.arraycopy(old, 0, arr, 0, len); - return arr; - } - - /* - /*************************************************** - /* Binary access - /*************************************************** - */ - - @Override - protected byte[] _decodeBase64(Base64Variant b64variant) - throws IOException, JsonParseException - { - ByteArrayBuilder builder = _getByteArrayBuilder(); - - /* !!! 23-Jan-2009, tatu: There are some potential problems - * with this: - * - * - Escaped chars are not handled. Should they? - */ - - //main_loop: - while (true) { - // first, we'll skip preceding white space, if any - int ch; - do { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - ch = (int) _inputBuffer[_inputPtr++] & 0xFF; - } while (ch <= INT_SPACE); - int bits = b64variant.decodeBase64Char(ch); - if (bits < 0) { // reached the end, fair and square? - if (ch == INT_QUOTE) { - return builder.toByteArray(); - } - throw reportInvalidChar(b64variant, ch, 0); - } - int decodedData = bits; - - // then second base64 char; can't get padding yet, nor ws - - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - ch = _inputBuffer[_inputPtr++] & 0xFF; - bits = b64variant.decodeBase64Char(ch); - if (bits < 0) { - throw reportInvalidChar(b64variant, ch, 1); - } - decodedData = (decodedData << 6) | bits; - - // third base64 char; can be padding, but not ws - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - ch = _inputBuffer[_inputPtr++] & 0xFF; - bits = b64variant.decodeBase64Char(ch); - - // First branch: can get padding (-> 1 byte) - if (bits < 0) { - if (bits != Base64Variant.BASE64_VALUE_PADDING) { - throw reportInvalidChar(b64variant, ch, 2); - } - // Ok, must get padding - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - ch = _inputBuffer[_inputPtr++] & 0xFF; - if (!b64variant.usesPaddingChar(ch)) { - throw reportInvalidChar(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'"); - } - // Got 12 bits, only need 8, need to shift - decodedData >>= 4; - builder.append(decodedData); - continue; - } - // Nope, 2 or 3 bytes - decodedData = (decodedData << 6) | bits; - // fourth and last base64 char; can be padding, but not ws - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - ch = _inputBuffer[_inputPtr++] & 0xFF; - bits = b64variant.decodeBase64Char(ch); - if (bits < 0) { - if (bits != Base64Variant.BASE64_VALUE_PADDING) { - throw reportInvalidChar(b64variant, ch, 3); - } - /* With padding we only get 2 bytes; but we have - * to shift it a bit so it is identical to triplet - * case with partial output. - * 3 chars gives 3x6 == 18 bits, of which 2 are - * dummies, need to discard: - */ - decodedData >>= 2; - builder.appendTwoBytes(decodedData); - } else { - // otherwise, our triple is now complete - decodedData = (decodedData << 6) | bits; - builder.appendThreeBytes(decodedData); - } - } - } - - protected IllegalArgumentException reportInvalidChar(Base64Variant b64variant, int ch, int bindex) - throws IllegalArgumentException - { - return reportInvalidChar(b64variant, ch, bindex, null); - } - - /** - * @param bindex Relative index within base64 character unit; between 0 - * and 3 (as unit has exactly 4 characters) - */ - protected IllegalArgumentException reportInvalidChar(Base64Variant b64variant, int ch, int bindex, String msg) - throws IllegalArgumentException - { - String base; - if (ch <= INT_SPACE) { - base = "Illegal white space character (code 0x"+Integer.toHexString(ch)+") as character #"+(bindex+1)+" of 4-char base64 unit: can only used between units"; - } else if (b64variant.usesPaddingChar(ch)) { - base = "Unexpected padding character ('"+b64variant.getPaddingChar()+"') as character #"+(bindex+1)+" of 4-char base64 unit: padding only legal as 3rd or 4th character"; - } else if (!Character.isDefined(ch) || Character.isISOControl(ch)) { - // Not sure if we can really get here... ? (most illegal xml chars are caught at lower level) - base = "Illegal character (code 0x"+Integer.toHexString(ch)+") in base64 content"; - } else { - base = "Illegal character '"+((char)ch)+"' (code 0x"+Integer.toHexString(ch)+") in base64 content"; - } - if (msg != null) { - base = base + ": " + msg; - } - return new IllegalArgumentException(base); - } -} diff --git a/src/org/codehaus/jackson/impl/WriterBasedGenerator.java b/src/org/codehaus/jackson/impl/WriterBasedGenerator.java deleted file mode 100644 index 5e1dac1e10..0000000000 --- a/src/org/codehaus/jackson/impl/WriterBasedGenerator.java +++ /dev/null @@ -1,1019 +0,0 @@ -package org.codehaus.jackson.impl; - -import java.io.*; -import java.math.BigDecimal; -import java.math.BigInteger; - -import org.codehaus.jackson.*; -import org.codehaus.jackson.io.*; -import org.codehaus.jackson.util.CharTypes; - -public final class WriterBasedGenerator - extends JsonGeneratorBase -{ - final static int SHORT_WRITE = 32; - - final static char[] HEX_CHARS = "0123456789ABCDEF".toCharArray(); - - /* - //////////////////////////////////////////////////// - // Configuration - //////////////////////////////////////////////////// - */ - - final protected IOContext _ioContext; - - final protected Writer _writer; - - /* - //////////////////////////////////////////////////// - // Output buffering - //////////////////////////////////////////////////// - */ - - /** - * Intermediate buffer in which contents are buffered before - * being written using {@link #_writer}. - */ - protected char[] _outputBuffer; - - /** - * Pointer to the first buffered character to output - */ - protected int _outputHead = 0; - - /** - * Pointer to the position right beyond the last character to output - * (end marker; may be past the buffer) - */ - protected int _outputTail = 0; - - /** - * End marker of the output buffer; one past the last valid position - * within the buffer. - */ - protected int _outputEnd; - - /** - * 6-char temporary buffer allocated if needed, for constructing - * escape sequences - */ - protected char[] _entityBuffer; - - /* - //////////////////////////////////////////////////// - // Life-cycle - //////////////////////////////////////////////////// - */ - - public WriterBasedGenerator(IOContext ctxt, int features, ObjectCodec codec, - Writer w) - { - super(features, codec); - _ioContext = ctxt; - _writer = w; - _outputBuffer = ctxt.allocConcatBuffer(); - _outputEnd = _outputBuffer.length; - } - - /* - //////////////////////////////////////////////////// - // Output method implementations, structural - //////////////////////////////////////////////////// - */ - - @Override - protected void _writeStartArray() - throws IOException, JsonGenerationException - { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '['; - } - - @Override - protected void _writeEndArray() - throws IOException, JsonGenerationException - { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = ']'; - } - - @Override - protected void _writeStartObject() - throws IOException, JsonGenerationException - { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '{'; - } - - @Override - protected void _writeEndObject() - throws IOException, JsonGenerationException - { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '}'; - } - - @Override - protected void _writeFieldName(String name, boolean commaBefore) - throws IOException, JsonGenerationException - { - if (_cfgPrettyPrinter != null) { - _writePPFieldName(name, commaBefore); - return; - } - // for fast+std case, need to output up to 2 chars, comma, dquote - if ((_outputTail + 1) >= _outputEnd) { - _flushBuffer(); - } - if (commaBefore) { - _outputBuffer[_outputTail++] = ','; - } - - /* To support [JACKSON-46], we'll do this: - * (Quostion: should quoting of spaces (etc) still be enabled?) - */ - if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) { - _writeString(name); - return; - } - - // we know there's room for at least one more char - _outputBuffer[_outputTail++] = '"'; - // The beef: - _writeString(name); - // and closing quotes; need room for one more char: - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - } - - /** - * Specialized version of _writeFieldName, off-lined - * to keep the "fast path" as simple (and hopefully fast) as possible. - */ - protected final void _writePPFieldName(String name, boolean commaBefore) - throws IOException, JsonGenerationException - { - if (commaBefore) { - _cfgPrettyPrinter.writeObjectEntrySeparator(this); - } else { - _cfgPrettyPrinter.beforeObjectEntries(this); - } - - if (isEnabled(Feature.QUOTE_FIELD_NAMES)) { // standard - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - _writeString(name); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - } else { // non-standard, omit quotes - _writeString(name); - } - } - - /* - //////////////////////////////////////////////////// - // Output method implementations, textual - //////////////////////////////////////////////////// - */ - - @Override - public void writeString(String text) - throws IOException, JsonGenerationException - { - _verifyValueWrite("write text value"); - if (text == null) { - _writeNull(); - return; - } - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - _writeString(text); - // And finally, closing quotes - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - } - - @Override - public void writeString(char[] text, int offset, int len) - throws IOException, JsonGenerationException - { - _verifyValueWrite("write text value"); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - _writeString(text, offset, len); - // And finally, closing quotes - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - } - - /* - //////////////////////////////////////////////////// - // Output method implementations, unprocessed ("raw") - //////////////////////////////////////////////////// - */ - - @Override - public void writeRaw(String text) - throws IOException, JsonGenerationException - { - // Nothing to check, can just output as is - int len = text.length(); - int room = _outputEnd - _outputTail; - - if (room == 0) { - _flushBuffer(); - room = _outputEnd - _outputTail; - } - // But would it nicely fit in? If yes, it's easy - if (room >= len) { - text.getChars(0, len, _outputBuffer, _outputTail); - _outputTail += len; - } else { - writeRawLong(text); - } - } - - @Override - public void writeRaw(String text, int start, int len) - throws IOException, JsonGenerationException - { - // Nothing to check, can just output as is - int room = _outputEnd - _outputTail; - - if (room < len) { - _flushBuffer(); - room = _outputEnd - _outputTail; - } - // But would it nicely fit in? If yes, it's easy - if (room >= len) { - text.getChars(start, start+len, _outputBuffer, _outputTail); - _outputTail += len; - } else { - writeRawLong(text.substring(start, start+len)); - } - } - - @Override - public void writeRaw(char[] text, int offset, int len) - throws IOException, JsonGenerationException - { - // Only worth buffering if it's a short write? - if (len < SHORT_WRITE) { - int room = _outputEnd - _outputTail; - if (len > room) { - _flushBuffer(); - } - System.arraycopy(text, offset, _outputBuffer, _outputTail, len); - _outputTail += len; - return; - } - // Otherwise, better just pass through: - _flushBuffer(); - _writer.write(text, offset, len); - } - - @Override - public void writeRaw(char c) - throws IOException, JsonGenerationException - { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = c; - } - - @Override - public void writeRawValue(String text) - throws IOException, JsonGenerationException - { - _verifyValueWrite("write raw value"); - writeRaw(text); - } - - @Override - public void writeRawValue(String text, int offset, int len) - throws IOException, JsonGenerationException - { - _verifyValueWrite("write raw value"); - writeRaw(text, offset, len); - } - - @Override - public void writeRawValue(char[] text, int offset, int len) - throws IOException, JsonGenerationException - { - _verifyValueWrite("write raw value"); - writeRaw(text, offset, len); - } - - private void writeRawLong(String text) - throws IOException, JsonGenerationException - { - int room = _outputEnd - _outputTail; - // If not, need to do it by looping - text.getChars(0, room, _outputBuffer, _outputTail); - _outputTail += room; - _flushBuffer(); - int offset = room; - int len = text.length() - room; - - while (len > _outputEnd) { - int amount = _outputEnd; - text.getChars(offset, offset+amount, _outputBuffer, 0); - _outputHead = 0; - _outputTail = amount; - _flushBuffer(); - offset += amount; - len -= amount; - } - // And last piece (at most length of buffer) - text.getChars(offset, offset+len, _outputBuffer, 0); - _outputHead = 0; - _outputTail = len; - } - - /* - //////////////////////////////////////////////////// - // Output method implementations, base64-encoded binary - //////////////////////////////////////////////////// - */ - - @Override - public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) - throws IOException, JsonGenerationException - { - _verifyValueWrite("write binary value"); - // Starting quotes - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - _writeBinary(b64variant, data, offset, offset+len); - // and closing quotes - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - } - - /* - //////////////////////////////////////////////////// - // Output method implementations, primitive - //////////////////////////////////////////////////// - */ - - @Override - public void writeNumber(int i) - throws IOException, JsonGenerationException - { - _verifyValueWrite("write number"); - // up to 10 digits and possible minus sign - if ((_outputTail + 11) >= _outputEnd) { - _flushBuffer(); - } - if (_cfgNumbersAsStrings) { - _writeQuotedInt(i); - return; - } - _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail); - } - - private final void _writeQuotedInt(int i) throws IOException { - if ((_outputTail + 13) >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail); - _outputBuffer[_outputTail++] = '"'; - } - - @Override - public void writeNumber(long l) - throws IOException, JsonGenerationException - { - _verifyValueWrite("write number"); - if (_cfgNumbersAsStrings) { - _writeQuotedLong(l); - return; - } - if ((_outputTail + 21) >= _outputEnd) { - // up to 20 digits, minus sign - _flushBuffer(); - } - _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail); - } - - private final void _writeQuotedLong(long l) throws IOException { - if ((_outputTail + 23) >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail); - _outputBuffer[_outputTail++] = '"'; - } - - // !!! 05-Aug-2008, tatus: Any ways to optimize these? - - @Override - public void writeNumber(BigInteger value) - throws IOException, JsonGenerationException - { - _verifyValueWrite("write number"); - if (value == null) { - _writeNull(); - } else if (_cfgNumbersAsStrings) { - _writeQuotedRaw(value); - } else { - writeRaw(value.toString()); - } - } - - - @Override - public void writeNumber(double d) - throws IOException, JsonGenerationException - { - if (_cfgNumbersAsStrings || - // [JACKSON-139] - (((Double.isNaN(d) || Double.isInfinite(d)) - && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)))) { - writeString(String.valueOf(d)); - return; - } - // What is the max length for doubles? 40 chars? - _verifyValueWrite("write number"); - writeRaw(String.valueOf(d)); - } - - @Override - public void writeNumber(float f) - throws IOException, JsonGenerationException - { - if (_cfgNumbersAsStrings || - // [JACKSON-139] - (((Float.isNaN(f) || Float.isInfinite(f)) - && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)))) { - writeString(String.valueOf(f)); - return; - } - // What is the max length for floats? - _verifyValueWrite("write number"); - writeRaw(String.valueOf(f)); - } - - @Override - public void writeNumber(BigDecimal value) - throws IOException, JsonGenerationException - { - // Don't really know max length for big decimal, no point checking - _verifyValueWrite("write number"); - if (value == null) { - _writeNull(); - } else if (_cfgNumbersAsStrings) { - _writeQuotedRaw(value); - } else { - writeRaw(value.toString()); - } - } - - @Override - public void writeNumber(String encodedValue) - throws IOException, JsonGenerationException - { - _verifyValueWrite("write number"); - if (_cfgNumbersAsStrings) { - _writeQuotedRaw(encodedValue); - } else { - writeRaw(encodedValue); - } - } - - private final void _writeQuotedRaw(Object value) throws IOException - { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - writeRaw(value.toString()); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '"'; - } - - @Override - public void writeBoolean(boolean state) - throws IOException, JsonGenerationException - { - _verifyValueWrite("write boolean value"); - if ((_outputTail + 5) >= _outputEnd) { - _flushBuffer(); - } - int ptr = _outputTail; - char[] buf = _outputBuffer; - if (state) { - buf[ptr] = 't'; - buf[++ptr] = 'r'; - buf[++ptr] = 'u'; - buf[++ptr] = 'e'; - } else { - buf[ptr] = 'f'; - buf[++ptr] = 'a'; - buf[++ptr] = 'l'; - buf[++ptr] = 's'; - buf[++ptr] = 'e'; - } - _outputTail = ptr+1; - } - - @Override - public void writeNull() - throws IOException, JsonGenerationException - { - _verifyValueWrite("write null value"); - _writeNull(); - } - - /* - //////////////////////////////////////////////////// - // Implementations for other methods - //////////////////////////////////////////////////// - */ - - @Override - protected final void _verifyValueWrite(String typeMsg) - throws IOException, JsonGenerationException - { - int status = _writeContext.writeValue(); - if (status == JsonWriteContext.STATUS_EXPECT_NAME) { - _reportError("Can not "+typeMsg+", expecting field name"); - } - if (_cfgPrettyPrinter == null) { - char c; - switch (status) { - case JsonWriteContext.STATUS_OK_AFTER_COMMA: - c = ','; - break; - case JsonWriteContext.STATUS_OK_AFTER_COLON: - c = ':'; - break; - case JsonWriteContext.STATUS_OK_AFTER_SPACE: - c = ' '; - break; - case JsonWriteContext.STATUS_OK_AS_IS: - default: - return; - } - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail] = c; - ++_outputTail; - return; - } - // Otherwise, pretty printer knows what to do... - _verifyPrettyValueWrite(typeMsg, status); - } - - protected final void _verifyPrettyValueWrite(String typeMsg, int status) - throws IOException, JsonGenerationException - { - // If we have a pretty printer, it knows what to do: - switch (status) { - case JsonWriteContext.STATUS_OK_AFTER_COMMA: // array - _cfgPrettyPrinter.writeArrayValueSeparator(this); - break; - case JsonWriteContext.STATUS_OK_AFTER_COLON: - _cfgPrettyPrinter.writeObjectFieldValueSeparator(this); - break; - case JsonWriteContext.STATUS_OK_AFTER_SPACE: - _cfgPrettyPrinter.writeRootValueSeparator(this); - break; - case JsonWriteContext.STATUS_OK_AS_IS: - // First entry, but of which context? - if (_writeContext.inArray()) { - _cfgPrettyPrinter.beforeArrayValues(this); - } else if (_writeContext.inObject()) { - _cfgPrettyPrinter.beforeObjectEntries(this); - } - break; - default: - _cantHappen(); - break; - } - } - - /* - //////////////////////////////////////////////////// - // Low-level output handling - //////////////////////////////////////////////////// - */ - - @Override - public final void flush() - throws IOException - { - _flushBuffer(); - _writer.flush(); - } - - @Override - public void close() - throws IOException - { - super.close(); - - /* 05-Dec-2008, tatu: To add [JACKSON-27], need to close open - * scopes. - */ - // First: let's see that we still have buffers... - if (_outputBuffer != null - && isEnabled(Feature.AUTO_CLOSE_JSON_CONTENT)) { - while (true) { - JsonStreamContext ctxt = getOutputContext(); - if (ctxt.inArray()) { - writeEndArray(); - } else if (ctxt.inObject()) { - writeEndObject(); - } else { - break; - } - } - } - _flushBuffer(); - - /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() - * on the underlying Reader, unless we "own" it, or auto-closing - * feature is enabled. - * One downside: when using UTF8Writer, underlying buffer(s) - * may not be properly recycled if we don't close the writer. - */ - if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_TARGET)) { - _writer.close(); - } else { - // If we can't close it, we should at least flush - _writer.flush(); - } - // Internal buffer(s) generator has can now be released as well - _releaseBuffers(); - } - - @Override - protected void _releaseBuffers() - { - char[] buf = _outputBuffer; - if (buf != null) { - _outputBuffer = null; - _ioContext.releaseConcatBuffer(buf); - } - } - - /* - //////////////////////////////////////////////////// - // Internal methods, low-level writing - //////////////////////////////////////////////////// - */ - - private void _writeString(String text) - throws IOException, JsonGenerationException - { - /* One check first: if String won't fit in the buffer, let's - * segment writes. No point in extending buffer to huge sizes - * (like if someone wants to include multi-megabyte base64 - * encoded stuff or such) - */ - int len = text.length(); - if (len > _outputEnd) { // Let's reserve space for entity at begin/end - _writeLongString(text); - return; - } - - // Ok: we know String will fit in buffer ok - // But do we need to flush first? - if ((_outputTail + len) > _outputEnd) { - _flushBuffer(); - } - text.getChars(0, len, _outputBuffer, _outputTail); - - // And then we'll need to verify need for escaping etc: - int end = _outputTail + len; - final int[] escCodes = CharTypes.getOutputEscapes(); - final int escLen = escCodes.length; - - output_loop: - while (_outputTail < end) { - // Fast loop for chars not needing escaping - escape_loop: - while (true) { - char c = _outputBuffer[_outputTail]; - if (c < escLen && escCodes[c] != 0) { - break escape_loop; - } - if (++_outputTail >= end) { - break output_loop; - } - } - - // Ok, bumped into something that needs escaping. - /* First things first: need to flush the buffer. - * Inlined, as we don't want to lose tail pointer - */ - int flushLen = (_outputTail - _outputHead); - if (flushLen > 0) { - _writer.write(_outputBuffer, _outputHead, flushLen); - } - /* In any case, tail will be the new start, so hopefully - * we have room now. - */ - { - int escCode = escCodes[_outputBuffer[_outputTail]]; - ++_outputTail; - int needLen = (escCode < 0) ? 6 : 2; - // If not, need to call separate method (note: buffer is empty now) - if (needLen > _outputTail) { - _outputHead = _outputTail; - _writeSingleEscape(escCode); - } else { - // But if it fits, can just prepend to buffer - int ptr = _outputTail - needLen; - _outputHead = ptr; - _appendSingleEscape(escCode, _outputBuffer, ptr); - } - } - } - } - - /** - * Method called to write "long strings", strings whose length exceeds - * output buffer length. - */ - private void _writeLongString(String text) - throws IOException, JsonGenerationException - { - // First things first: let's flush the buffer to get some more room - _flushBuffer(); - - // Then we can write - final int textLen = text.length(); - int offset = 0; - do { - int max = _outputEnd; - int segmentLen = ((offset + max) > textLen) - ? (textLen - offset) : max; - text.getChars(offset, offset+segmentLen, _outputBuffer, 0); - _writeSegment(segmentLen); - offset += segmentLen; - } while (offset < textLen); - } - /** - * Method called to output textual context which has been copied - * to the output buffer prior to call. If any escaping is needed, - * it will also be handled by the method. - *

- * Note: when called, textual content to write is within output - * buffer, right after buffered content (if any). That's why only - * length of that text is passed, as buffer and offset are implied. - */ - private final void _writeSegment(int end) - throws IOException, JsonGenerationException - { - final int[] escCodes = CharTypes.getOutputEscapes(); - final int escLen = escCodes.length; - - int ptr = 0; - - output_loop: - while (ptr < end) { - // Fast loop for chars not needing escaping - int start = ptr; - while (true) { - char c = _outputBuffer[ptr]; - if (c < escLen && escCodes[c] != 0) { - break; - } - if (++ptr >= end) { - break; - } - } - - // Ok, bumped into something that needs escaping. - /* First things first: need to flush the buffer. - * Inlined, as we don't want to lose tail pointer - */ - int flushLen = (ptr - start); - if (flushLen > 0) { - _writer.write(_outputBuffer, start, flushLen); - if (ptr >= end) { - break output_loop; - } - } - /* In any case, tail will be the new start, so hopefully - * we have room now. - */ - { - int escCode = escCodes[_outputBuffer[ptr]]; - ++ptr; - int needLen = (escCode < 0) ? 6 : 2; - // If not, need to call separate method (note: buffer is empty now) - if (needLen > _outputTail) { - _writeSingleEscape(escCode); - } else { - // But if it fits, can just prepend to buffer - ptr -= needLen; - _appendSingleEscape(escCode, _outputBuffer, ptr); - } - } - } - } - - /** - * This method called when the string content is already in - * a char buffer, and need not be copied for processing. - */ - private void _writeString(char[] text, int offset, int len) - throws IOException, JsonGenerationException - { - /* Let's just find longest spans of non-escapable - * content, and for each see if it makes sense - * to copy them, or write through - */ - len += offset; // -> len marks the end from now on - final int[] escCodes = CharTypes.getOutputEscapes(); - final int escLen = escCodes.length; - while (offset < len) { - int start = offset; - - while (true) { - char c = text[offset]; - if (c < escLen && escCodes[c] != 0) { - break; - } - if (++offset >= len) { - break; - } - } - - // Short span? Better just copy it to buffer first: - int newAmount = offset - start; - if (newAmount < SHORT_WRITE) { - // Note: let's reserve room for escaped char (up to 6 chars) - if ((_outputTail + newAmount) > _outputEnd) { - _flushBuffer(); - } - if (newAmount > 0) { - System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount); - _outputTail += newAmount; - } - } else { // Nope: better just write through - _flushBuffer(); - _writer.write(text, start, newAmount); - } - // Was this the end? - if (offset >= len) { // yup - break; - } - // Nope, need to escape the char. - int escCode = escCodes[text[offset]]; - ++offset; - int needLen = (escCode < 0) ? 6 : 2; - if ((_outputTail + needLen) > _outputEnd) { - _flushBuffer(); - } - _appendSingleEscape(escCode, _outputBuffer, _outputTail); - _outputTail += needLen; - } - } - - protected void _writeBinary(Base64Variant b64variant, byte[] input, int inputPtr, final int inputEnd) - throws IOException, JsonGenerationException - { - // Encoding is by chunks of 3 input, 4 output chars, so: - int safeInputEnd = inputEnd - 3; - // Let's also reserve room for possible (and quoted) lf char each round - int safeOutputEnd = _outputEnd - 6; - int chunksBeforeLF = b64variant.getMaxLineLength() >> 2; - - // Ok, first we loop through all full triplets of data: - while (inputPtr <= safeInputEnd) { - if (_outputTail > safeOutputEnd) { // need to flush - _flushBuffer(); - } - // First, mash 3 bytes into lsb of 32-bit int - int b24 = ((int) input[inputPtr++]) << 8; - b24 |= ((int) input[inputPtr++]) & 0xFF; - b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF); - _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail); - if (--chunksBeforeLF <= 0) { - // note: must quote in JSON value - _outputBuffer[_outputTail++] = '\\'; - _outputBuffer[_outputTail++] = 'n'; - chunksBeforeLF = b64variant.getMaxLineLength() >> 2; - } - } - - // And then we may have 1 or 2 leftover bytes to encode - int inputLeft = inputEnd - inputPtr; // 0, 1 or 2 - if (inputLeft > 0) { // yes, but do we have room for output? - if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but... - _flushBuffer(); - } - int b24 = ((int) input[inputPtr++]) << 16; - if (inputLeft == 2) { - b24 |= (((int) input[inputPtr++]) & 0xFF) << 8; - } - _outputTail = b64variant.encodeBase64Partial(b24, inputLeft, _outputBuffer, _outputTail); - } - } - - private final void _writeNull() throws IOException - { - if ((_outputTail + 4) >= _outputEnd) { - _flushBuffer(); - } - int ptr = _outputTail; - char[] buf = _outputBuffer; - buf[ptr] = 'n'; - buf[++ptr] = 'u'; - buf[++ptr] = 'l'; - buf[++ptr] = 'l'; - _outputTail = ptr+1; - } - - /** - * @param escCode Character code for escape sequence (\C); or -1 - * to indicate a generic (\\uXXXX) sequence. - */ - private void _writeSingleEscape(int escCode) - throws IOException - { - char[] buf = _entityBuffer; - if (buf == null) { - buf = new char[6]; - buf[0] = '\\'; - buf[2] = '0'; - buf[3] = '0'; - } - - if (escCode < 0) { // control char, value -(char + 1) - int value = -(escCode + 1); - buf[1] = 'u'; - // We know it's a control char, so only the last 2 chars are non-0 - buf[4] = HEX_CHARS[value >> 4]; - buf[5] = HEX_CHARS[value & 0xF]; - _writer.write(buf, 0, 6); - } else { - buf[1] = (char) escCode; - _writer.write(buf, 0, 2); - } - } - - private void _appendSingleEscape(int escCode, char[] buf, int ptr) - { - if (escCode < 0) { // control char, value -(char + 1) - int value = -(escCode + 1); - buf[ptr] = '\\'; - buf[++ptr] = 'u'; - // We know it's a control char, so only the last 2 chars are non-0 - buf[++ptr] = '0'; - buf[++ptr] = '0'; - buf[++ptr] = HEX_CHARS[value >> 4]; - buf[++ptr] = HEX_CHARS[value & 0xF]; - } else { - buf[ptr] = '\\'; - buf[ptr+1] = (char) escCode; - } - } - - protected final void _flushBuffer() throws IOException - { - int len = _outputTail - _outputHead; - if (len > 0) { - int offset = _outputHead; - _outputTail = _outputHead = 0; - _writer.write(_outputBuffer, offset, len); - } - } -} diff --git a/src/org/codehaus/jackson/io/BaseReader.java b/src/org/codehaus/jackson/io/BaseReader.java deleted file mode 100644 index b0fb6417be..0000000000 --- a/src/org/codehaus/jackson/io/BaseReader.java +++ /dev/null @@ -1,117 +0,0 @@ - -package org.codehaus.jackson.io; - -import java.io.*; - - -/** - * Simple basic class for optimized readers in this package; implements - * "cookie-cutter" methods that are used by all actual implementations. - */ -abstract class BaseReader - extends Reader -{ - /** - * JSON actually limits available Unicode range in the high end - * to the same as xml (to basically limit UTF-8 max byte sequence - * length to 4) - */ - final protected static int LAST_VALID_UNICODE_CHAR = 0x10FFFF; - - final protected static char NULL_CHAR = (char) 0; - final protected static char NULL_BYTE = (byte) 0; - - final protected IOContext mContext; - - protected InputStream mIn; - - protected byte[] mBuffer; - - protected int mPtr; - protected int mLength; - - /* - //////////////////////////////////////// - // Life-cycle - //////////////////////////////////////// - */ - - protected BaseReader(IOContext context, - InputStream in, byte[] buf, int ptr, int len) - { - mContext = context; - mIn = in; - mBuffer = buf; - mPtr = ptr; - mLength = len; - } - - /* - //////////////////////////////////////// - // Reader API - //////////////////////////////////////// - */ - - public void close() - throws IOException - { - InputStream in = mIn; - - if (in != null) { - mIn = null; - freeBuffers(); - in.close(); - } - } - - char[] mTmpBuf = null; - - /** - * Although this method is implemented by the base class, AND it should - * never be called by main code, let's still implement it bit more - * efficiently just in case - */ - public int read() - throws IOException - { - if (mTmpBuf == null) { - mTmpBuf = new char[1]; - } - if (read(mTmpBuf, 0, 1) < 1) { - return -1; - } - return mTmpBuf[0]; - } - - /* - //////////////////////////////////////// - // Internal/package methods: - //////////////////////////////////////// - */ - - /** - * This method should be called along with (or instead of) normal - * close. After calling this method, no further reads should be tried. - * Method will try to recycle read buffers (if any). - */ - public final void freeBuffers() - { - byte[] buf = mBuffer; - if (buf != null) { - mBuffer = null; - mContext.releaseReadIOBuffer(buf); - } - } - - protected void reportBounds(char[] cbuf, int start, int len) - throws IOException - { - throw new ArrayIndexOutOfBoundsException("read(buf,"+start+","+len+"), cbuf["+cbuf.length+"]"); - } - - protected void reportStrangeStream() - throws IOException - { - throw new IOException("Strange I/O stream, returned 0 bytes on read"); - } -} diff --git a/src/org/codehaus/jackson/io/IOContext.java b/src/org/codehaus/jackson/io/IOContext.java deleted file mode 100644 index ffac1eebf3..0000000000 --- a/src/org/codehaus/jackson/io/IOContext.java +++ /dev/null @@ -1,240 +0,0 @@ -package org.codehaus.jackson.io; - -import org.codehaus.jackson.JsonEncoding; -import org.codehaus.jackson.util.BufferRecycler; -import org.codehaus.jackson.util.TextBuffer; - -/** - * To limit number of configuration and state objects to pass, all - * contextual objects that need to be passed by the factory to - * readers and writers are combined under this object. One instance - * is created for each reader and writer. - */ -public final class IOContext -{ - /* - ////////////////////////////////////////////////////// - // Configuration - ////////////////////////////////////////////////////// - */ - - /** - * Reference to the source object, which can be used for displaying - * location information - */ - final Object _sourceRef; - - /** - * Encoding used by the underlying stream, if known. - */ - protected JsonEncoding _encoding; - - /** - * Flag that indicates whether underlying input/output source/target - * object is fully managed by the owner of this context (parser or - * generator). If true, it is, and is to be closed by parser/generator; - * if false, calling application has to do closing (unless auto-closing - * feature is enabled for the parser/generator in question; in which - * case it acts like the owner). - */ - protected final boolean _managedResource; - - /* - ////////////////////////////////////////////////////// - // Buffer handling, recycling - ////////////////////////////////////////////////////// - */ - - /** - * Recycler used for actual allocation/deallocation/reuse - */ - final BufferRecycler _bufferRecycler; - - /** - * Reference to the allocated I/O buffer for low-level input reading, - * if any allocated. - */ - protected byte[] _readIOBuffer = null; - - /** - * Reference to the allocated I/O buffer used for low-level - * encoding-related buffering. - */ - protected byte[] _writeEncodingBuffer = null; - - /** - * Reference to the buffer allocated for tokenization purposes, - * in which character input is read, and from which it can be - * further returned. - */ - protected char[] _tokenCBuffer = null; - - /** - * Reference to the buffer allocated for buffering it for - * output, before being encoded: generally this means concatenating - * output, then encoding when buffer fills up. - */ - protected char[] _concatCBuffer = null; - - /** - * Reference temporary buffer Parser instances need if calling - * app decides it wants to access name via 'getTextCharacters' method. - * Regular text buffer can not be used as it may contain textual - * representation of the value token. - */ - protected char[] _nameCopyBuffer = null; - - /* - ////////////////////////////////////////////////////// - // Life-cycle - ////////////////////////////////////////////////////// - */ - - public IOContext(BufferRecycler br, Object sourceRef, boolean managedResource) - { - _bufferRecycler = br; - _sourceRef = sourceRef; - _managedResource = managedResource; - } - - public void setEncoding(JsonEncoding enc) - { - _encoding = enc; - } - - /* - ////////////////////////////////////////////////////// - // Public API, accessors - ////////////////////////////////////////////////////// - */ - - public Object getSourceReference() { return _sourceRef; } - public JsonEncoding getEncoding() { return _encoding; } - public boolean isResourceManaged() { return _managedResource; } - - /* - ////////////////////////////////////////////////////// - // Public API, buffer management - ////////////////////////////////////////////////////// - */ - - public TextBuffer constructTextBuffer() - { - return new TextBuffer(_bufferRecycler); - } - - /** - *

- * Note: the method can only be called once during its life cycle. - * This is to protect against accidental sharing. - */ - public byte[] allocReadIOBuffer() - { - if (_readIOBuffer != null) { - throw new IllegalStateException("Trying to call allocReadIOBuffer() second time"); - } - _readIOBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.ByteBufferType.READ_IO_BUFFER); - return _readIOBuffer; - } - - public byte[] allocWriteEncodingBuffer() - { - if (_writeEncodingBuffer != null) { - throw new IllegalStateException("Trying to call allocWriteEncodingBuffer() second time"); - } - _writeEncodingBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.ByteBufferType.WRITE_ENCODING_BUFFER); - return _writeEncodingBuffer; - } - - public char[] allocTokenBuffer() - { - if (_tokenCBuffer != null) { - throw new IllegalStateException("Trying to call allocTokenBuffer() second time"); - } - _tokenCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CharBufferType.TOKEN_BUFFER); - return _tokenCBuffer; - } - - public char[] allocConcatBuffer() - { - if (_concatCBuffer != null) { - throw new IllegalStateException("Trying to call allocConcatBuffer() second time"); - } - _concatCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CharBufferType.CONCAT_BUFFER); - return _concatCBuffer; - } - - public char[] allocNameCopyBuffer(int minSize) - { - if (_nameCopyBuffer != null) { - throw new IllegalStateException("Trying to call allocNameCopyBuffer() second time"); - } - _nameCopyBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CharBufferType.NAME_COPY_BUFFER, minSize); - return _nameCopyBuffer; - } - - /** - * Method to call when all the processing buffers can be safely - * recycled. - */ - public void releaseReadIOBuffer(byte[] buf) - { - if (buf != null) { - /* Let's do sanity checks to ensure once-and-only-once release, - * as well as avoiding trying to release buffers not owned - */ - if (buf != _readIOBuffer) { - throw new IllegalArgumentException("Trying to release buffer not owned by the context"); - } - _readIOBuffer = null; - _bufferRecycler.releaseByteBuffer(BufferRecycler.ByteBufferType.READ_IO_BUFFER, buf); - } - } - - public void releaseWriteEncodingBuffer(byte[] buf) - { - if (buf != null) { - /* Let's do sanity checks to ensure once-and-only-once release, - * as well as avoiding trying to release buffers not owned - */ - if (buf != _writeEncodingBuffer) { - throw new IllegalArgumentException("Trying to release buffer not owned by the context"); - } - _writeEncodingBuffer = null; - _bufferRecycler.releaseByteBuffer(BufferRecycler.ByteBufferType.WRITE_ENCODING_BUFFER, buf); - } - } - - public void releaseTokenBuffer(char[] buf) - { - if (buf != null) { - if (buf != _tokenCBuffer) { - throw new IllegalArgumentException("Trying to release buffer not owned by the context"); - } - _tokenCBuffer = null; - _bufferRecycler.releaseCharBuffer(BufferRecycler.CharBufferType.TOKEN_BUFFER, buf); - } - } - - public void releaseConcatBuffer(char[] buf) - { - if (buf != null) { - if (buf != _concatCBuffer) { - throw new IllegalArgumentException("Trying to release buffer not owned by the context"); - } - _concatCBuffer = null; - _bufferRecycler.releaseCharBuffer(BufferRecycler.CharBufferType.CONCAT_BUFFER, buf); - } - } - - public void releaseNameCopyBuffer(char[] buf) - { - if (buf != null) { - if (buf != _nameCopyBuffer) { - throw new IllegalArgumentException("Trying to release buffer not owned by the context"); - } - _nameCopyBuffer = null; - _bufferRecycler.releaseCharBuffer(BufferRecycler.CharBufferType.NAME_COPY_BUFFER, buf); - } - } -} diff --git a/src/org/codehaus/jackson/io/MergedStream.java b/src/org/codehaus/jackson/io/MergedStream.java deleted file mode 100644 index 7ec3694d85..0000000000 --- a/src/org/codehaus/jackson/io/MergedStream.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.codehaus.jackson.io; - -import java.io.*; - -/** - * Simple {@link InputStream} implementation that is used to "unwind" some - * data previously read from an input stream; so that as long as some of - * that data remains, it's returned; but as long as it's read, we'll - * just use data from the underlying original stream. - * This is similar to {@link java.io.PushbackInputStream}, but here there's - * only one implicit pushback, when instance is constructed. - */ -public final class MergedStream - extends InputStream -{ - final protected IOContext _context; - - final InputStream _in; - - byte[] _buffer; - - int _ptr; - - final int _end; - - public MergedStream(IOContext context, - InputStream in, byte[] buf, int start, int end) - { - _context = context; - _in = in; - _buffer = buf; - _ptr = start; - _end = end; - } - - public int available() - throws IOException - { - if (_buffer != null) { - return _end - _ptr; - } - return _in.available(); - } - - public void close() - throws IOException - { - freeMergedBuffer(); - _in.close(); - } - - public void mark(int readlimit) - { - if (_buffer == null) { - _in.mark(readlimit); - } - } - - public boolean markSupported() - { - // Only supports marks past the initial rewindable section... - return (_buffer == null) && _in.markSupported(); - } - - public int read() - throws IOException - { - if (_buffer != null) { - int c = _buffer[_ptr++] & 0xFF; - if (_ptr >= _end) { - freeMergedBuffer(); - } - return c; - } - return _in.read(); - } - - public int read(byte[] b) - throws IOException - { - return read(b, 0, b.length); - } - - public int read(byte[] b, int off, int len) - throws IOException - { - if (_buffer != null) { - int avail = _end - _ptr; - if (len > avail) { - len = avail; - } - System.arraycopy(_buffer, _ptr, b, off, len); - _ptr += len; - if (_ptr >= _end) { - freeMergedBuffer(); - } - return len; - } - return _in.read(b, off, len); - } - - public void reset() - throws IOException - { - if (_buffer == null) { - _in.reset(); - } - } - - public long skip(long n) - throws IOException - { - long count = 0L; - - if (_buffer != null) { - int amount = _end - _ptr; - - if (amount > n) { // all in pushed back segment? - _ptr += (int) n; - return n; - } - freeMergedBuffer(); - count += amount; - n -= amount; - } - - if (n > 0) { - count += _in.skip(n); - } - return count; - } - - private void freeMergedBuffer() - { - byte[] buf = _buffer; - if (buf != null) { - _buffer = null; - _context.releaseReadIOBuffer(buf); - } - } -} diff --git a/src/org/codehaus/jackson/io/NumberInput.java b/src/org/codehaus/jackson/io/NumberInput.java deleted file mode 100644 index 9e3b2e4a17..0000000000 --- a/src/org/codehaus/jackson/io/NumberInput.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.codehaus.jackson.io; - -public final class NumberInput -{ - /** - * Constants needed for parsing longs from basic int parsing methods - */ - final static long L_BILLION = 1000000000; - - final static String MIN_LONG_STR_NO_SIGN = String.valueOf(Long.MIN_VALUE).substring(1); - final static String MAX_LONG_STR = String.valueOf(Long.MAX_VALUE); - - /** - * Fast method for parsing integers that are known to fit into - * regular 32-bit signed int type. This means that length is - * between 1 and 9 digits (inclusive) - *

- * Note: public to let unit tests call it - */ - public final static int parseInt(char[] digitChars, int offset, int len) - { - int num = digitChars[offset] - '0'; - len += offset; - // This looks ugly, but appears the fastest way: - if (++offset < len) { - num = (num * 10) + (digitChars[offset] - '0'); - if (++offset < len) { - num = (num * 10) + (digitChars[offset] - '0'); - if (++offset < len) { - num = (num * 10) + (digitChars[offset] - '0'); - if (++offset < len) { - num = (num * 10) + (digitChars[offset] - '0'); - if (++offset < len) { - num = (num * 10) + (digitChars[offset] - '0'); - if (++offset < len) { - num = (num * 10) + (digitChars[offset] - '0'); - if (++offset < len) { - num = (num * 10) + (digitChars[offset] - '0'); - if (++offset < len) { - num = (num * 10) + (digitChars[offset] - '0'); - } - } - } - } - } - } - } - } - return num; - } - - public final static long parseLong(char[] digitChars, int offset, int len) - { - // Note: caller must ensure length is [10, 18] - int len1 = len-9; - long val = parseInt(digitChars, offset, len1) * L_BILLION; - return val + (long) parseInt(digitChars, offset+len1, 9); - } - - /** - * Helper method for determining if given String representation of - * an integral number would fit in 64-bit Java long or not. - * Note that input String must NOT contain leading minus sign (even - * if 'negative' is set to true). - * - * @param negative Whether original number had a minus sign (which is - * NOT passed to this method) or not - */ - public final static boolean inLongRange(char[] digitChars, int offset, int len, - boolean negative) - { - String cmpStr = negative ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR; - int cmpLen = cmpStr.length(); - if (len < cmpLen) return true; - if (len > cmpLen) return false; - - for (int i = 0; i < cmpLen; ++i) { - if (digitChars[offset+i] > cmpStr.charAt(i)) { - return false; - } - } - return true; - } - - /** - * Similar to {@link #inLongRange(char[],int,int,boolean)}, but - * with String argument - * - * @param negative Whether original number had a minus sign (which is - * NOT passed to this method) or not - * - * @since 1.5.0 - */ - public final static boolean inLongRange(String numberStr, boolean negative) - { - String cmpStr = negative ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR; - int cmpLen = cmpStr.length(); - int actualLen = numberStr.length(); - if (actualLen < cmpLen) return true; - if (actualLen > cmpLen) return false; - - // could perhaps just use String.compareTo()? - for (int i = 0; i < cmpLen; ++i) { - if (numberStr.charAt(i) > cmpStr.charAt(i)) { - return false; - } - } - return true; - } -} diff --git a/src/org/codehaus/jackson/io/NumberOutput.java b/src/org/codehaus/jackson/io/NumberOutput.java deleted file mode 100644 index cfb3591def..0000000000 --- a/src/org/codehaus/jackson/io/NumberOutput.java +++ /dev/null @@ -1,269 +0,0 @@ -package org.codehaus.jackson.io; - -public final class NumberOutput -{ - private final static char NULL_CHAR = (char) 0; - - private static int MILLION = 1000000; - private static int BILLION = 1000000000; - private static long TEN_BILLION_L = 10000000000L; - private static long THOUSAND_L = 1000L; - - private static long MIN_INT_AS_LONG = (long) Integer.MIN_VALUE; - private static long MAX_INT_AS_LONG = (long) Integer.MAX_VALUE; - - final static String SMALLEST_LONG = String.valueOf(Long.MIN_VALUE); - - final static char[] LEADING_TRIPLETS = new char[4000]; - final static char[] FULL_TRIPLETS = new char[4000]; - static { - /* Let's fill it with NULLs for ignorable leading digits, - * and digit chars for others - */ - int ix = 0; - for (int i1 = 0; i1 < 10; ++i1) { - char f1 = (char) ('0' + i1); - char l1 = (i1 == 0) ? NULL_CHAR : f1; - for (int i2 = 0; i2 < 10; ++i2) { - char f2 = (char) ('0' + i2); - char l2 = (i1 == 0 && i2 == 0) ? NULL_CHAR : f2; - for (int i3 = 0; i3 < 10; ++i3) { - // Last is never to be empty - char f3 = (char) ('0' + i3); - LEADING_TRIPLETS[ix] = l1; - LEADING_TRIPLETS[ix+1] = l2; - LEADING_TRIPLETS[ix+2] = f3; - FULL_TRIPLETS[ix] = f1; - FULL_TRIPLETS[ix+1] = f2; - FULL_TRIPLETS[ix+2] = f3; - ix += 4; - } - } - } - } - - final static String[] sSmallIntStrs = new String[] { - "0","1","2","3","4","5","6","7","8","9","10" - }; - final static String[] sSmallIntStrs2 = new String[] { - "-1","-2","-3","-4","-5","-6","-7","-8","-9","-10" - }; - - /* - //////////////////////////////////////////////////// - // Efficient serialization methods using raw buffers - //////////////////////////////////////////////////// - */ - - /** - * @return Offset within buffer after outputting int - */ - public static int outputInt(int value, char[] buffer, int offset) - { - if (value < 0) { - if (value == Integer.MIN_VALUE) { - /* Special case: no matching positive value within range; - * let's then "upgrade" to long and output as such. - */ - return outputLong((long) value, buffer, offset); - } - buffer[offset++] = '-'; - value = -value; - } - - if (value < MILLION) { // at most 2 triplets... - if (value < 1000) { - if (value < 10) { - buffer[offset++] = (char) ('0' + value); - } else { - offset = outputLeadingTriplet(value, buffer, offset); - } - } else { - int thousands = value / 1000; - value -= (thousands * 1000); // == value % 1000 - offset = outputLeadingTriplet(thousands, buffer, offset); - offset = outputFullTriplet(value, buffer, offset); - } - return offset; - } - - // ok, all 3 triplets included - /* Let's first hand possible billions separately before - * handling 3 triplets. This is possible since we know we - * can have at most '2' as billion count. - */ - boolean hasBillions = (value >= BILLION); - if (hasBillions) { - value -= BILLION; - if (value >= BILLION) { - value -= BILLION; - buffer[offset++] = '2'; - } else { - buffer[offset++] = '1'; - } - } - int newValue = value / 1000; - int ones = (value - (newValue * 1000)); // == value % 1000 - value = newValue; - newValue /= 1000; - int thousands = (value - (newValue * 1000)); - - // value now has millions, which have 1, 2 or 3 digits - if (hasBillions) { - offset = outputFullTriplet(newValue, buffer, offset); - } else { - offset = outputLeadingTriplet(newValue, buffer, offset); - } - offset = outputFullTriplet(thousands, buffer, offset); - offset = outputFullTriplet(ones, buffer, offset); - return offset; - } - - /** - * @return Offset within buffer after outputting int - */ - public static int outputLong(long value, char[] buffer, int offset) - { - // First: does it actually fit in an int? - if (value < 0L) { - /* MIN_INT is actually printed as long, just because its - * negation is not an int but long - */ - if (value > MIN_INT_AS_LONG) { - return outputInt((int) value, buffer, offset); - } - if (value == Long.MIN_VALUE) { - // Special case: no matching positive value within range - int len = SMALLEST_LONG.length(); - SMALLEST_LONG.getChars(0, len, buffer, offset); - return (offset + len); - } - buffer[offset++] = '-'; - value = -value; - } else { - if (value <= MAX_INT_AS_LONG) { - return outputInt((int) value, buffer, offset); - } - } - - /* Ok: real long print. Need to first figure out length - * in characters, and then print in from end to beginning - */ - int origOffset = offset; - offset += calcLongStrLength(value); - int ptr = offset; - - // First, with long arithmetics: - while (value > MAX_INT_AS_LONG) { // full triplet - ptr -= 3; - long newValue = value / THOUSAND_L; - int triplet = (int) (value - newValue * THOUSAND_L); - outputFullTriplet(triplet, buffer, ptr); - value = newValue; - } - // Then with int arithmetics: - int ivalue = (int) value; - while (ivalue >= 1000) { // still full triplet - ptr -= 3; - int newValue = ivalue / 1000; - int triplet = ivalue - (newValue * 1000); - outputFullTriplet(triplet, buffer, ptr); - ivalue = newValue; - } - // And finally, if anything remains, partial triplet - outputLeadingTriplet(ivalue, buffer, origOffset); - - return offset; - } - - /* - //////////////////////////////////////////////////// - // Secondary convenience serialization methods - //////////////////////////////////////////////////// - */ - - /* !!! 05-Aug-2008, tatus: Any ways to further optimize - * these? (or need: only called by diagnostics methods?) - */ - - public static String toString(int value) - { - // Lookup table for small values - if (value < sSmallIntStrs.length) { - if (value >= 0) { - return sSmallIntStrs[value]; - } - int v2 = -value - 1; - if (v2 < sSmallIntStrs2.length) { - return sSmallIntStrs2[v2]; - } - } - return Integer.toString(value); - } - - public static String toString(long value) - { - if (value <= Integer.MAX_VALUE && - value >= Integer.MIN_VALUE) { - return toString((int) value); - } - return Long.toString(value); - } - - public static String toString(double value) - { - return Double.toString(value); - } - - /* - //////////////////////////////////////// - // Internal methods - //////////////////////////////////////// - */ - - private static int outputLeadingTriplet(int triplet, char[] buffer, int offset) - { - int digitOffset = (triplet << 2); - char c = LEADING_TRIPLETS[digitOffset++]; - if (c != NULL_CHAR) { - buffer[offset++] = c; - } - c = LEADING_TRIPLETS[digitOffset++]; - if (c != NULL_CHAR) { - buffer[offset++] = c; - } - // Last is required to be non-empty - buffer[offset++] = LEADING_TRIPLETS[digitOffset]; - return offset; - } - - private static int outputFullTriplet(int triplet, char[] buffer, int offset) - { - int digitOffset = (triplet << 2); - buffer[offset++] = FULL_TRIPLETS[digitOffset++]; - buffer[offset++] = FULL_TRIPLETS[digitOffset++]; - buffer[offset++] = FULL_TRIPLETS[digitOffset]; - return offset; - } - - /** - *

- * Pre-conditions: posValue is positive, and larger than - * Integer.MAX_VALUE (about 2 billions). - */ - private static int calcLongStrLength(long posValue) - { - int len = 10; - long comp = TEN_BILLION_L; - - // 19 is longest, need to worry about overflow - while (posValue >= comp) { - if (len == 19) { - break; - } - ++len; - comp = (comp << 3) + (comp << 1); // 10x - } - return len; - } -} diff --git a/src/org/codehaus/jackson/io/SegmentedStringWriter.java b/src/org/codehaus/jackson/io/SegmentedStringWriter.java deleted file mode 100644 index a8c24bc119..0000000000 --- a/src/org/codehaus/jackson/io/SegmentedStringWriter.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.codehaus.jackson.io; - -import java.io.*; - -import org.codehaus.jackson.util.BufferRecycler; -import org.codehaus.jackson.util.TextBuffer; - -/** - * Efficient alternative to {@link StringWriter}, based on using segmented - * internal buffer. Initial input buffer is also recyclable. - *

- * This class is most useful when serializing JSON content as a String: - * if so, instance of this class can be given as the writer to - * JsonGenerator. - * - * @since 1.3 - */ -public final class SegmentedStringWriter - extends Writer -{ - final TextBuffer _buffer; - - public SegmentedStringWriter(BufferRecycler br) - { - super(); - _buffer = new TextBuffer(br); - } - - /* - ///////////////////////////////////////////////////////////// - // java.io.Writer implementation - ///////////////////////////////////////////////////////////// - */ - - @Override - public Writer append(char c) - { - write(c); - return this; - } - - @Override - public Writer append(CharSequence csq) - { - String str = csq.toString(); - _buffer.append(str, 0, str.length()); - return this; - } - - @Override - public Writer append(CharSequence csq, int start, int end) - { - String str = csq.subSequence(start, end).toString(); - _buffer.append(str, 0, str.length()); - return this; - } - - @Override public void close() { } // NOP - - @Override public void flush() { } // NOP - - @Override - public void write(char[] cbuf) { - _buffer.append(cbuf, 0, cbuf.length); - } - - @Override - public void write(char[] cbuf, int off, int len) { - _buffer.append(cbuf, off, len); - } - - @Override - public void write(int c) { - _buffer.append((char) c); - } - - @Override - public void write(String str) { _buffer.append(str, 0, str.length()); } - - @Override - public void write(String str, int off, int len) { - _buffer.append(str, 0, str.length()); - } - - /* - ///////////////////////////////////////////////////////////// - // Extended API - ///////////////////////////////////////////////////////////// - */ - - /** - * Main access method that will construct a String that contains - * all the contents, release all internal buffers we may have, - * and return result String. - * Note that the method is not idempotent -- if called second time, - * will just return an empty String. - */ - public String getAndClear() - { - String result = _buffer.contentsAsString(); - _buffer.releaseBuffers(); - return result; - } -} diff --git a/src/org/codehaus/jackson/io/UTF32Reader.java b/src/org/codehaus/jackson/io/UTF32Reader.java deleted file mode 100644 index 4e7d83baec..0000000000 --- a/src/org/codehaus/jackson/io/UTF32Reader.java +++ /dev/null @@ -1,214 +0,0 @@ -package org.codehaus.jackson.io; - -import java.io.*; - - -/** - * Since JDK does not come with UTF-32/UCS-4, let's implement a simple - * decoder to use. - */ -public final class UTF32Reader - extends BaseReader -{ - final boolean mBigEndian; - - /** - * Although input is fine with full Unicode set, Java still uses - * 16-bit chars, so we may have to split high-order chars into - * surrogate pairs. - */ - char mSurrogate = NULL_CHAR; - - /** - * Total read character count; used for error reporting purposes - */ - int mCharCount = 0; - - /** - * Total read byte count; used for error reporting purposes - */ - int mByteCount = 0; - - /* - //////////////////////////////////////// - // Life-cycle - //////////////////////////////////////// - */ - - public UTF32Reader(IOContext ctxt, - InputStream in, byte[] buf, int ptr, int len, - boolean isBigEndian) - { - super(ctxt, in, buf, ptr, len); - mBigEndian = isBigEndian; - } - - /* - //////////////////////////////////////// - // Public API - //////////////////////////////////////// - */ - - @Override - public int read(char[] cbuf, int start, int len) - throws IOException - { - // Already EOF? - if (mBuffer == null) { - return -1; - } - if (len < 1) { - return len; - } - // Let's then ensure there's enough room... - if (start < 0 || (start+len) > cbuf.length) { - reportBounds(cbuf, start, len); - } - - len += start; - int outPtr = start; - - // Ok, first; do we have a surrogate from last round? - if (mSurrogate != NULL_CHAR) { - cbuf[outPtr++] = mSurrogate; - mSurrogate = NULL_CHAR; - // No need to load more, already got one char - } else { - /* Note: we'll try to avoid blocking as much as possible. As a - * result, we only need to get 4 bytes for a full char. - */ - int left = (mLength - mPtr); - if (left < 4) { - if (!loadMore(left)) { // (legal) EOF? - return -1; - } - } - } - - main_loop: - while (outPtr < len) { - int ptr = mPtr; - int ch; - - if (mBigEndian) { - ch = (mBuffer[ptr] << 24) | ((mBuffer[ptr+1] & 0xFF) << 16) - | ((mBuffer[ptr+2] & 0xFF) << 8) | (mBuffer[ptr+3] & 0xFF); - } else { - ch = (mBuffer[ptr] & 0xFF) | ((mBuffer[ptr+1] & 0xFF) << 8) - | ((mBuffer[ptr+2] & 0xFF) << 16) | (mBuffer[ptr+3] << 24); - } - mPtr += 4; - - // Does it need to be split to surrogates? - // (also, we can and need to verify illegal chars) - if (ch > 0xFFFF) { // need to split into surrogates? - if (ch > LAST_VALID_UNICODE_CHAR) { - reportInvalid(ch, outPtr-start, - "(above "+Integer.toHexString(LAST_VALID_UNICODE_CHAR)+") "); - } - ch -= 0x10000; // to normalize it starting with 0x0 - cbuf[outPtr++] = (char) (0xD800 + (ch >> 10)); - // hmmh. can this ever be 0? (not legal, at least?) - ch = (0xDC00 | (ch & 0x03FF)); - // Room for second part? - if (outPtr >= len) { // nope - mSurrogate = (char) ch; - break main_loop; - } - } - cbuf[outPtr++] = (char) ch; - if (mPtr >= mLength) { - break main_loop; - } - } - - len = outPtr - start; - mCharCount += len; - return len; - } - - /* - //////////////////////////////////////// - // Internal methods - //////////////////////////////////////// - */ - - private void reportUnexpectedEOF(int gotBytes, int needed) - throws IOException - { - int bytePos = mByteCount + gotBytes; - int charPos = mCharCount; - - throw new CharConversionException("Unexpected EOF in the middle of a 4-byte UTF-32 char: got " - +gotBytes+", needed "+needed - +", at char #"+charPos+", byte #"+bytePos+")"); - } - - private void reportInvalid(int value, int offset, String msg) - throws IOException - { - int bytePos = mByteCount + mPtr - 1; - int charPos = mCharCount + offset; - - throw new CharConversionException("Invalid UTF-32 character 0x" - +Integer.toHexString(value) - +msg+" at char #"+charPos+", byte #"+bytePos+")"); - } - - /** - * @param available Number of "unused" bytes in the input buffer - * - * @return True, if enough bytes were read to allow decoding of at least - * one full character; false if EOF was encountered instead. - */ - private boolean loadMore(int available) - throws IOException - { - mByteCount += (mLength - available); - - // Bytes that need to be moved to the beginning of buffer? - if (available > 0) { - if (mPtr > 0) { - for (int i = 0; i < available; ++i) { - mBuffer[i] = mBuffer[mPtr+i]; - } - mPtr = 0; - } - mLength = available; - } else { - /* Ok; here we can actually reasonably expect an EOF, - * so let's do a separate read right away: - */ - mPtr = 0; - int count = mIn.read(mBuffer); - if (count < 1) { - mLength = 0; - if (count < 0) { // -1 - freeBuffers(); // to help GC? - return false; - } - // 0 count is no good; let's err out - reportStrangeStream(); - } - mLength = count; - } - - /* Need at least 4 bytes; if we don't get that many, it's an - * error. - */ - while (mLength < 4) { - int count = mIn.read(mBuffer, mLength, mBuffer.length - mLength); - if (count < 1) { - if (count < 0) { // -1, EOF... no good! - freeBuffers(); // to help GC? - reportUnexpectedEOF(mLength, 4); - } - // 0 count is no good; let's err out - reportStrangeStream(); - } - mLength += count; - } - return true; - } -} - diff --git a/src/org/codehaus/jackson/io/UTF8Writer.java b/src/org/codehaus/jackson/io/UTF8Writer.java deleted file mode 100644 index c874f1ad9c..0000000000 --- a/src/org/codehaus/jackson/io/UTF8Writer.java +++ /dev/null @@ -1,385 +0,0 @@ -package org.codehaus.jackson.io; - -import java.io.*; - - -public final class UTF8Writer - extends Writer -{ - final static int SURR1_FIRST = 0xD800; - final static int SURR1_LAST = 0xDBFF; - final static int SURR2_FIRST = 0xDC00; - final static int SURR2_LAST = 0xDFFF; - - final protected IOContext mContext; - - OutputStream mOut; - - byte[] mOutBuffer; - - final int mOutBufferLast; - - int mOutPtr; - - /** - * When outputting chars from BMP, surrogate pairs need to be coalesced. - * To do this, both pairs must be known first; and since it is possible - * pairs may be split, we need temporary storage for the first half - */ - int mSurrogate = 0; - - public UTF8Writer(IOContext ctxt, OutputStream out) - { - mContext = ctxt; - mOut = out; - - mOutBuffer = ctxt.allocWriteEncodingBuffer(); - /* Max. expansion for a single char (in unmodified UTF-8) is - * 4 bytes (or 3 depending on how you view it -- 4 when recombining - * surrogate pairs) - */ - mOutBufferLast = mOutBuffer.length - 4; - mOutPtr = 0; - } - - @Override - public Writer append(char c) - throws IOException - { - write(c); - return this; - } - - @Override - public void close() - throws IOException - { - if (mOut != null) { - if (mOutPtr > 0) { - mOut.write(mOutBuffer, 0, mOutPtr); - mOutPtr = 0; - } - OutputStream out = mOut; - mOut = null; - - byte[] buf = mOutBuffer; - if (buf != null) { - mOutBuffer = null; - mContext.releaseWriteEncodingBuffer(buf); - } - - out.close(); - - /* Let's 'flush' orphan surrogate, no matter what; but only - * after cleanly closing everything else. - */ - int code = mSurrogate; - mSurrogate = 0; - if (code > 0) { - throwIllegal(code); - } - } - } - - @Override - public void flush() - throws IOException - { - if (mOutPtr > 0) { - mOut.write(mOutBuffer, 0, mOutPtr); - mOutPtr = 0; - } - mOut.flush(); - } - - @Override - public void write(char[] cbuf) - throws IOException - { - write(cbuf, 0, cbuf.length); - } - - @Override - public void write(char[] cbuf, int off, int len) - throws IOException - { - if (len < 2) { - if (len == 1) { - write(cbuf[off]); - } - return; - } - - // First: do we have a leftover surrogate to deal with? - if (mSurrogate > 0) { - char second = cbuf[off++]; - --len; - write(convertSurrogate(second)); - // will have at least one more char - } - - int outPtr = mOutPtr; - byte[] outBuf = mOutBuffer; - int outBufLast = mOutBufferLast; // has 4 'spare' bytes - - // All right; can just loop it nice and easy now: - len += off; // len will now be the end of input buffer - - output_loop: - for (; off < len; ) { - /* First, let's ensure we can output at least 4 bytes - * (longest UTF-8 encoded codepoint): - */ - if (outPtr >= outBufLast) { - mOut.write(outBuf, 0, outPtr); - outPtr = 0; - } - - int c = cbuf[off++]; - // And then see if we have an Ascii char: - if (c < 0x80) { // If so, can do a tight inner loop: - outBuf[outPtr++] = (byte)c; - // Let's calc how many ascii chars we can copy at most: - int maxInCount = (len - off); - int maxOutCount = (outBufLast - outPtr); - - if (maxInCount > maxOutCount) { - maxInCount = maxOutCount; - } - maxInCount += off; - ascii_loop: - while (true) { - if (off >= maxInCount) { // done with max. ascii seq - continue output_loop; - } - c = cbuf[off++]; - if (c >= 0x80) { - break ascii_loop; - } - outBuf[outPtr++] = (byte) c; - } - } - - // Nope, multi-byte: - if (c < 0x800) { // 2-byte - outBuf[outPtr++] = (byte) (0xc0 | (c >> 6)); - outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); - } else { // 3 or 4 bytes - // Surrogates? - if (c < SURR1_FIRST || c > SURR2_LAST) { - outBuf[outPtr++] = (byte) (0xe0 | (c >> 12)); - outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); - outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); - continue; - } - // Yup, a surrogate: - if (c > SURR1_LAST) { // must be from first range - mOutPtr = outPtr; - throwIllegal(c); - } - mSurrogate = c; - // and if so, followed by another from next range - if (off >= len) { // unless we hit the end? - break; - } - c = convertSurrogate(cbuf[off++]); - if (c > 0x10FFFF) { // illegal in JSON as well as in XML - mOutPtr = outPtr; - throwIllegal(c); - } - outBuf[outPtr++] = (byte) (0xf0 | (c >> 18)); - outBuf[outPtr++] = (byte) (0x80 | ((c >> 12) & 0x3f)); - outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); - outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); - } - } - mOutPtr = outPtr; - } - - @Override - public void write(int c) throws IOException - { - // First; do we have a left over surrogate? - if (mSurrogate > 0) { - c = convertSurrogate(c); - // If not, do we start with a surrogate? - } else if (c >= SURR1_FIRST && c <= SURR2_LAST) { - // Illegal to get second part without first: - if (c > SURR1_LAST) { - throwIllegal(c); - } - // First part just needs to be held for now - mSurrogate = c; - return; - } - - if (mOutPtr >= mOutBufferLast) { // let's require enough room, first - mOut.write(mOutBuffer, 0, mOutPtr); - mOutPtr = 0; - } - - if (c < 0x80) { // ascii - mOutBuffer[mOutPtr++] = (byte) c; - } else { - int ptr = mOutPtr; - if (c < 0x800) { // 2-byte - mOutBuffer[ptr++] = (byte) (0xc0 | (c >> 6)); - mOutBuffer[ptr++] = (byte) (0x80 | (c & 0x3f)); - } else if (c <= 0xFFFF) { // 3 bytes - mOutBuffer[ptr++] = (byte) (0xe0 | (c >> 12)); - mOutBuffer[ptr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); - mOutBuffer[ptr++] = (byte) (0x80 | (c & 0x3f)); - } else { // 4 bytes - if (c > 0x10FFFF) { // illegal - throwIllegal(c); - } - mOutBuffer[ptr++] = (byte) (0xf0 | (c >> 18)); - mOutBuffer[ptr++] = (byte) (0x80 | ((c >> 12) & 0x3f)); - mOutBuffer[ptr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); - mOutBuffer[ptr++] = (byte) (0x80 | (c & 0x3f)); - } - mOutPtr = ptr; - } - } - - @Override - public void write(String str) throws IOException - { - write(str, 0, str.length()); - } - - @Override - public void write(String str, int off, int len) throws IOException - { - if (len < 2) { - if (len == 1) { - write(str.charAt(off)); - } - return; - } - - // First: do we have a leftover surrogate to deal with? - if (mSurrogate > 0) { - char second = str.charAt(off++); - --len; - write(convertSurrogate(second)); - // will have at least one more char (case of 1 char was checked earlier on) - } - - int outPtr = mOutPtr; - byte[] outBuf = mOutBuffer; - int outBufLast = mOutBufferLast; // has 4 'spare' bytes - - // All right; can just loop it nice and easy now: - len += off; // len will now be the end of input buffer - - output_loop: - for (; off < len; ) { - /* First, let's ensure we can output at least 4 bytes - * (longest UTF-8 encoded codepoint): - */ - if (outPtr >= outBufLast) { - mOut.write(outBuf, 0, outPtr); - outPtr = 0; - } - - int c = str.charAt(off++); - // And then see if we have an Ascii char: - if (c < 0x80) { // If so, can do a tight inner loop: - outBuf[outPtr++] = (byte)c; - // Let's calc how many ascii chars we can copy at most: - int maxInCount = (len - off); - int maxOutCount = (outBufLast - outPtr); - - if (maxInCount > maxOutCount) { - maxInCount = maxOutCount; - } - maxInCount += off; - ascii_loop: - while (true) { - if (off >= maxInCount) { // done with max. ascii seq - continue output_loop; - } - c = str.charAt(off++); - if (c >= 0x80) { - break ascii_loop; - } - outBuf[outPtr++] = (byte) c; - } - } - - // Nope, multi-byte: - if (c < 0x800) { // 2-byte - outBuf[outPtr++] = (byte) (0xc0 | (c >> 6)); - outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); - } else { // 3 or 4 bytes - // Surrogates? - if (c < SURR1_FIRST || c > SURR2_LAST) { - outBuf[outPtr++] = (byte) (0xe0 | (c >> 12)); - outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); - outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); - continue; - } - // Yup, a surrogate: - if (c > SURR1_LAST) { // must be from first range - mOutPtr = outPtr; - throwIllegal(c); - } - mSurrogate = c; - // and if so, followed by another from next range - if (off >= len) { // unless we hit the end? - break; - } - c = convertSurrogate(str.charAt(off++)); - if (c > 0x10FFFF) { // illegal, as per RFC 4627 - mOutPtr = outPtr; - throwIllegal(c); - } - outBuf[outPtr++] = (byte) (0xf0 | (c >> 18)); - outBuf[outPtr++] = (byte) (0x80 | ((c >> 12) & 0x3f)); - outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); - outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); - } - } - mOutPtr = outPtr; - } - - /* - //////////////////////////////////////////////////////////// - // Internal methods - //////////////////////////////////////////////////////////// - */ - - /** - * Method called to calculate UTF codepoint, from a surrogate pair. - */ - private int convertSurrogate(int secondPart) - throws IOException - { - int firstPart = mSurrogate; - mSurrogate = 0; - - // Ok, then, is the second part valid? - if (secondPart < SURR2_FIRST || secondPart > SURR2_LAST) { - throw new IOException("Broken surrogate pair: first char 0x"+Integer.toHexString(firstPart)+", second 0x"+Integer.toHexString(secondPart)+"; illegal combination"); - } - return 0x10000 + ((firstPart - SURR1_FIRST) << 10) + (secondPart - SURR2_FIRST); - } - - private void throwIllegal(int code) - throws IOException - { - if (code > 0x10FFFF) { // over max? - throw new IOException("Illegal character point (0x"+Integer.toHexString(code)+") to output; max is 0x10FFFF as per RFC 4627"); - } - if (code >= SURR1_FIRST) { - if (code <= SURR1_LAST) { // Unmatched first part (closing without second part?) - throw new IOException("Unmatched first part of surrogate pair (0x"+Integer.toHexString(code)+")"); - } - throw new IOException("Unmatched second part of surrogate pair (0x"+Integer.toHexString(code)+")"); - } - - // should we ever get this? - throw new IOException("Illegal character point (0x"+Integer.toHexString(code)+") to output"); - } -} diff --git a/src/org/codehaus/jackson/sym/BytesToNameCanonicalizer.java b/src/org/codehaus/jackson/sym/BytesToNameCanonicalizer.java deleted file mode 100644 index a3ec715e75..0000000000 --- a/src/org/codehaus/jackson/sym/BytesToNameCanonicalizer.java +++ /dev/null @@ -1,958 +0,0 @@ -package org.codehaus.jackson.sym; - -import java.util.Arrays; - -import org.codehaus.jackson.util.InternCache; - -/** - * This class is basically a caching symbol table implementation used for - * canonicalizing {@link Name}s, constructed directly from a byte-based - * input source. - * - * @author Tatu Saloranta - */ -public final class BytesToNameCanonicalizer -{ - protected static final int DEFAULT_TABLE_SIZE = 64; - - /** - * Let's not expand symbol tables past some maximum size; - * this should protected against OOMEs caused by large documents - * with uniquer (~= random) names. - * - * @since 1.5 - */ - protected static final int MAX_TABLE_SIZE = 0x10000; // 64k entries == 256k mem - - /** - * Let's only share reasonably sized symbol tables. Max size set to 3/4 of 16k; - * this corresponds to 64k main hash index. This should allow for enough distinct - * names for almost any case. - */ - final static int MAX_ENTRIES_FOR_REUSE = 6000; - - final static int MIN_HASH_SIZE = 16; - - final static int INITIAL_COLLISION_LEN = 32; - - /** - * Bucket index is 8 bits, and value 0 is reserved to represent - * 'empty' status. - */ - final static int LAST_VALID_BUCKET = 0xFE; - - /* - /**************************************************** - /* Linkage, needed for merging symbol tables - /**************************************************** - */ - - final BytesToNameCanonicalizer _parent; - - /* - /**************************************************** - /* Main table state - /**************************************************** - */ - - /** - * Whether canonial symbol Strings are to be intern()ed before added - * to the table or not - */ - final boolean _intern; - - // // // First, global information - - /** - * Total number of Names in the symbol table - */ - private int _count; - - // // // Then information regarding primary hash array and its - // // // matching Name array - - /** - * Mask used to truncate 32-bit hash value to current hash array - * size; essentially, hash array size - 1 (since hash array sizes - * are 2^N). - */ - private int _mainHashMask; - - /** - * Array of 2^N size, which contains combination - * of 24-bits of hash (0 to indicate 'empty' slot), - * and 8-bit collision bucket index (0 to indicate empty - * collision bucket chain; otherwise subtract one from index) - */ - private int[] _mainHash; - - /** - * Array that contains Name instances matching - * entries in _mainHash. Contains nulls for unused - * entries. - */ - private Name[] _mainNames; - - // // // Then the collision/spill-over area info - - /** - * Array of heads of collision bucket chains; size dynamically - */ - private Bucket[] _collList; - - /** - * Total number of Names in collision buckets (included in - * _count along with primary entries) - */ - private int _collCount; - - /** - * Index of the first unused collision bucket entry (== size of - * the used portion of collision list): less than - * or equal to 0xFF (255), since max number of entries is 255 - * (8-bit, minus 0 used as 'empty' marker) - */ - private int _collEnd; - - // // // Info regarding pending rehashing... - - /** - * This flag is set if, after adding a new entry, it is deemed - * that a rehash is warranted if any more entries are to be added. - */ - private transient boolean _needRehash; - - /* - /**************************************************** - /* Sharing, versioning - /**************************************************** - */ - - // // // Which of the buffers may be shared (and are copy-on-write)? - - /** - * Flag that indicates whether underlying data structures for - * the main hash area are shared or not. If they are, then they - * need to be handled in copy-on-write way, i.e. if they need - * to be modified, a copy needs to be made first; at this point - * it will not be shared any more, and can be modified. - *

- * This flag needs to be checked both when adding new main entries, - * and when adding new collision list queues (i.e. creating a new - * collision list head entry) - */ - private boolean _mainHashShared; - - private boolean _mainNamesShared; - - /** - * Flag that indicates whether underlying data structures for - * the collision list are shared or not. If they are, then they - * need to be handled in copy-on-write way, i.e. if they need - * to be modified, a copy needs to be made first; at this point - * it will not be shared any more, and can be modified. - *

- * This flag needs to be checked when adding new collision entries. - */ - private boolean _collListShared; - - /* - /**************************************************** - /* Construction, merging - /**************************************************** - */ - - public static BytesToNameCanonicalizer createRoot() - { - return new BytesToNameCanonicalizer(DEFAULT_TABLE_SIZE, true); - } - - /** - * @param intern Whether canonical symbol Strings should be interned - * or not - */ - public synchronized BytesToNameCanonicalizer makeChild(boolean canonicalize, - boolean intern) - { - return new BytesToNameCanonicalizer(this, intern); - } - - /** - * Method called by the using code to indicate it is done - * with this instance. This lets instance merge accumulated - * changes into parent (if need be), safely and efficiently, - * and without calling code having to know about parent - * information - */ - public void release() - { - if (maybeDirty() && _parent != null) { - _parent.mergeChild(this); - /* Let's also mark this instance as dirty, so that just in - * case release was too early, there's no corruption - * of possibly shared data. - */ - markAsShared(); - } - } - - private BytesToNameCanonicalizer(int hashSize, boolean intern) - { - _parent = null; - _intern = intern; - /* Sanity check: let's now allow hash sizes below certain - * min. value - */ - if (hashSize < MIN_HASH_SIZE) { - hashSize = MIN_HASH_SIZE; - } else { - /* Also; size must be 2^N; otherwise hash algorithm won't - * work... so let's just pad it up, if so - */ - if ((hashSize & (hashSize - 1)) != 0) { // only true if it's 2^N - int curr = MIN_HASH_SIZE; - while (curr < hashSize) { - curr += curr; - } - hashSize = curr; - } - } - initTables(hashSize); - } - - /** - * Constructor used when creating a child instance - */ - private BytesToNameCanonicalizer(BytesToNameCanonicalizer parent, boolean intern) - { - _parent = parent; - _intern = intern; - - // First, let's copy the state as is: - _count = parent._count; - _mainHashMask = parent._mainHashMask; - _mainHash = parent._mainHash; - _mainNames = parent._mainNames; - _collList = parent._collList; - _collCount = parent._collCount; - _collEnd = parent._collEnd; - _needRehash = false; - // And consider all shared, so far: - _mainHashShared = true; - _mainNamesShared = true; - _collListShared = true; - } - - private void initTables(int hashSize) - { - _count = 0; - _mainHash = new int[hashSize]; - _mainNames = new Name[hashSize]; - _mainHashShared = false; - _mainNamesShared = false; - _mainHashMask = hashSize - 1; - - _collListShared = true; // just since it'll need to be allocated - _collList = null; - _collEnd = 0; - - _needRehash = false; - } - - private synchronized void mergeChild(BytesToNameCanonicalizer child) - { - // Only makes sense if child has more entries - int childCount = child._count; - if (childCount <= _count) { - return; - } - - /* One caveat: let's try to avoid problems with - * degenerate cases of documents with generated "random" - * names: for these, symbol tables would bloat indefinitely. - * One way to do this is to just purge tables if they grow - * too large, and that's what we'll do here. - */ - if (child.size() > MAX_ENTRIES_FOR_REUSE) { - /* Should there be a way to get notified about this - * event, to log it or such? (as it's somewhat abnormal - * thing to happen) - */ - // At any rate, need to clean up the tables, then: - initTables(DEFAULT_TABLE_SIZE); - } else { - _count = child._count; - _mainHash = child._mainHash; - _mainNames = child._mainNames; - _mainHashShared = true; // shouldn't matter for parent - _mainNamesShared = true; // - "" - - _mainHashMask = child._mainHashMask; - _collList = child._collList; - _collCount = child._collCount; - _collEnd = child._collEnd; - } - } - - private void markAsShared() - { - _mainHashShared = true; - _mainNamesShared = true; - _collListShared = true; - } - - /* - /**************************************************** - /* API, accessors - /**************************************************** - */ - - public int size() { return _count; } - - /** - * Method called to check to quickly see if a child symbol table - * may have gotten additional entries. Used for checking to see - * if a child table should be merged into shared table. - */ - public boolean maybeDirty() - { - return !_mainHashShared; - } - - public static Name getEmptyName() - { - return Name1.getEmptyName(); - } - - /** - * Finds and returns name matching the specified symbol, if such - * name already exists in the table. - * If not, will return null. - *

- * Note: separate methods to optimize common case of - * short element/attribute names (4 or less ascii characters) - * - * @param firstQuad int32 containing first 4 bytes of the name; - * if the whole name less than 4 bytes, padded with zero bytes - * in front (zero MSBs, ie. right aligned) - * - * @return Name matching the symbol passed (or constructed for - * it) - */ - public Name findName(int firstQuad) - { - int hash = calcHash(firstQuad); - int ix = (hash & _mainHashMask); - int val = _mainHash[ix]; - - /* High 24 bits of the value are low 24 bits of hash (low 8 bits - * are bucket index)... match? - */ - if ((((val >> 8) ^ hash) << 8) == 0) { // match - // Ok, but do we have an actual match? - Name name = _mainNames[ix]; - if (name == null) { // main slot empty; can't find - return null; - } - if (name.equals(firstQuad)) { - return name; - } - } else if (val == 0) { // empty slot? no match - return null; - } - // Maybe a spill-over? - val &= 0xFF; - if (val > 0) { // 0 means 'empty' - val -= 1; // to convert from 1-based to 0... - Bucket bucket = _collList[val]; - if (bucket != null) { - return bucket.find(hash, firstQuad, 0); - } - } - // Nope, no match whatsoever - return null; - } - - /** - * Finds and returns name matching the specified symbol, if such - * name already exists in the table. - * If not, will return null. - *

- * Note: separate methods to optimize common case of relatively - * short element/attribute names (8 or less ascii characters) - * - * @param firstQuad int32 containing first 4 bytes of the name. - * @param secondQuad int32 containing bytes 5 through 8 of the - * name; if less than 8 bytes, padded with up to 3 zero bytes - * in front (zero MSBs, ie. right aligned) - * - * @return Name matching the symbol passed (or constructed for - * it) - */ - public Name findName(int firstQuad, int secondQuad) - { - int hash = calcHash(firstQuad, secondQuad); - int ix = (hash & _mainHashMask); - int val = _mainHash[ix]; - - /* High 24 bits of the value are low 24 bits of hash (low 8 bits - * are bucket index)... match? - */ - if ((((val >> 8) ^ hash) << 8) == 0) { // match - // Ok, but do we have an actual match? - Name name = _mainNames[ix]; - if (name == null) { // main slot empty; can't find - return null; - } - if (name.equals(firstQuad, secondQuad)) { - return name; - } - } else if (val == 0) { // empty slot? no match - return null; - } - // Maybe a spill-over? - val &= 0xFF; - if (val > 0) { // 0 means 'empty' - val -= 1; // to convert from 1-based to 0... - Bucket bucket = _collList[val]; - if (bucket != null) { - return bucket.find(hash, firstQuad, secondQuad); - } - } - // Nope, no match whatsoever - return null; - } - - /** - * Finds and returns name matching the specified symbol, if such - * name already exists in the table; or if not, creates name object, - * adds to the table, and returns it. - *

- * Note: this is the general purpose method that can be called for - * names of any length. However, if name is less than 9 bytes long, - * it is preferable to call the version optimized for short - * names. - * - * @param quads Array of int32s, each of which contain 4 bytes of - * encoded name - * @param qlen Number of int32s, starting from index 0, in quads - * parameter - * - * @return Name matching the symbol passed (or constructed for - * it) - */ - public Name findName(int[] quads, int qlen) - { - /* // Not needed, never gets called - if (qlen < 3) { // another sanity check - return findName(quads[0], (qlen < 2) ? 0 : quads[1]); - } - */ - int hash = calcHash(quads, qlen); - // (for rest of comments regarding logic, see method above) - int ix = (hash & _mainHashMask); - int val = _mainHash[ix]; - if ((((val >> 8) ^ hash) << 8) == 0) { - Name name = _mainNames[ix]; - if (name == null // main slot empty; no collision list then either - || name.equals(quads, qlen)) { // should be match, let's verify - return name; - } - } else if (val == 0) { // empty slot? no match - return null; - } - val &= 0xFF; - if (val > 0) { // 0 means 'empty' - val -= 1; // to convert from 1-based to 0... - Bucket bucket = _collList[val]; - if (bucket != null) { - return bucket.find(hash, quads, qlen); - } - } - return null; - } - - /* - /**************************************** - /* API, mutators - /**************************************** - */ - - public Name addName(String symbolStr, int[] quads, int qlen) - { - if (_intern) { - symbolStr = InternCache.instance.intern(symbolStr); - } - int hash = calcHash(quads, qlen); - Name symbol = constructName(hash, symbolStr, quads, qlen); - _addSymbol(hash, symbol); - return symbol; - } - - /* - /**************************************** - /* Helper methods - /**************************************** - */ - - public final static int calcHash(int firstQuad) - { - int hash = firstQuad; - hash ^= (hash >>> 16); // to xor hi- and low- 16-bits - hash ^= (hash >>> 8); // as well as lowest 2 bytes - return hash; - } - - public final static int calcHash(int firstQuad, int secondQuad) - { - int hash = (firstQuad * 31) + secondQuad; - - // If this was called for single-quad instance: - //int hash = (secondQuad == 0) ? firstQuad : ((firstQuad * 31) + secondQuad); - - hash ^= (hash >>> 16); // to xor hi- and low- 16-bits - hash ^= (hash >>> 8); // as well as lowest 2 bytes - return hash; - } - - public final static int calcHash(int[] quads, int qlen) - { - // Note: may be called for qlen < 3 - int hash = quads[0]; - for (int i = 1; i < qlen; ++i) { - hash = (hash * 31) + quads[i]; - } - - hash ^= (hash >>> 16); // to xor hi- and low- 16-bits - hash ^= (hash >>> 8); // as well as lowest 2 bytes - - return hash; - } - - /* 26-Nov-2008, tatu: not used currently; if not used in near future, - * let's just delete it. - */ - /* - public static int[] calcQuads(byte[] wordBytes) - { - int blen = wordBytes.length; - int[] result = new int[(blen + 3) / 4]; - for (int i = 0; i < blen; ++i) { - int x = wordBytes[i] & 0xFF; - - if (++i < blen) { - x = (x << 8) | (wordBytes[i] & 0xFF); - if (++i < blen) { - x = (x << 8) | (wordBytes[i] & 0xFF); - if (++i < blen) { - x = (x << 8) | (wordBytes[i] & 0xFF); - } - } - } - result[i >> 2] = x; - } - return result; - } - */ - - /* - /**************************************** - /* Standard methods - /**************************************** - */ - - /* - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append("[BytesToNameCanonicalizer, size: "); - sb.append(_count); - sb.append('/'); - sb.append(_mainHash.length); - sb.append(", "); - sb.append(_collCount); - sb.append(" coll; avg length: "); - - // Average length: minimum of 1 for all (1 == primary hit); - // and then 1 per each traversal for collisions/buckets - //int maxDist = 1; - int pathCount = _count; - for (int i = 0; i < _collEnd; ++i) { - int spillLen = _collList[i].length(); - for (int j = 1; j <= spillLen; ++j) { - pathCount += j; - } - } - double avgLength; - - if (_count == 0) { - avgLength = 0.0; - } else { - avgLength = (double) pathCount / (double) _count; - } - // let's round up a bit (two 2 decimal places) - //avgLength -= (avgLength % 0.01); - - sb.append(avgLength); - sb.append(']'); - return sb.toString(); - } - */ - - /* - /**************************************** - /* Internal methods - /**************************************** - */ - - private void _addSymbol(int hash, Name symbol) - { - if (_mainHashShared) { // always have to modify main entry - unshareMain(); - } - // First, do we need to rehash? - if (_needRehash) { - rehash(); - } - - ++_count; - - /* Ok, enough about set up: now we need to find the slot to add - * symbol in: - */ - int ix = (hash & _mainHashMask); - if (_mainNames[ix] == null) { // primary empty? - _mainHash[ix] = (hash << 8); - if (_mainNamesShared) { - unshareNames(); - } - _mainNames[ix] = symbol; - } else { // nope, it's a collision, need to spill over - /* How about spill-over area... do we already know the bucket - * (is the case if it's not the first collision) - */ - if (_collListShared) { - unshareCollision(); // also allocates if list was null - } - - ++_collCount; - int entryValue = _mainHash[ix]; - int bucket = entryValue & 0xFF; - if (bucket == 0) { // first spill over? - if (_collEnd <= LAST_VALID_BUCKET) { // yup, still unshared bucket - bucket = _collEnd; - ++_collEnd; - // need to expand? - if (bucket >= _collList.length) { - expandCollision(); - } - } else { // nope, have to share... let's find shortest? - bucket = findBestBucket(); - } - // Need to mark the entry... and the spill index is 1-based - _mainHash[ix] = (entryValue & ~0xFF) | (bucket + 1); - } else { - --bucket; // 1-based index in value - } - - // And then just need to link the new bucket entry in - _collList[bucket] = new Bucket(symbol, _collList[bucket]); - } - - /* Ok. Now, do we need a rehash next time? Need to have at least - * 50% fill rate no matter what: - */ - { - int hashSize = _mainHash.length; - if (_count > (hashSize >> 1)) { - int hashQuarter = (hashSize >> 2); - /* And either strictly above 75% (the usual) or - * just 50%, and collision count >= 25% of total hash size - */ - if (_count > (hashSize - hashQuarter)) { - _needRehash = true; - } else if (_collCount >= hashQuarter) { - _needRehash = true; - } - } - } - } - - private void rehash() - { - _needRehash = false; - // Note: since we'll make copies, no need to unshare, can just mark as such: - _mainNamesShared = false; - - /* And then we can first deal with the main hash area. Since we - * are expanding linearly (double up), we know there'll be no - * collisions during this phase. - */ - int[] oldMainHash = _mainHash; - int len = oldMainHash.length; - int newLen = len+len; - - /* 13-Mar-2010, tatu: Let's guard against OOME that could be caused by - * large documents with unique (or mostly so) names - */ - if (newLen > MAX_TABLE_SIZE) { - nukeSymbols(); - return; - } - - _mainHash = new int[newLen]; - _mainHashMask = (newLen - 1); - Name[] oldNames = _mainNames; - _mainNames = new Name[newLen]; - int symbolsSeen = 0; // let's do a sanity check - for (int i = 0; i < len; ++i) { - Name symbol = oldNames[i]; - if (symbol != null) { - ++symbolsSeen; - int hash = symbol.hashCode(); - int ix = (hash & _mainHashMask); - _mainNames[ix] = symbol; - _mainHash[ix] = hash << 8; // will clear spill index - } - } - - /* And then the spill area. This may cause collisions, although - * not necessarily as many as there were earlier. Let's allocate - * same amount of space, however - */ - int oldEnd = _collEnd; - if (oldEnd == 0) { // no prior collisions... - return; - } - - _collCount = 0; - _collEnd = 0; - _collListShared = false; - - Bucket[] oldBuckets = _collList; - _collList = new Bucket[oldBuckets.length]; - for (int i = 0; i < oldEnd; ++i) { - for (Bucket curr = oldBuckets[i]; curr != null; curr = curr.mNext) { - ++symbolsSeen; - Name symbol = curr.mName; - int hash = symbol.hashCode(); - int ix = (hash & _mainHashMask); - int val = _mainHash[ix]; - if (_mainNames[ix] == null) { // no primary entry? - _mainHash[ix] = (hash << 8); - _mainNames[ix] = symbol; - } else { // nope, it's a collision, need to spill over - ++_collCount; - int bucket = val & 0xFF; - if (bucket == 0) { // first spill over? - if (_collEnd <= LAST_VALID_BUCKET) { // yup, still unshared bucket - bucket = _collEnd; - ++_collEnd; - // need to expand? - if (bucket >= _collList.length) { - expandCollision(); - } - } else { // nope, have to share... let's find shortest? - bucket = findBestBucket(); - } - // Need to mark the entry... and the spill index is 1-based - _mainHash[ix] = (val & ~0xFF) | (bucket + 1); - } else { - --bucket; // 1-based index in value - } - // And then just need to link the new bucket entry in - _collList[bucket] = new Bucket(symbol, _collList[bucket]); - } - } // for (... buckets in the chain ...) - } // for (... list of bucket heads ... ) - - if (symbolsSeen != _count) { // sanity check - throw new RuntimeException("Internal error: count after rehash "+symbolsSeen+"; should be "+_count); - } - } - - /** - * Helper method called to empty all shared symbols, but to leave - * arrays allocated - */ - private void nukeSymbols() - { - _count = 0; - Arrays.fill(_mainHash, 0); - Arrays.fill(_mainNames, null); - Arrays.fill(_collList, null); - _collCount = 0; - _collEnd = 0; - } - - /** - * Method called to find the best bucket to spill a Name over to: - * usually the first bucket that has only one entry, but in general - * first one of the buckets with least number of entries - */ - private int findBestBucket() - { - Bucket[] buckets = _collList; - int bestCount = Integer.MAX_VALUE; - int bestIx = -1; - - for (int i = 0, len = _collEnd; i < len; ++i) { - int count = buckets[i].length(); - if (count < bestCount) { - if (count == 1) { // best possible - return i; - } - bestCount = count; - bestIx = i; - } - } - return bestIx; - } - - /** - * Method that needs to be called, if the main hash structure - * is (may be) shared. This happens every time something is added, - * even if addition is to the collision list (since collision list - * index comes from lowest 8 bits of the primary hash entry) - */ - private void unshareMain() - { - int[] old = _mainHash; - int len = _mainHash.length; - - _mainHash = new int[len]; - System.arraycopy(old, 0, _mainHash, 0, len); - _mainHashShared = false; - } - - private void unshareCollision() - { - Bucket[] old = _collList; - if (old == null) { - _collList = new Bucket[INITIAL_COLLISION_LEN]; - } else { - int len = old.length; - _collList = new Bucket[len]; - System.arraycopy(old, 0, _collList, 0, len); - } - _collListShared = false; - } - - private void unshareNames() - { - Name[] old = _mainNames; - int len = old.length; - _mainNames = new Name[len]; - System.arraycopy(old, 0, _mainNames, 0, len); - _mainNamesShared = false; - } - - private void expandCollision() - { - Bucket[] old = _collList; - int len = old.length; - _collList = new Bucket[len+len]; - System.arraycopy(old, 0, _collList, 0, len); - } - - - /* - /**************************************** - /* Constructing name objects - /**************************************** - */ - - /* - private static Name constructName(int hash, String name, int q1, int q2) - { - if (q2 == 0) { // one quad only? - return new Name1(name, hash, q1); - } - return new Name2(name, hash, q1, q2); - } - */ - - private static Name constructName(int hash, String name, int[] quads, int qlen) - { - if (qlen < 4) { // Need to check for 3 quad one, can do others too - switch (qlen) { - case 1: - return new Name1(name, hash, quads[0]); - case 2: - return new Name2(name, hash, quads[0], quads[1]); - case 3: - return new Name3(name, hash, quads[0], quads[1], quads[2]); - default: - } - } - // Otherwise, need to copy the incoming buffer - int[] buf = new int[qlen]; - for (int i = 0; i < qlen; ++i) { - buf[i] = quads[i]; - } - return new NameN(name, hash, buf, qlen); - } - - /* - /**************************************** - /* Helper classes - /**************************************** - */ - - final static class Bucket - { - final Name mName; - final Bucket mNext; - - Bucket(Name name, Bucket next) - { - mName = name; - mNext = next; - } - - public int length() - { - int len = 1; - for (Bucket curr = mNext; curr != null; curr = curr.mNext) { - ++len; - } - return len; - } - - public Name find(int hash, int firstQuad, int secondQuad) - { - if (mName.hashCode() == hash) { - if (mName.equals(firstQuad, secondQuad)) { - return mName; - } - } - for (Bucket curr = mNext; curr != null; curr = curr.mNext) { - Name currName = curr.mName; - if (currName.hashCode() == hash) { - if (currName.equals(firstQuad, secondQuad)) { - return currName; - } - } - } - return null; - } - - public Name find(int hash, int[] quads, int qlen) - { - if (mName.hashCode() == hash) { - if (mName.equals(quads, qlen)) { - return mName; - } - } - for (Bucket curr = mNext; curr != null; curr = curr.mNext) { - Name currName = curr.mName; - if (currName.hashCode() == hash) { - if (currName.equals(quads, qlen)) { - return currName; - } - } - } - return null; - } - } -} diff --git a/src/org/codehaus/jackson/sym/CharsToNameCanonicalizer.java b/src/org/codehaus/jackson/sym/CharsToNameCanonicalizer.java deleted file mode 100644 index 6cc61645ff..0000000000 --- a/src/org/codehaus/jackson/sym/CharsToNameCanonicalizer.java +++ /dev/null @@ -1,578 +0,0 @@ -package org.codehaus.jackson.sym; - -import java.util.Arrays; - -import org.codehaus.jackson.util.InternCache; - -/** - * This class is a kind of specialized type-safe Map, from char array to - * String value. Specialization means that in addition to type-safety - * and specific access patterns (key char array, Value optionally interned - * String; values added on access if necessary), and that instances are - * meant to be used concurrently, but by using well-defined mechanisms - * to obtain such concurrently usable instances. Main use for the class - * is to store symbol table information for things like compilers and - * parsers; especially when number of symbols (keywords) is limited. - *

- * For optimal performance, usage pattern should be one where matches - * should be very common (esp. after "warm-up"), and as with most hash-based - * maps/sets, that hash codes are uniformly distributed. Also, collisions - * are slightly more expensive than with HashMap or HashSet, since hash codes - * are not used in resolving collisions; that is, equals() comparison is - * done with all symbols in same bucket index.
- * Finally, rehashing is also more expensive, as hash codes are not - * stored; rehashing requires all entries' hash codes to be recalculated. - * Reason for not storing hash codes is reduced memory usage, hoping - * for better memory locality. - *

- * Usual usage pattern is to create a single "master" instance, and either - * use that instance in sequential fashion, or to create derived "child" - * instances, which after use, are asked to return possible symbol additions - * to master instance. In either case benefit is that symbol table gets - * initialized so that further uses are more efficient, as eventually all - * symbols needed will already be in symbol table. At that point no more - * Symbol String allocations are needed, nor changes to symbol table itself. - *

- * Note that while individual SymbolTable instances are NOT thread-safe - * (much like generic collection classes), concurrently used "child" - * instances can be freely used without synchronization. However, using - * master table concurrently with child instances can only be done if - * access to master instance is read-only (ie. no modifications done). - */ - -public final class CharsToNameCanonicalizer -{ - /** - * Default initial table size. Shouldn't be miniscule (as there's - * cost to both array realloc and rehashing), but let's keep - * it reasonably small nonetheless. For systems that properly - * reuse factories it doesn't matter either way; but when - * recreating factories often, initial overhead may dominate. - */ - protected static final int DEFAULT_TABLE_SIZE = 64; - - /** - * Let's not expand symbol tables past some maximum size; - * this should protected against OOMEs caused by large documents - * with uniquer (~= random) names. - * - * @since 1.5 - */ - protected static final int MAX_TABLE_SIZE = 0x10000; // 64k entries == 256k mem - - /** - * Let's only share reasonably sized symbol tables. Max size set to 3/4 of 16k; - * this corresponds to 64k main hash index. This should allow for enough distinct - * names for almost any case. - */ - final static int MAX_ENTRIES_FOR_REUSE = 12000; - - final static CharsToNameCanonicalizer sBootstrapSymbolTable; - static { - sBootstrapSymbolTable = new CharsToNameCanonicalizer(); - } - - /* - /**************************************** - /* Configuration: - /**************************************** - */ - - /** - * Sharing of learnt symbols is done by optional linking of symbol - * table instances with their parents. When parent linkage is - * defined, and child instance is released (call to release), - * parent's shared tables may be updated from the child instance. - */ - protected CharsToNameCanonicalizer _parent; - - /** - * Whether canonical symbol Strings are to be intern()ed before added - * to the table or not - */ - final protected boolean _intern; - - /** - * Whether any canonicalization should be attempted (whether using - * intern or not) - */ - final protected boolean _canonicalize; - - /* - /**************************************** - /* Actual symbol table data: - /**************************************** - */ - - /** - * Primary matching symbols; it's expected most match occur from - * here. - */ - protected String[] _symbols; - - /** - * Overflow buckets; if primary doesn't match, lookup is done - * from here. - *

- * Note: Number of buckets is half of number of symbol entries, on - * assumption there's less need for buckets. - */ - protected Bucket[] _buckets; - - /** - * Current size (number of entries); needed to know if and when - * rehash. - */ - protected int _size; - - /** - * Limit that indicates maximum size this instance can hold before - * it needs to be expanded and rehashed. Calculated using fill - * factor passed in to constructor. - */ - protected int _sizeThreshold; - - /** - * Mask used to get index from hash values; equal to - * _buckets.length - 1, when _buckets.length is - * a power of two. - */ - protected int _indexMask; - - /* - /**************************************** - /* State regarding shared arrays - /**************************************** - */ - - /** - * Flag that indicates if any changes have been made to the data; - * used to both determine if bucket array needs to be copied when - * (first) change is made, and potentially if updated bucket list - * is to be resync'ed back to master instance. - */ - protected boolean _dirty; - - /* - /**************************************** - /* Life-cycle - /**************************************** - */ - - /** - * Method called to create root canonicalizer for a {@link org.codehaus.jackson.JsonFactory} - * instance. Root instance is never used directly; its main use is for - * storing and sharing underlying symbol arrays as needed. - */ - public static CharsToNameCanonicalizer createRoot() - { - return sBootstrapSymbolTable.makeOrphan(); - } - - /** - * Main method for constructing a master symbol table instance. - * - * @param initialSize Minimum initial size for bucket array; internally - * will always use a power of two equal to or bigger than this value. - */ - private CharsToNameCanonicalizer() - { - // these settings don't really matter for the bootstrap instance - _canonicalize = true; - _intern = true; - // And we'll also set flags so no copying of buckets is needed: - _dirty = true; - initTables(DEFAULT_TABLE_SIZE); - } - - private void initTables(int initialSize) - { - _symbols = new String[initialSize]; - _buckets = new Bucket[initialSize >> 1]; - // Mask is easy to calc for powers of two. - _indexMask = initialSize - 1; - _size = 0; - // Hard-coded fill factor is 75% - _sizeThreshold = (initialSize - (initialSize >> 2)); - } - - /** - * Internal constructor used when creating child instances. - */ - private CharsToNameCanonicalizer(CharsToNameCanonicalizer parent, - boolean canonicalize, boolean intern, - String[] symbols, Bucket[] buckets, int size) - { - _parent = parent; - _canonicalize = canonicalize; - _intern = intern; - - _symbols = symbols; - _buckets = buckets; - _size = size; - // Hard-coded fill factor, 75% - int arrayLen = (symbols.length); - _sizeThreshold = arrayLen - (arrayLen >> 2); - _indexMask = (arrayLen - 1); - - // Need to make copies of arrays, if/when adding new entries - _dirty = false; - } - - /** - * "Factory" method; will create a new child instance of this symbol - * table. It will be a copy-on-write instance, ie. it will only use - * read-only copy of parent's data, but when changes are needed, a - * copy will be created. - *

- * Note: while this method is synchronized, it is generally not - * safe to both use makeChild/mergeChild, AND to use instance - * actively. Instead, a separate 'root' instance should be used - * on which only makeChild/mergeChild are called, but instance itself - * is not used as a symbol table. - */ - public synchronized CharsToNameCanonicalizer makeChild(boolean canonicalize, boolean intern) - { - return new CharsToNameCanonicalizer(this, canonicalize, intern, _symbols, _buckets, _size); - } - - private CharsToNameCanonicalizer makeOrphan() - { - return new CharsToNameCanonicalizer(null, true, true, _symbols, _buckets, _size); - } - - /** - * Method that allows contents of child table to potentially be - * "merged in" with contents of this symbol table. - *

- * Note that caller has to make sure symbol table passed in is - * really a child or sibling of this symbol table. - */ - private synchronized void mergeChild(CharsToNameCanonicalizer child) - { - /* One caveat: let's try to avoid problems with - * degenerate cases of documents with generated "random" - * names: for these, symbol tables would bloat indefinitely. - * One way to do this is to just purge tables if they grow - * too large, and that's what we'll do here. - */ - if (child.size() > MAX_ENTRIES_FOR_REUSE) { - /* Should there be a way to get notified about this - * event, to log it or such? (as it's somewhat abnormal - * thing to happen) - */ - // At any rate, need to clean up the tables, then: - initTables(DEFAULT_TABLE_SIZE); - } else { - /* Otherwise, we'll merge changed stuff in, if there are - * more entries (which may not be the case if one of siblings - * has added symbols first or such) - */ - if (child.size() <= size()) { // nothing to add - return; - } - // Okie dokie, let's get the data in! - _symbols = child._symbols; - _buckets = child._buckets; - _size = child._size; - _sizeThreshold = child._sizeThreshold; - _indexMask = child._indexMask; - } - /* Dirty flag... well, let's just clear it, to force copying just - * in case. Shouldn't really matter, for master tables. - * (which this is, given something is merged to it etc) - */ - _dirty = false; - } - - public void release() - { - // If nothing has been added, nothing to do - if (!maybeDirty()) { - return; - } - if (_parent != null) { - _parent.mergeChild(this); - /* Let's also mark this instance as dirty, so that just in - * case release was too early, there's no corruption - * of possibly shared data. - */ - _dirty = false; - } - } - - /* - /**************************************** - /* Public API, generic accessors: - /**************************************** - */ - - public int size() { return _size; } - - public boolean maybeDirty() { return _dirty; } - - /* - /**************************************** - /* Public API, accessing symbols: - /**************************************** - */ - - public String findSymbol(char[] buffer, int start, int len, int hash) - { - if (len < 1) { // empty Strings are simplest to handle up front - return ""; - } - if (!_canonicalize) { // [JACKSON-259] - return new String(buffer, start, len); - } - - hash &= _indexMask; - - String sym = _symbols[hash]; - - // Optimal case; checking existing primary symbol for hash index: - if (sym != null) { - // Let's inline primary String equality checking: - if (sym.length() == len) { - int i = 0; - do { - if (sym.charAt(i) != buffer[start+i]) { - break; - } - } while (++i < len); - // Optimal case; primary match found - if (i == len) { - return sym; - } - } - // How about collision bucket? - Bucket b = _buckets[hash >> 1]; - if (b != null) { - sym = b.find(buffer, start, len); - if (sym != null) { - return sym; - } - } - } - - if (!_dirty) { //need to do copy-on-write? - copyArrays(); - _dirty = true; - } else if (_size >= _sizeThreshold) { // Need to expand? - rehash(); - /* Need to recalc hash; rare occurence (index mask has been - * recalculated as part of rehash) - */ - hash = calcHash(buffer, start, len) & _indexMask; - } - ++_size; - - String newSymbol = new String(buffer, start, len); - if (_intern) { - newSymbol = InternCache.instance.intern(newSymbol); - } - // Ok; do we need to add primary entry, or a bucket? - if (_symbols[hash] == null) { - _symbols[hash] = newSymbol; - } else { - int bix = hash >> 1; - _buckets[bix] = new Bucket(newSymbol, _buckets[bix]); - } - - return newSymbol; - } - - /** - * Implementation of a hashing method for variable length - * Strings. Most of the time intention is that this calculation - * is done by caller during parsing, not here; however, sometimes - * it needs to be done for parsed "String" too. - * - * @param len Length of String; has to be at least 1 (caller guarantees - * this pre-condition) - */ - public static int calcHash(char[] buffer, int start, int len) { - int hash = (int) buffer[0]; - for (int i = 1; i < len; ++i) { - hash = (hash * 31) + (int) buffer[i]; - } - return hash; - } - - public static int calcHash(String key) { - int hash = (int) key.charAt(0); - for (int i = 1, len = key.length(); i < len; ++i) { - hash = (hash * 31) + (int) key.charAt(i); - - } - return hash; - } - - /* - /**************************************** - /* Internal methods - /**************************************** - */ - - /** - * Method called when copy-on-write is needed; generally when first - * change is made to a derived symbol table. - */ - private void copyArrays() { - String[] oldSyms = _symbols; - int size = oldSyms.length; - _symbols = new String[size]; - System.arraycopy(oldSyms, 0, _symbols, 0, size); - Bucket[] oldBuckets = _buckets; - size = oldBuckets.length; - _buckets = new Bucket[size]; - System.arraycopy(oldBuckets, 0, _buckets, 0, size); - } - - /** - * Method called when size (number of entries) of symbol table grows - * so big that load factor is exceeded. Since size has to remain - * power of two, arrays will then always be doubled. Main work - * is really redistributing old entries into new String/Bucket - * entries. - */ - private void rehash() - { - int size = _symbols.length; - int newSize = size + size; - - /* 12-Mar-2010, tatu: Let's actually limit maximum size we are - * prepared to use, to guard against OOME in case of unbounded - * name sets (unique [non-repeating] names) - */ - if (newSize > MAX_TABLE_SIZE) { - /* If this happens, there's no point in either growing or - * shrinking hash areas. Rather, it's better to just clean - * them up for reuse. - */ - _size = 0; - Arrays.fill(_symbols, null); - Arrays.fill(_buckets, null); - _dirty = true; - return; - } - - String[] oldSyms = _symbols; - Bucket[] oldBuckets = _buckets; - _symbols = new String[newSize]; - _buckets = new Bucket[newSize >> 1]; - // Let's update index mask, threshold, now (needed for rehashing) - _indexMask = newSize - 1; - _sizeThreshold += _sizeThreshold; - - int count = 0; // let's do sanity check - - /* Need to do two loops, unfortunately, since spill-over area is - * only half the size: - */ - for (int i = 0; i < size; ++i) { - String symbol = oldSyms[i]; - if (symbol != null) { - ++count; - int index = calcHash(symbol) & _indexMask; - if (_symbols[index] == null) { - _symbols[index] = symbol; - } else { - int bix = index >> 1; - _buckets[bix] = new Bucket(symbol, _buckets[bix]); - } - } - } - - size >>= 1; - for (int i = 0; i < size; ++i) { - Bucket b = oldBuckets[i]; - while (b != null) { - ++count; - String symbol = b.getSymbol(); - int index = calcHash(symbol) & _indexMask; - if (_symbols[index] == null) { - _symbols[index] = symbol; - } else { - int bix = index >> 1; - _buckets[bix] = new Bucket(symbol, _buckets[bix]); - } - b = b.getNext(); - } - } - - if (count != _size) { - throw new Error("Internal error on SymbolTable.rehash(): had "+_size+" entries; now have "+count+"."); - } - } - - /* - /**************************************** - /* Bucket class - /**************************************** - */ - - /** - * This class is a symbol table entry. Each entry acts as a node - * in a linked list. - */ - static final class Bucket { - private final String _symbol; - private final Bucket mNext; - - public Bucket(String symbol, Bucket next) { - _symbol = symbol; - mNext = next; - } - - public String getSymbol() { return _symbol; } - public Bucket getNext() { return mNext; } - - public String find(char[] buf, int start, int len) { - String sym = _symbol; - Bucket b = mNext; - - while (true) { // Inlined equality comparison: - if (sym.length() == len) { - int i = 0; - do { - if (sym.charAt(i) != buf[start+i]) { - break; - } - } while (++i < len); - if (i == len) { - return sym; - } - } - if (b == null) { - break; - } - sym = b.getSymbol(); - b = b.getNext(); - } - return null; - } - - /* 26-Nov-2008, tatu: not used currently; if not used in near future, - * let's just delete it. - */ - /* - public String find(String str) { - String sym = _symbol; - Bucket b = mNext; - - while (true) { - if (sym.equals(str)) { - return sym; - } - if (b == null) { - break; - } - sym = b.getSymbol(); - b = b.getNext(); - } - return null; - } - */ - } -} diff --git a/src/org/codehaus/jackson/sym/Name.java b/src/org/codehaus/jackson/sym/Name.java deleted file mode 100644 index b677876bb9..0000000000 --- a/src/org/codehaus/jackson/sym/Name.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.codehaus.jackson.sym; - -/** - * Base class for tokenized names (key strings in objects) that have - * been tokenized from byte-based input sources (like - * {@link java.io.InputStream}. - * - * @author Tatu Saloranta - */ -public abstract class Name -{ - protected final String mName; - - protected final int mHashCode; - - protected Name(String name, int hashCode) { - mName = name; - mHashCode = hashCode; - } - - public String getName() { return mName; } - - /* - ////////////////////////////////////////////////////////// - // Methods for package/core parser - ////////////////////////////////////////////////////////// - */ - - public abstract boolean equals(int quad1); - - public abstract boolean equals(int quad1, int quad2); - - public abstract boolean equals(int[] quads, int qlen); - - /* - ////////////////////////////////////////////////////////// - // Overridden standard methods - ////////////////////////////////////////////////////////// - */ - - @Override - public String toString() { return mName; } - - @Override - public final int hashCode() { return mHashCode; } - - @Override - public boolean equals(Object o) - { - // Canonical instances, can usually just do identity comparison - return (o == this); - } -} diff --git a/src/org/codehaus/jackson/sym/Name1.java b/src/org/codehaus/jackson/sym/Name1.java deleted file mode 100644 index 6be327a54d..0000000000 --- a/src/org/codehaus/jackson/sym/Name1.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.codehaus.jackson.sym; - -/** - * Specialized implementation of PName: can be used for short Strings - * that consists of at most 4 bytes. Usually this means short - * ascii-only names. - *

- * The reason for such specialized classes is mostly space efficiency; - * and to a lesser degree performance. Both are achieved for short - * Strings by avoiding another level of indirection (via quad arrays) - */ -public final class Name1 - extends Name -{ - final static Name1 sEmptyName = new Name1("", 0, 0); - - final int mQuad; - - Name1(String name, int hash, int quad) - { - super(name, hash); - mQuad = quad; - } - - final static Name1 getEmptyName() { return sEmptyName; } - - public boolean equals(int quad) - { - return (quad == mQuad); - } - - public boolean equals(int quad1, int quad2) - { - return (quad1 == mQuad) && (quad2 == 0); - } - - public boolean equals(int[] quads, int qlen) - { - return (qlen == 1 && quads[0] == mQuad); - } -} diff --git a/src/org/codehaus/jackson/sym/Name2.java b/src/org/codehaus/jackson/sym/Name2.java deleted file mode 100644 index ba6d97e9be..0000000000 --- a/src/org/codehaus/jackson/sym/Name2.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.codehaus.jackson.sym; - -/** - * Specialized implementation of PName: can be used for short Strings - * that consists of 5 to 8 bytes. Usually this means relatively short - * ascii-only names. - *

- * The reason for such specialized classes is mostly space efficiency; - * and to a lesser degree performance. Both are achieved for short - * Strings by avoiding another level of indirection (via quad arrays) - */ -public final class Name2 - extends Name -{ - final int mQuad1; - - final int mQuad2; - - Name2(String name, int hash, int quad1, int quad2) - { - super(name, hash); - mQuad1 = quad1; - mQuad2 = quad2; - } - - public boolean equals(int quad) { return false; } - - public boolean equals(int quad1, int quad2) - { - return (quad1 == mQuad1) && (quad2 == mQuad2); - } - - public boolean equals(int[] quads, int qlen) - { - return (qlen == 2 && quads[0] == mQuad1 && quads[1] == mQuad2); - } -} diff --git a/src/org/codehaus/jackson/sym/Name3.java b/src/org/codehaus/jackson/sym/Name3.java deleted file mode 100644 index d35db6c9af..0000000000 --- a/src/org/codehaus/jackson/sym/Name3.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.codehaus.jackson.sym; - -/** - * Specialized implementation of PName: can be used for short Strings - * that consists of 9 to 12 bytes. It's the longest special purpose - * implementaion; longer ones are expressed using {@link NameN}. - */ -public final class Name3 - extends Name -{ - final int mQuad1; - final int mQuad2; - final int mQuad3; - - Name3(String name, int hash, int q1, int q2, int q3) - { - super(name, hash); - mQuad1 = q1; - mQuad2 = q2; - mQuad3 = q3; - } - - // Implies quad length == 1, never matches - public boolean equals(int quad) { return false; } - - // Implies quad length == 2, never matches - public boolean equals(int quad1, int quad2) { return false; } - - public boolean equals(int[] quads, int qlen) - { - return (qlen == 3) - && (quads[0] == mQuad1) - && (quads[1] == mQuad2) - && (quads[2] == mQuad3); - } -} diff --git a/src/org/codehaus/jackson/sym/NameN.java b/src/org/codehaus/jackson/sym/NameN.java deleted file mode 100644 index b5236f2b53..0000000000 --- a/src/org/codehaus/jackson/sym/NameN.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.codehaus.jackson.sym; - -/** - * Generic implementation of PName used for "long" names, where long - * means that its byte (UTF-8) representation is 13 bytes or more. - */ -public final class NameN - extends Name -{ - final int[] mQuads; - final int mQuadLen; - - NameN(String name, int hash, int[] quads, int quadLen) - { - super(name, hash); - /* We have specialized implementations for shorter - * names, so let's not allow runt instances here - */ - if (quadLen < 3) { - throw new IllegalArgumentException("Qlen must >= 3"); - } - mQuads = quads; - mQuadLen = quadLen; - } - - // Implies quad length == 1, never matches - @Override - public boolean equals(int quad) { return false; } - - // Implies quad length == 2, never matches - @Override - public boolean equals(int quad1, int quad2) { return false; } - - @Override - public boolean equals(int[] quads, int qlen) - { - if (qlen != mQuadLen) { - return false; - } - - /* 26-Nov-2008, tatus: Strange, but it does look like - * unrolling here is counter-productive, reducing - * speed. Perhaps it prevents inlining by HotSpot or - * something... - */ - // Will always have >= 3 quads, can unroll - /* - if (quads[0] == mQuads[0] - && quads[1] == mQuads[1] - && quads[2] == mQuads[2]) { - for (int i = 3; i < qlen; ++i) { - if (quads[i] != mQuads[i]) { - return false; - } - } - return true; - } - */ - - // or simpler way without unrolling: - for (int i = 0; i < qlen; ++i) { - if (quads[i] != mQuads[i]) { - return false; - } - } - return true; - } -} diff --git a/src/org/codehaus/jackson/type/JavaType.java b/src/org/codehaus/jackson/type/JavaType.java deleted file mode 100644 index 224fda3362..0000000000 --- a/src/org/codehaus/jackson/type/JavaType.java +++ /dev/null @@ -1,333 +0,0 @@ -package org.codehaus.jackson.type; - -import java.lang.reflect.Modifier; - -/** - * Base class for type token classes used both to contain information - * and as keys for deserializers. - *

- * Instances can (only) be constructed by - * {@link org.codehaus.jackson.map.type.TypeFactory}. - */ -public abstract class JavaType -{ - /** - * This is the nominal type-erased Class that would be close to the - * type represented (but not exactly type, due to type erasure: type - * instance may have more information on this). - * May be an interface or abstract class, so instantiation - * may not be possible. - */ - protected final Class _class; - - protected int _hashCode; - - /** - * Optional handler (codec) that can be attached to indicate - * what to use for handling (serializing, deserializing) values of - * this specific type. - *

- * Note: untyped (i.e. caller has to cast) because it is used for - * different kinds of handlers, with unrelated types. - * - * @since 1.3 - */ - protected Object _valueHandler; - - /** - * Optional handler that can be attached to indicate how to handle - * additional type metadata associated with this type. - *

- * Note: untyped (i.e. caller has to cast) because it is used for - * different kinds of handlers, with unrelated types. - * - * @since 1.5 - */ - protected Object _typeHandler; - - /* - /************************************************* - // Life-cycle - /************************************************* - */ - - protected JavaType(Class clz) - { - _class = clz; - String name = clz.getName(); - _hashCode = name.hashCode(); - } - - /** - * Method that can be called to do a "narrowing" conversions; that is, - * to return a type with a raw class that is assignable to the raw - * class of this type. If this is not possible, an - * {@link IllegalArgumentException} is thrown. - * If class is same as the current raw class, instance itself is - * returned. - */ - public final JavaType narrowBy(Class subclass) - { - // First: if same raw class, just return this instance - if (subclass == _class) { - return this; - } - // Otherwise, ensure compatibility - _assertSubclass(subclass, _class); - JavaType result = _narrow(subclass); - if (_valueHandler != null) { - result.setValueHandler(_valueHandler); - } - if (_typeHandler != null) { - result.setTypeHandler(_typeHandler); - } - return result; - } - - /** - * More efficient version of {@link #narrowBy}, called by - * internal framework in cases where compatibility checks - * are to be skipped. - * - * @since 1.5 - */ - public final JavaType forcedNarrowBy(Class subclass) - { - if (subclass == _class) { // can still optimize for simple case - return this; - } - JavaType result = _narrow(subclass); - if (_valueHandler != null) { - result.setValueHandler(_valueHandler); - } - if (_typeHandler != null) { - result.setTypeHandler(_typeHandler); - } - return result; - } - - /** - * Method that can be called to do a "widening" conversions; that is, - * to return a type with a raw class that could be assigned from this - * type. - * If such conversion is not possible, an - * {@link IllegalArgumentException} is thrown. - * If class is same as the current raw class, instance itself is - * returned. - */ - public final JavaType widenBy(Class superclass) - { - // First: if same raw class, just return this instance - if (superclass == _class) { - return this; - } - // Otherwise, ensure compatibility - _assertSubclass(_class, superclass); - return _widen(superclass); - } - - protected abstract JavaType _narrow(Class subclass); - - /** - *

- * Default implementation is just to call {@link #_narrow}, since - * underlying type construction is usually identical - */ - protected JavaType _widen(Class superclass) { - return _narrow(superclass); - } - - public abstract JavaType narrowContentsBy(Class contentClass); - - /** - * Method for assigning handler to associate with this type; or - * if null passed, to remove such assignment - * - * @since 1.3 - */ - public void setValueHandler(Object h) { - // sanity check, should be assigned just once - if (h != null && _valueHandler != null) { - throw new IllegalStateException("Trying to reset value handler for type ["+toString() - +"]; old handler of type "+_valueHandler.getClass().getName()+", new handler of type "+h.getClass().getName()); - } - _valueHandler = h; - } - - /** - * Method for assigning type handler to associate with this type; or - * if null passed, to remove such assignment - * - * @since 1.5 - */ - public void setTypeHandler(Object h) { - // sanity check, should be assigned just once - if (h != null && _typeHandler != null) { - throw new IllegalStateException("Trying to reset type handler for type ["+toString() - +"]; old handler of type "+_typeHandler.getClass().getName()+", new handler of type "+h.getClass().getName()); - } - _typeHandler = h; - } - - /* - /************************************************* - /* Public API - /************************************************* - */ - - public final Class getRawClass() { return _class; } - - /** - * Method that can be used to check whether this type has - * specified Class as its type erasure. Put another way, returns - * true if instantiation of this Type is given (type-erased) Class. - */ - public final boolean hasRawClass(Class clz) { - return _class == clz; - } - - /** - * @return True if type represented is a container type; this includes - * array, Map and Collection types. - */ - public abstract boolean isContainerType(); - - public boolean isAbstract() { - return Modifier.isAbstract(_class.getModifiers()); - } - - /** - * @since 1.3 - */ - public boolean isConcrete() { - int mod = _class.getModifiers(); - if ((mod & (Modifier.INTERFACE | Modifier.ABSTRACT)) == 0) { - return true; - } - /* 19-Feb-2010, tatus: Holy mackarel; primitive types - * have 'abstract' flag set... - */ - if (_class.isPrimitive()) { - return true; - } - return false; - } - - public boolean isThrowable() { - return Throwable.class.isAssignableFrom(_class); - } - - public boolean isArrayType() { return false; } - - public final boolean isEnumType() { return _class.isEnum(); } - - public final boolean isInterface() { return _class.isInterface(); } - - public final boolean isPrimitive() { return _class.isPrimitive(); } - - public final boolean isFinal() { return Modifier.isFinal(_class.getModifiers()); } - - /** - * Method for accessing key type for this type, assuming type - * has such a concept (only Map types do) - */ - public JavaType getKeyType() { return null; } - - /** - * Method for accessing content type of this type, if type has - * such a thing: simple types do not, structured types do - * (like arrays, Collections and Maps) - */ - public JavaType getContentType() { return null; } - - /** - * Method for checking how many contained types this type - * has. Contained types are usually generic types, so that - * generic Maps have 2 contained types. - * - * @since 1.5 - */ - public int containedTypeCount() { return 0; } - - /** - * Method for accessing definitions of contained ("child") - * types. - * - * @param index Index of contained type to return - * - * @return Contained type at index, or null if no such type - * exists (no exception thrown) - * - * @since 1.5 - */ - public JavaType containedType(int index) { return null; } - - /** - * Method for accessing name of type variable in indicated - * position. If no name is bound, will use placeholders (derived - * from 0-based index); if no type variable or argument exists - * with given index, null is returned. - * - * @param index Index of contained type to return - * - * @return Contained type at index, or null if no such type - * exists (no exception thrown) - * - * @since 1.5 - */ - public String containedTypeName(int index) { return null; } - - /** - * Method for accessing value handler associated with this type, if any - * - * @since 1.3 - */ - @SuppressWarnings("unchecked") - public T getValueHandler() { return (T) _valueHandler; } - - /** - * Method for accessing type handler associated with this type, if any - * - * @since 1.5 - */ - @SuppressWarnings("unchecked") - public T getTypeHandler() { return (T) _typeHandler; } - - /** - * Method that can be used to serialize type into form from which - * it can be fully deserialized from at a later point (using - * TypeFactory from mapper package). - * For simple types this is same as calling - * {@link Class#getName}, but for structured types it may additionally - * contain type information about contents. - * - * @since 1.5 - */ - public abstract String toCanonical(); - - /* - /************************************************* - /* Helper methods - /************************************************* - */ - - protected void _assertSubclass(Class subclass, Class superClass) - { - if (!_class.isAssignableFrom(subclass)) { - throw new IllegalArgumentException("Class "+subclass.getName()+" is not assignable to "+_class.getName()); - } - } - - /* - /************************************************************** - /* Standard methods; let's make them abstract to force override - /************************************************************** - */ - - public abstract String toString(); - - public abstract boolean equals(Object o); - - @Override - public final int hashCode() { return _hashCode; } -} diff --git a/src/org/codehaus/jackson/type/TypeReference.java b/src/org/codehaus/jackson/type/TypeReference.java deleted file mode 100644 index b9834e2492..0000000000 --- a/src/org/codehaus/jackson/type/TypeReference.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.codehaus.jackson.type; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -/** - * This class is used to pass full generics type information, and - * avoid problems with type erasure (that basically removes most - * usable type references from runtime Class objects). - * It is based on ideas from - * http://gafter.blogspot.com/2006/12/super-type-tokens.html, - * Additional idea (from a suggestion made in comments of the article) - * is to require bogus implementation of Comparable - * (any such generic interface would do, as long as it forces a method - * with generic type to be implemented). - * to ensure that a Type argument is indeed given. - *

- * Usage is by sub-classing: here is one way to instantiate reference - * to generic type List<Integer>: - *

- *  TypeReference ref = new TypeReference<List<Integer>>() { };
- *
- * which can be passed to methods that accept TypeReference. - */ -public abstract class TypeReference - implements Comparable> -{ - final Type _type; - - protected TypeReference() - { - Type superClass = getClass().getGenericSuperclass(); - if (superClass instanceof Class) { // sanity check, should never happen - throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information"); - } - /* 22-Dec-2008, tatu: Not sure if this case is safe -- I suspect - * it is possible to make it fail? - * But let's deal with specifc - * case when we know an actual use case, and thereby suitable - * work arounds for valid case(s) and/or error to throw - * on invalid one(s). - */ - _type = ((ParameterizedType) superClass).getActualTypeArguments()[0]; - } - - public Type getType() { return _type; } - - /** - * The only reason we define this method (and require implementation - * of Comparable) is to prevent constructing a - * reference without type information. - */ - public int compareTo(TypeReference o) { - // just need an implementation, not a good one... hence: - return 0; - } -} - diff --git a/src/org/codehaus/jackson/util/BufferRecycler.java b/src/org/codehaus/jackson/util/BufferRecycler.java deleted file mode 100644 index b32a64c695..0000000000 --- a/src/org/codehaus/jackson/util/BufferRecycler.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.codehaus.jackson.util; - -/** - * This is a small utility class, whose main functionality is to allow - * simple reuse of raw byte/char buffers. It is usually used through - * ThreadLocal member of the owning class pointing to - * instance of this class through a SoftReference. The - * end result is a low-overhead GC-cleanable recycling: hopefully - * ideal for use by stream readers. - */ -public final class BufferRecycler -{ - public final static int DEFAULT_WRITE_CONCAT_BUFFER_LEN = 2000; - - public enum ByteBufferType { - READ_IO_BUFFER(4000) - /** - * Buffer used for temporarily storing encoded content; used - * for example by UTF-8 encoding writer - */ - ,WRITE_ENCODING_BUFFER(4000) - - /** - * Buffer used for temporarily concatenating output; used for - * example when requesting output as byte array. - */ - ,WRITE_CONCAT_BUFFER(2000) - ; - - private final int size; - - ByteBufferType(int size) { this.size = size; } - } - - public enum CharBufferType { - TOKEN_BUFFER(2000) // Tokenizable input - ,CONCAT_BUFFER(2000) // concatenated output - ,TEXT_BUFFER(200) // Text content from input - ,NAME_COPY_BUFFER(200) // Temporary buffer for getting name characters - ; - - private final int size; - - CharBufferType(int size) { this.size = size; } - } - - final protected byte[][] mByteBuffers = new byte[ByteBufferType.values().length][]; - final protected char[][] mCharBuffers = new char[CharBufferType.values().length][]; - - public BufferRecycler() { } - - public byte[] allocByteBuffer(ByteBufferType type) - { - int ix = type.ordinal(); - byte[] buffer = mByteBuffers[ix]; - if (buffer == null) { - buffer = balloc(type.size); - } else { - mByteBuffers[ix] = null; - } - return buffer; - } - - public void releaseByteBuffer(ByteBufferType type, byte[] buffer) - { - mByteBuffers[type.ordinal()] = buffer; - } - - public char[] allocCharBuffer(CharBufferType type) - { - return allocCharBuffer(type, 0); - } - - public char[] allocCharBuffer(CharBufferType type, int minSize) - { - if (type.size > minSize) { - minSize = type.size; - } - int ix = type.ordinal(); - char[] buffer = mCharBuffers[ix]; - if (buffer == null || buffer.length < minSize) { - buffer = calloc(minSize); - } else { - mCharBuffers[ix] = null; - } - return buffer; - } - - public void releaseCharBuffer(CharBufferType type, char[] buffer) - { - mCharBuffers[type.ordinal()] = buffer; - } - - /* - ////////////////////////////////////////////////////////////// - // Actual allocations separated for easier debugging/profiling - ////////////////////////////////////////////////////////////// - */ - - private byte[] balloc(int size) - { - return new byte[size]; - } - - private char[] calloc(int size) - { - return new char[size]; - } -} diff --git a/src/org/codehaus/jackson/util/ByteArrayBuilder.java b/src/org/codehaus/jackson/util/ByteArrayBuilder.java deleted file mode 100644 index d05228a8d4..0000000000 --- a/src/org/codehaus/jackson/util/ByteArrayBuilder.java +++ /dev/null @@ -1,233 +0,0 @@ -/* Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in file LICENSE, included with - * the source code and binary code bundles. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.codehaus.jackson.util; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.*; - -/** - * Helper class that is similar to {@link java.io.ByteArrayOutputStream} - * in usage, but more geared to Jackson use cases internally. - * Specific changes include segment storage (no need to have linear - * backing buffer, can avoid reallocs, copying), as well API - * not based on {@link java.io.OutputStream}. In short, a very much - * specialized builder object. - *

- * Since version 1.5, also implements {@link OutputStream} to allow - * efficient aggregation of output content as a byte array, similar - * to how {@link java.io.ByteArrayOutputStream} works, but somewhat more - * efficiently for many use cases. - */ -public final class ByteArrayBuilder - extends OutputStream -{ - private final static byte[] NO_BYTES = new byte[0]; - - /** - * Size of the first block we will allocate. - */ - private final static int INITIAL_BLOCK_SIZE = 500; - - /** - * Maximum block size we will use for individual non-aggregated - * blocks. Let's limit to using 256k chunks. - */ - private final static int MAX_BLOCK_SIZE = (1 << 18); - - final static int DEFAULT_BLOCK_ARRAY_SIZE = 40; - - /** - * Optional buffer recycler instance that we can use for allocating - * the first block. - * - * @since 1.5 - */ - private final BufferRecycler _bufferRecycler; - - private final LinkedList _pastBlocks = new LinkedList(); - - /** - * Number of bytes within byte arrays in {@link _pastBlocks}. - */ - private int _pastLen; - - private byte[] _currBlock; - - private int _currBlockPtr; - - public ByteArrayBuilder() { this(null); } - - public ByteArrayBuilder(BufferRecycler br) { this(br, INITIAL_BLOCK_SIZE); } - - public ByteArrayBuilder(int firstBlockSize) { this(null, firstBlockSize); } - - public ByteArrayBuilder(BufferRecycler br, int firstBlockSize) - { - _bufferRecycler = br; - if (br == null) { - _currBlock = new byte[firstBlockSize]; - } else { - _currBlock = br.allocByteBuffer(BufferRecycler.ByteBufferType.WRITE_CONCAT_BUFFER); - } - } - - public void reset() - { - _pastLen = 0; - _currBlockPtr = 0; - - if (!_pastBlocks.isEmpty()) { - _currBlock = _pastBlocks.getLast(); - _pastBlocks.clear(); - } - } - - /** - * Clean up method to call to release all buffers this object may be - * using. After calling the method, no other accessors can be used (and - * attempt to do so may result in an exception) - */ - public void release() { - reset(); - if (_bufferRecycler != null && _currBlock != null) { - _bufferRecycler.releaseByteBuffer(BufferRecycler.ByteBufferType.WRITE_CONCAT_BUFFER, _currBlock); - } - } - - public void append(int i) - { - byte b = (byte) i; - if (_currBlockPtr >= _currBlock.length) { - _allocMore(); - } - _currBlock[_currBlockPtr++] = b; - } - - public void appendTwoBytes(int b16) - { - if ((_currBlockPtr + 1) < _currBlock.length) { - _currBlock[_currBlockPtr++] = (byte) (b16 >> 8); - _currBlock[_currBlockPtr++] = (byte) b16; - } else { - append(b16 >> 8); - append(b16); - } - } - - public void appendThreeBytes(int b24) - { - if ((_currBlockPtr + 2) < _currBlock.length) { - _currBlock[_currBlockPtr++] = (byte) (b24 >> 16); - _currBlock[_currBlockPtr++] = (byte) (b24 >> 8); - _currBlock[_currBlockPtr++] = (byte) b24; - } else { - append(b24 >> 16); - append(b24 >> 8); - append(b24); - } - } - - /** - * Method called when results are finalized and we can get the - * full aggregated result buffer to return to the caller - */ - public byte[] toByteArray() - { - int totalLen = _pastLen + _currBlockPtr; - - if (totalLen == 0) { // quick check: nothing aggregated? - return NO_BYTES; - } - - byte[] result = new byte[totalLen]; - int offset = 0; - - for (byte[] block : _pastBlocks) { - int len = block.length; - System.arraycopy(block, 0, result, offset, len); - offset += len; - } - System.arraycopy(_currBlock, 0, result, offset, _currBlockPtr); - offset += _currBlockPtr; - if (offset != totalLen) { // just a sanity check - throw new RuntimeException("Internal error: total len assumed to be "+totalLen+", copied "+offset+" bytes"); - } - // Let's only reset if there's sizable use, otherwise will get reset later on - if (!_pastBlocks.isEmpty()) { - reset(); - } - return result; - } - - private void _allocMore() - { - _pastLen += _currBlock.length; - - /* Let's allocate block that's half the total size, except - * never smaller than twice the initial block size. - * The idea is just to grow with reasonable rate, to optimize - * between minimal number of chunks and minimal amount of - * wasted space. - */ - int newSize = Math.max((_pastLen >> 1), (INITIAL_BLOCK_SIZE + INITIAL_BLOCK_SIZE)); - // plus not to exceed max we define... - if (newSize > MAX_BLOCK_SIZE) { - newSize = MAX_BLOCK_SIZE; - } - _pastBlocks.add(_currBlock); - _currBlock = new byte[newSize]; - _currBlockPtr = 0; - } - - /* - /******************************************************* - /* OutputStream implementation - /******************************************************* - */ - - @Override - public void write(byte[] b) { - write(b, 0, b.length); - } - - @Override - public void write(byte[] b, int off, int len) - { - while (true) { - int max = _currBlock.length - _currBlockPtr; - int toCopy = Math.min(max, len); - if (toCopy > 0) { - System.arraycopy(b, off, _currBlock, _currBlockPtr, toCopy); - off += toCopy; - _currBlockPtr += toCopy; - len -= toCopy; - } - if (len <= 0) break; - _allocMore(); - } - } - - @Override - public void write(int b) throws IOException { - append(b); - } - - @Override public void close() { /* NOP */ } - - @Override public void flush() { /* NOP */ } -} - diff --git a/src/org/codehaus/jackson/util/CharTypes.java b/src/org/codehaus/jackson/util/CharTypes.java deleted file mode 100644 index 8fee6a44a9..0000000000 --- a/src/org/codehaus/jackson/util/CharTypes.java +++ /dev/null @@ -1,193 +0,0 @@ -package org.codehaus.jackson.util; - -import java.util.Arrays; - -public final class CharTypes -{ - final static char[] HEX_CHARS = "0123456789ABCDEF".toCharArray(); - - /** - * Lookup table used for determining which input characters - * need special handling when contained in text segment. - */ - final static int[] sInputCodes; - static { - /* 96 would do for most cases (backslash is ascii 94) - * but if we want to do lookups by raw bytes it's better - * to have full table - */ - int[] table = new int[256]; - // Control chars and non-space white space are not allowed unquoted - for (int i = 0; i < 32; ++i) { - table[i] = -1; - } - // And then string end and quote markers are special too - table['"'] = 1; - table['\\'] = 1; - sInputCodes = table; - } - - /** - * Additionally we can combine UTF-8 decoding info into similar - * data table. - */ - final static int[] sInputCodesUtf8; - static { - int[] table = new int[sInputCodes.length]; - System.arraycopy(sInputCodes, 0, table, 0, sInputCodes.length); - for (int c = 128; c < 256; ++c) { - int code; - - // We'll add number of bytes needed for decoding - if ((c & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF) - code = 2; - } else if ((c & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF) - code = 3; - } else if ((c & 0xF8) == 0xF0) { - // 4 bytes; double-char with surrogates and all... - code = 4; - } else { - // And -1 seems like a good "universal" error marker... - code = -1; - } - table[c] = code; - } - sInputCodesUtf8 = table; - } - - /** - * To support non-default (and -standard) unquoted field names mode, - * need to have alternate checking. - * Basically this is list of 8-bit ascii characters that are legal - * as part of Javascript identifier - * - * @since 1.2 - */ - final static int[] sInputCodesJsNames; - static { - int[] table = new int[256]; - // Default is "not a name char", mark ones that are - Arrays.fill(table, -1); - // Assume rules with JS same as Java (change if/as needed) - for (int i = 33; i < 256; ++i) { - if (Character.isJavaIdentifierPart((char) i)) { - table[i] = 0; - } - } - sInputCodesJsNames = table; - } - - /** - * This table is similar to Latin1, except that it marks all "high-bit" - * code as ok. They will be validated at a later point, when decoding - * name - */ - final static int[] sInputCodesUtf8JsNames; - static { - int[] table = new int[256]; - // start with 8-bit JS names - System.arraycopy(sInputCodesJsNames, 0, table, 0, sInputCodesJsNames.length); - Arrays.fill(table, 128, 128, 0); - sInputCodesUtf8JsNames = table; - } - - /** - * Decoding table used to quickly determine characters that are - * relevant within comment content - */ - final static int[] sInputCodesComment = new int[256]; - static { - // but first: let's start with UTF-8 multi-byte markers: - System.arraycopy(sInputCodesUtf8, 128, sInputCodesComment, 128, 128); - - // default (0) means "ok" (skip); -1 invalid, others marked by char itself - Arrays.fill(sInputCodesComment, 0, 32, -1); // invalid white space - sInputCodesComment['\t'] = 0; // tab is still fine - sInputCodesComment['\n'] = '\n'; // lf/cr need to be observed, ends cpp comment - sInputCodesComment['\r'] = '\r'; - sInputCodesComment['*'] = '*'; // end marker for c-style comments - } - - /** - * Lookup table used for determining which output characters - * need to be quoted. - */ - final static int[] sOutputEscapes; - static { - int[] table = new int[256]; - // Control chars need generic escape sequence - for (int i = 0; i < 32; ++i) { - table[i] = -(i + 1); - } - /* Others (and some within that range too) have explicit shorter - * sequences - */ - table['"'] = '"'; - table['\\'] = '\\'; - // Escaping of slash is optional, so let's not add it - table[0x08] = 'b'; - table[0x09] = 't'; - table[0x0C] = 'f'; - table[0x0A] = 'n'; - table[0x0D] = 'r'; - sOutputEscapes = table; - } - - /** - * Lookup table for the first 128 Unicode characters (7-bit ascii) - * range. For actual hex digits, contains corresponding value; - * for others -1. - */ - final static int[] sHexValues = new int[128]; - static { - Arrays.fill(sHexValues, -1); - for (int i = 0; i < 10; ++i) { - sHexValues['0' + i] = i; - } - for (int i = 0; i < 6; ++i) { - sHexValues['a' + i] = 10 + i; - sHexValues['A' + i] = 10 + i; - } - } - - public final static int[] getInputCodeLatin1() { return sInputCodes; } - public final static int[] getInputCodeUtf8() { return sInputCodesUtf8; } - - public final static int[] getInputCodeLatin1JsNames() { return sInputCodesJsNames; } - public final static int[] getInputCodeUtf8JsNames() { return sInputCodesUtf8JsNames; } - - public final static int[] getInputCodeComment() { return sInputCodesComment; } - public final static int[] getOutputEscapes() { return sOutputEscapes; } - - public static int charToHex(int ch) - { - return (ch > 127) ? -1 : sHexValues[ch]; - } - - public static void appendQuoted(StringBuilder sb, String content) - { - final int[] escCodes = sOutputEscapes; - int escLen = escCodes.length; - for (int i = 0, len = content.length(); i < len; ++i) { - char c = content.charAt(i); - if (c >= escLen || escCodes[c] == 0) { - sb.append(c); - continue; - } - sb.append('\\'); - int escCode = escCodes[c]; - if (escCode < 0) { // generic quoting (hex value) - // We know that it has to fit in just 2 hex chars - sb.append('u'); - sb.append('0'); - sb.append('0'); - int value = -(escCode + 1); - sb.append(HEX_CHARS[value >> 4]); - sb.append(HEX_CHARS[value & 0xF]); - } else { // "named", i.e. prepend with slash - sb.append((char) escCode); - } - } - } -} - diff --git a/src/org/codehaus/jackson/util/InternCache.java b/src/org/codehaus/jackson/util/InternCache.java deleted file mode 100644 index 0246409626..0000000000 --- a/src/org/codehaus/jackson/util/InternCache.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.codehaus.jackson.util; - -import java.util.Map; -import java.util.LinkedHashMap; - -/** - * Singleton class that adds a simple first-level cache in front of - * regular String.intern() functionality. This is done as a minor - * performance optimization, to avoid calling native intern() method - * in cases where same String is being interned multiple times. - *

- * Note: that this class extends {@link LinkedHashMap} is an implementation - * detail -- no code should ever directly call Map methods. - */ -@SuppressWarnings("serial") -public final class InternCache - extends LinkedHashMap -{ - /** - * Size to use is somewhat arbitrary, so let's choose something that's - * neither too small (low hit ratio) nor too large (waste of memory) - */ - private final static int MAX_ENTRIES = 192; - - public final static InternCache instance = new InternCache(); - - private InternCache() { - super(MAX_ENTRIES, 0.8f, true); - } - - protected boolean removeEldestEntry(Map.Entry eldest) - { - return size() > MAX_ENTRIES; - } - - public synchronized String intern(String input) - { - String result = get(input); - if (result == null) { - result = input.intern(); - put(result, result); - } - return result; - } - - -} - diff --git a/src/org/codehaus/jackson/util/JsonGeneratorDelegate.java b/src/org/codehaus/jackson/util/JsonGeneratorDelegate.java deleted file mode 100644 index 186ced2c72..0000000000 --- a/src/org/codehaus/jackson/util/JsonGeneratorDelegate.java +++ /dev/null @@ -1,225 +0,0 @@ -package org.codehaus.jackson.util; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; - -import org.codehaus.jackson.Base64Variant; -import org.codehaus.jackson.JsonGenerationException; -import org.codehaus.jackson.JsonGenerator; -import org.codehaus.jackson.JsonNode; -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonProcessingException; -import org.codehaus.jackson.JsonStreamContext; -import org.codehaus.jackson.ObjectCodec; - -public class JsonGeneratorDelegate extends JsonGenerator -{ - /** - * Delegate object that method calls are delegated to. - */ - protected JsonGenerator delegate; - - public JsonGeneratorDelegate(JsonGenerator d) { - delegate = d; - } - - @Override - public void close() throws IOException { - delegate.close(); - } - - @Override - public void copyCurrentEvent(JsonParser jp) throws IOException, JsonProcessingException { - delegate.copyCurrentEvent(jp); - } - - @Override - public void copyCurrentStructure(JsonParser jp) throws IOException, JsonProcessingException { - delegate.copyCurrentStructure(jp); - } - - @Override - public JsonGenerator disable(Feature f) { - return delegate.disable(f); - } - - @Override - public JsonGenerator enable(Feature f) { - return delegate.enable(f); - } - - @Override - public void flush() throws IOException { - delegate.flush(); - } - - @Override - public ObjectCodec getCodec() { - return delegate.getCodec(); - } - - @Override - public JsonStreamContext getOutputContext() { - return delegate.getOutputContext(); - } - - @Override - public boolean isClosed() { - return delegate.isClosed(); - } - - @Override - public boolean isEnabled(Feature f) { - return delegate.isEnabled(f); - } - - @Override - public JsonGenerator setCodec(ObjectCodec oc) { - delegate.setCodec(oc); - return this; - } - - @Override - public JsonGenerator useDefaultPrettyPrinter() { - delegate.useDefaultPrettyPrinter(); - return this; - } - - @Override - public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) - throws IOException, JsonGenerationException - { - delegate.writeBinary(b64variant, data, offset, len); - } - - @Override - public void writeBoolean(boolean state) throws IOException, JsonGenerationException { - delegate.writeBoolean(state); - } - - @Override - public void writeEndArray() throws IOException, JsonGenerationException { - delegate.writeEndArray(); - } - - @Override - public void writeEndObject() throws IOException, JsonGenerationException { - delegate.writeEndObject(); - } - - @Override - public void writeFieldName(String name) throws IOException, - JsonGenerationException { - delegate.writeFieldName(name); - } - - @Override - public void writeNull() throws IOException, JsonGenerationException { - delegate.writeNull(); - } - - @Override - public void writeNumber(int v) throws IOException, JsonGenerationException { - delegate.writeNumber(v); - } - - @Override - public void writeNumber(long v) throws IOException, JsonGenerationException { - delegate.writeNumber(v); - } - - @Override - public void writeNumber(BigInteger v) throws IOException, - JsonGenerationException { - delegate.writeNumber(v); - } - - @Override - public void writeNumber(double v) throws IOException, - JsonGenerationException { - delegate.writeNumber(v); - } - - @Override - public void writeNumber(float v) throws IOException, - JsonGenerationException { - delegate.writeNumber(v); - } - - @Override - public void writeNumber(BigDecimal v) throws IOException, - JsonGenerationException { - delegate.writeNumber(v); - } - - @Override - public void writeNumber(String encodedValue) throws IOException, JsonGenerationException, UnsupportedOperationException { - delegate.writeNumber(encodedValue); - } - - @Override - public void writeObject(Object pojo) throws IOException,JsonProcessingException { - delegate.writeObject(pojo); - } - - @Override - public void writeRaw(String text) throws IOException, JsonGenerationException { - delegate.writeRaw(text); - } - - @Override - public void writeRaw(String text, int offset, int len) throws IOException, JsonGenerationException { - delegate.writeRaw(text, offset, len); - } - - @Override - public void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException { - delegate.writeRaw(text, offset, len); - } - - @Override - public void writeRaw(char c) throws IOException, JsonGenerationException { - delegate.writeRaw(c); - } - - @Override - public void writeRawValue(String text) throws IOException, JsonGenerationException { - delegate.writeRawValue(text); - } - - @Override - public void writeRawValue(String text, int offset, int len) throws IOException, JsonGenerationException { - delegate.writeRawValue(text, offset, len); - } - - @Override - public void writeRawValue(char[] text, int offset, int len) throws IOException, JsonGenerationException { - delegate.writeRawValue(text, offset, len); - } - - @Override - public void writeStartArray() throws IOException, JsonGenerationException { - delegate.writeStartArray(); - } - - @Override - public void writeStartObject() throws IOException, JsonGenerationException { - delegate.writeStartObject(); - } - - @Override - public void writeString(String text) throws IOException,JsonGenerationException { - delegate.writeString(text); - } - - @Override - public void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException { - delegate.writeString(text, offset, len); - } - - @Override - public void writeTree(JsonNode rootNode) throws IOException, JsonProcessingException { - delegate.writeTree(rootNode); - } -} diff --git a/src/org/codehaus/jackson/util/JsonParserDelegate.java b/src/org/codehaus/jackson/util/JsonParserDelegate.java deleted file mode 100644 index 51e564d2a3..0000000000 --- a/src/org/codehaus/jackson/util/JsonParserDelegate.java +++ /dev/null @@ -1,217 +0,0 @@ -package org.codehaus.jackson.util; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; - -import org.codehaus.jackson.*; - -/** - * Helper class that implements - * delegation pattern for {@link JsonParser}, - * to allow for simple overridability of basic parsing functionality. - * The idea is that any functionality to be modified can be simply - * overridden; and anything else will be delegated by default. - * - * @since 1.4 - */ -public class JsonParserDelegate extends JsonParser -{ - /** - * Delegate object that method calls are delegated to. - */ - protected JsonParser delegate; - - public JsonParserDelegate(JsonParser d) { - delegate = d; - } - - /* - /************************************************** - /* Public API, configuration - /************************************************** - */ - - @Override - public void setCodec(ObjectCodec c) { - delegate.setCodec(c); - } - - @Override - public ObjectCodec getCodec() { - return delegate.getCodec(); - } - - public JsonParser enable(Feature f) { - delegate.enable(f); - return this; - } - - public JsonParser disable(Feature f) { - delegate.disable(f); - return this; - } - - public boolean isEnabled(Feature f) { - return delegate.isEnabled(f); - } - - /* - /************************************************** - /* Closeable impl - /************************************************** - */ - - @Override - public void close() throws IOException { - delegate.close(); - } - - @Override - public boolean isClosed() { - return delegate.isClosed(); - } - - /* - /************************************************** - /* Public API, token accessors - /************************************************** - */ - - public JsonToken getCurrentToken() { - return delegate.getCurrentToken(); - } - - public boolean hasCurrentToken() { - return delegate.hasCurrentToken(); - } - - public void clearCurrentToken() { - delegate.clearCurrentToken(); - } - - @Override - public String getCurrentName() throws IOException, JsonParseException { - return delegate.getCurrentName(); - } - - @Override - public JsonLocation getCurrentLocation() { - return delegate.getCurrentLocation(); - } - - @Override - public JsonToken getLastClearedToken() { - return delegate.getLastClearedToken(); - } - - @Override - public JsonStreamContext getParsingContext() { - return delegate.getParsingContext(); - } - - /* - /************************************************** - /* Public API, access to token information, text - /************************************************** - */ - - @Override - public String getText() throws IOException, JsonParseException { - return delegate.getText(); - } - - @Override - public char[] getTextCharacters() throws IOException, JsonParseException { - return delegate.getTextCharacters(); - } - - @Override - public int getTextLength() throws IOException, JsonParseException { - return delegate.getTextLength(); - } - - @Override - public int getTextOffset() throws IOException, JsonParseException { - return delegate.getTextOffset(); - } - - - /* - /************************************************** - /* Public API, access to token information, numeric - /************************************************** - */ - - @Override - public BigInteger getBigIntegerValue() throws IOException,JsonParseException { - return delegate.getBigIntegerValue(); - } - - @Override - public byte getByteValue() throws IOException, JsonParseException { - return delegate.getByteValue(); - } - - @Override - public short getShortValue() throws IOException, JsonParseException { - return delegate.getShortValue(); - } - - @Override - public BigDecimal getDecimalValue() throws IOException, JsonParseException { - return delegate.getDecimalValue(); - } - - @Override - public double getDoubleValue() throws IOException, JsonParseException { - return delegate.getDoubleValue(); - } - - @Override - public float getFloatValue() throws IOException, JsonParseException { - return delegate.getFloatValue(); - } - - @Override - public int getIntValue() throws IOException, JsonParseException { - return delegate.getIntValue(); - } - - @Override - public long getLongValue() throws IOException, JsonParseException { - return delegate.getLongValue(); - } - - @Override - public NumberType getNumberType() throws IOException, JsonParseException { - return delegate.getNumberType(); - } - - @Override - public Number getNumberValue() throws IOException, JsonParseException { - return delegate.getNumberValue(); - } - - @Override - public byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException { - return delegate.getBinaryValue(b64variant); - } - - @Override - public JsonLocation getTokenLocation() { - return delegate.getTokenLocation(); - } - - @Override - public JsonToken nextToken() throws IOException, JsonParseException { - return delegate.nextToken(); - } - - @Override - public JsonParser skipChildren() throws IOException, JsonParseException { - delegate.skipChildren(); - // NOTE: must NOT delegate this method to delegate, needs to be self-reference for chaining - return this; - } -} diff --git a/src/org/codehaus/jackson/util/JsonParserSequence.java b/src/org/codehaus/jackson/util/JsonParserSequence.java deleted file mode 100644 index 4d49d009b9..0000000000 --- a/src/org/codehaus/jackson/util/JsonParserSequence.java +++ /dev/null @@ -1,150 +0,0 @@ -package org.codehaus.jackson.util; - -import java.io.IOException; -import java.util.*; - -import org.codehaus.jackson.*; - -/** - * Helper class that can be used to sequence multiple physical - * {@link JsonParser}s to create a single logical sequence of - * tokens, as a single {@link JsonParser}. - *

- * Fairly simple use of {@link JsonParserDelegate}: only need - * to override {@link #nextToken} to handle transition - * - * @author tatu - * @since 1.5 - */ -public class JsonParserSequence extends JsonParserDelegate -{ - /** - * Parsers other than the first one (which is initially assigned - * as delegate) - */ - protected final JsonParser[] _parsers; - - /** - * Index of the next parser in {@link #_parsers}. - */ - protected int _nextParser; - - /* - ******************************************************* - * Construction - ******************************************************* - */ - - protected JsonParserSequence(JsonParser[] parsers) - { - super(parsers[0]); - _parsers = parsers; - _nextParser = 1; - } - - /** - * Method that will construct a parser (possibly a sequence) that - * contains all given sub-parsers. - * All parsers given are checked to see if they are sequences: and - * if so, they will be "flattened", that is, contained parsers are - * directly added in a new sequence instead of adding sequences - * within sequences. This is done to minimize delegation depth, - * ideally only having just a single level of delegation. - */ - public static JsonParserSequence createFlattened(JsonParser first, JsonParser second) - { - if (!(first instanceof JsonParserSequence || second instanceof JsonParserSequence)) { - // simple: - return new JsonParserSequence(new JsonParser[] { first, second }); - } - ArrayList p = new ArrayList(); - if (first instanceof JsonParserSequence) { - ((JsonParserSequence) first).addFlattenedActiveParsers(p); - } else { - p.add(first); - } - if (second instanceof JsonParserSequence) { - ((JsonParserSequence) second).addFlattenedActiveParsers(p); - } else { - p.add(second); - } - return new JsonParserSequence(p.toArray(new JsonParser[p.size()])); - } - - protected void addFlattenedActiveParsers(List result) - { - for (int i = _nextParser-1, len = _parsers.length; i < len; ++i) { - JsonParser p = _parsers[i]; - if (p instanceof JsonParserSequence) { - ((JsonParserSequence) p).addFlattenedActiveParsers(result); - } else { - result.add(p); - } - } - } - - /* - ******************************************************* - * Overridden methods, needed: cases where default - * delegation does not work - ******************************************************* - */ - - @Override - public void close() throws IOException - { - do { - delegate.close(); - } while (switchToNext()); - } - - @Override - public JsonToken nextToken() throws IOException, JsonParseException - { - JsonToken t = delegate.nextToken(); - if (t != null) return t; - while (switchToNext()) { - t = delegate.nextToken(); - if (t != null) return t; - } - return null; - } - - /* - /******************************************************* - /* Additional extended API - /******************************************************* - */ - - /** - * Method that is most useful for debugging or testing; - * returns actual number of underlying parsers sequence - * was constructed with (nor just ones remaining active) - */ - public int containedParsersCount() { - return _parsers.length; - } - - /* - /******************************************************* - /* Helper methods - /******************************************************* - */ - - /** - * Method that will switch active parser from the current one - * to next parser in sequence, if there is another parser left, - * making this the new delegate. Old delegate is returned if - * switch succeeds. - * - * @return True if switch succeeded; false otherwise - */ - protected boolean switchToNext() - { - if (_nextParser >= _parsers.length) { - return false; - } - delegate = _parsers[_nextParser++]; - return true; - } -} diff --git a/src/org/codehaus/jackson/util/TextBuffer.java b/src/org/codehaus/jackson/util/TextBuffer.java deleted file mode 100644 index 62c6abfed9..0000000000 --- a/src/org/codehaus/jackson/util/TextBuffer.java +++ /dev/null @@ -1,634 +0,0 @@ -package org.codehaus.jackson.util; - -import java.math.BigDecimal; -import java.util.ArrayList; - -/** - * TextBuffer is a class similar to {@link StringBuffer}, with - * following differences: - *

    - *
  • TextBuffer uses segments character arrays, to avoid having - * to do additional array copies when array is not big enough. - * This means that only reallocating that is necessary is done only once: - * if and when caller - * wants to access contents in a linear array (char[], String). - *
  • -*
  • TextBuffer can also be initialized in "shared mode", in which -* it will just act as a wrapper to a single char array managed -* by another object (like parser that owns it) - *
  • - *
  • TextBuffer is not synchronized. - *
  • - *
- */ -public final class TextBuffer -{ - final static char[] NO_CHARS = new char[0]; - - /** - * Let's limit maximum segment length to something sensible - * like 256k - */ - final static int MAX_SEGMENT_LEN = 0x40000; - - /* - ////////////////////////////// - // Configuration: - ////////////////////////////// - */ - - private final BufferRecycler _allocator; - - /* - ////////////////////////////// - // Shared input buffers - ////////////////////////////// - */ - - /** - * Shared input buffer; stored here in case some input can be returned - * as is, without being copied to collector's own buffers. Note that - * this is read-only for this Object. - */ - private char[] _inputBuffer; - - /** - * Character offset of first char in input buffer; -1 to indicate - * that input buffer currently does not contain any useful char data - */ - private int _inputStart; - - private int _inputLen; - - /* - ////////////////////////////////////////////////// - // Aggregation segments (when not using input buf) - ////////////////////////////////////////////////// - */ - - /** - * List of segments prior to currently active segment. - */ - private ArrayList _segments; - - /** - * Flag that indicates whether _seqments is non-empty - */ - private boolean _hasSegments = false; - - // // // Currently used segment; not (yet) contained in _seqments - - /** - * Amount of characters in segments in {@link _segments} - */ - private int _segmentSize; - - private char[] _currentSegment; - - /** - * Number of characters in currently active (last) segment - */ - private int _currentSize; - - /* - ////////////////////////////////////////////////// - // Caching of results - ////////////////////////////////////////////////// - */ - - /** - * String that will be constructed when the whole contents are - * needed; will be temporarily stored in case asked for again. - */ - private String _resultString; - - private char[] _resultArray; - - /* - ////////////////////////////////////////////// - // Life-cycle - ////////////////////////////////////////////// - */ - - public TextBuffer(BufferRecycler allocator) - { - _allocator = allocator; - } - - /** - * Method called to indicate that the underlying buffers should now - * be recycled if they haven't yet been recycled. Although caller - * can still use this text buffer, it is not advisable to call this - * method if that is likely, since next time a buffer is needed, - * buffers need to reallocated. - * Note: calling this method automatically also clears contents - * of the buffer. - */ - public void releaseBuffers() - { - if (_allocator != null && _currentSegment != null) { - // First, let's get rid of all but the largest char array - resetWithEmpty(); - // And then return that array - char[] buf = _currentSegment; - _currentSegment = null; - _allocator.releaseCharBuffer(BufferRecycler.CharBufferType.TEXT_BUFFER, buf); - } - } - - /** - * Method called to clear out any content text buffer may have, and - * initializes buffer to use non-shared data. - */ - public void resetWithEmpty() - { - _inputBuffer = null; - _inputStart = -1; // indicates shared buffer not used - _inputLen = 0; - - _resultString = null; - _resultArray = null; - - // And then reset internal input buffers, if necessary: - if (_hasSegments) { - clearSegments(); - } - _currentSize = 0; - } - - /** - * Method called to initialize the buffer with a shared copy of data; - * this means that buffer will just have pointers to actual data. It - * also means that if anything is to be appended to the buffer, it - * will first have to unshare it (make a local copy). - */ - public void resetWithShared(char[] buf, int start, int len) - { - // First, let's clear intermediate values, if any: - _resultString = null; - _resultArray = null; - - // Then let's mark things we need about input buffer - _inputBuffer = buf; - _inputStart = start; - _inputLen = len; - - // And then reset internal input buffers, if necessary: - if (_hasSegments) { - clearSegments(); - } - } - - public void resetWithCopy(char[] buf, int start, int len) - { - _inputBuffer = null; - _inputStart = -1; // indicates shared buffer not used - _inputLen = 0; - - _resultString = null; - _resultArray = null; - - // And then reset internal input buffers, if necessary: - if (_hasSegments) { - clearSegments(); - } else if (_currentSegment == null) { - _currentSegment = findBuffer(len); - } - _currentSize = _segmentSize = 0; - append(buf, start, len); - } - - /** - * Helper method used to find a buffer to use, ideally one - * recycled earlier. - */ - private final char[] findBuffer(int needed) - { - return _allocator.allocCharBuffer(BufferRecycler.CharBufferType.TEXT_BUFFER, needed); - } - - private final void clearSegments() - { - _hasSegments = false; - /* Let's start using _last_ segment from list; for one, it's - * the biggest one, and it's also most likely to be cached - */ - /* 28-Aug-2009, tatu: Actually, the current segment should - * be the biggest one, already - */ - //_currentSegment = _segments.get(_segments.size() - 1); - _segments.clear(); - _currentSize = _segmentSize = 0; - } - - /* - ////////////////////////////////////////////// - // Accessors for implementing public interface - ////////////////////////////////////////////// - */ - - /** - * @return Number of characters currently stored by this collector - */ - public int size() { - if (_inputStart >= 0) { // shared copy from input buf - return _inputLen; - } - // local segmented buffers - return _segmentSize + _currentSize; - } - - public int getTextOffset() - { - /* Only shared input buffer can have non-zero offset; buffer - * segments start at 0, and if we have to create a combo buffer, - * that too will start from beginning of the buffer - */ - return (_inputStart >= 0) ? _inputStart : 0; - } - - public char[] getTextBuffer() - { - // Are we just using shared input buffer? - if (_inputStart >= 0) { - return _inputBuffer; - } - // Nope; but does it fit in just one segment? - if (!_hasSegments) { - return _currentSegment; - } - // Nope, need to have/create a non-segmented array and return it - return contentsAsArray(); - } - - /* - ////////////////////////////////////////////// - // Other accessors: - ////////////////////////////////////////////// - */ - - public String contentsAsString() - { - if (_resultString == null) { - // Has array been requested? Can make a shortcut, if so: - if (_resultArray != null) { - _resultString = new String(_resultArray); - } else { - // Do we use shared array? - if (_inputStart >= 0) { - if (_inputLen < 1) { - return (_resultString = ""); - } - _resultString = new String(_inputBuffer, _inputStart, _inputLen); - } else { // nope... need to copy - // But first, let's see if we have just one buffer - int segLen = _segmentSize; - int currLen = _currentSize; - - if (segLen == 0) { // yup - _resultString = (currLen == 0) ? "" : new String(_currentSegment, 0, currLen); - } else { // no, need to combine - StringBuilder sb = new StringBuilder(segLen + currLen); - // First stored segments - if (_segments != null) { - for (int i = 0, len = _segments.size(); i < len; ++i) { - char[] curr = _segments.get(i); - sb.append(curr, 0, curr.length); - } - } - // And finally, current segment: - sb.append(_currentSegment, 0, _currentSize); - _resultString = sb.toString(); - } - } - } - } - return _resultString; - } - - public char[] contentsAsArray() - { - char[] result = _resultArray; - if (result == null) { - _resultArray = result = buildResultArray(); - } - return result; - } - - /** - * Convenience method for converting contents of the buffer - * into a {@link BigDecimal}. - */ - public BigDecimal contentsAsDecimal() - throws NumberFormatException - { - // Already got a pre-cut array? - if (_resultArray != null) { - return new BigDecimal(_resultArray); - } - // Or a shared buffer? - if (_inputStart >= 0) { - return new BigDecimal(_inputBuffer, _inputStart, _inputLen); - } - // Or if not, just a single buffer (the usual case) - if (_segmentSize == 0) { - return new BigDecimal(_currentSegment, 0, _currentSize); - } - // If not, let's just get it aggregated... - return new BigDecimal(contentsAsArray()); - } - - /** - * Convenience method for converting contents of the buffer - * into a Double value. - */ - public double contentsAsDouble() - throws NumberFormatException - { - return Double.parseDouble(contentsAsString()); - } - - /* - ////////////////////////////////////////////// - // Public mutators: - ////////////////////////////////////////////// - */ - - /** - * Method called to make sure that buffer is not using shared input - * buffer; if it is, it will copy such contents to private buffer. - */ - public void ensureNotShared() { - if (_inputStart >= 0) { - unshare(16); - } - } - - public void append(char c) { - // Using shared buffer so far? - if (_inputStart >= 0) { - unshare(16); - } - _resultString = null; - _resultArray = null; - // Room in current segment? - char[] curr = _currentSegment; - if (_currentSize >= curr.length) { - expand(1); - curr = _currentSegment; - } - curr[_currentSize++] = c; - } - - public void append(char[] c, int start, int len) - { - // Can't append to shared buf (sanity check) - if (_inputStart >= 0) { - unshare(len); - } - _resultString = null; - _resultArray = null; - - // Room in current segment? - char[] curr = _currentSegment; - int max = curr.length - _currentSize; - - if (max >= len) { - System.arraycopy(c, start, curr, _currentSize, len); - _currentSize += len; - } else { - // No room for all, need to copy part(s): - if (max > 0) { - System.arraycopy(c, start, curr, _currentSize, max); - start += max; - len -= max; - } - // And then allocate new segment; we are guaranteed to now - // have enough room in segment. - expand(len); // note: curr != _currentSegment after this - System.arraycopy(c, start, _currentSegment, 0, len); - _currentSize = len; - } - } - - public void append(String str, int offset, int len) - { - // Can't append to shared buf (sanity check) - if (_inputStart >= 0) { - unshare(len); - } - _resultString = null; - _resultArray = null; - - // Room in current segment? - char[] curr = _currentSegment; - int max = curr.length - _currentSize; - if (max >= len) { - str.getChars(offset, offset+len, curr, _currentSize); - _currentSize += len; - } else { - // No room for all, need to copy part(s): - if (max > 0) { - str.getChars(offset, offset+max, curr, _currentSize); - len -= max; - offset += max; - } - /* And then allocate new segment; we are guaranteed to now - * have enough room in segment. - */ - expand(len); - str.getChars(offset, offset+len, _currentSegment, 0); - _currentSize = len; - } - } - - /* - ////////////////////////////////////////////// - // Raw access, for high-performance use: - ////////////////////////////////////////////// - */ - - public char[] getCurrentSegment() - { - /* Since the intention of the caller is to directly add stuff into - * buffers, we should NOT have anything in shared buffer... ie. may - * need to unshare contents. - */ - if (_inputStart >= 0) { - unshare(1); - } else { - char[] curr = _currentSegment; - if (curr == null) { - _currentSegment = findBuffer(0); - } else if (_currentSize >= curr.length) { - // Plus, we better have room for at least one more char - expand(1); - } - } - return _currentSegment; - } - - public char[] emptyAndGetCurrentSegment() - { - resetWithEmpty(); - char[] curr = _currentSegment; - if (curr == null) { - _currentSegment = curr = findBuffer(0); - } - return curr; - } - - public int getCurrentSegmentSize() { - return _currentSize; - } - - public void setCurrentLength(int len) { - _currentSize = len; - } - - public char[] finishCurrentSegment() - { - if (_segments == null) { - _segments = new ArrayList(); - } - _hasSegments = true; - _segments.add(_currentSegment); - int oldLen = _currentSegment.length; - _segmentSize += oldLen; - // Let's grow segments by 50% - int newLen = Math.min(oldLen + (oldLen >> 1), MAX_SEGMENT_LEN); - char[] curr = _charArray(newLen); - _currentSize = 0; - _currentSegment = curr; - return curr; - } - - /** - * Method called to expand size of the current segment, to - * accomodate for more contiguous content. Usually only - * used when parsing tokens like names. - */ - public char[] expandCurrentSegment() - { - char[] curr = _currentSegment; - // Let's grow by 50% - int len = curr.length; - // Must grow by at least 1 char, no matter what - int newLen = (len == MAX_SEGMENT_LEN) ? - (MAX_SEGMENT_LEN + 1) : Math.min(MAX_SEGMENT_LEN, len + (len >> 1)); - _currentSegment = _charArray(newLen); - System.arraycopy(curr, 0, _currentSegment, 0, len); - return _currentSegment; - } - - /* - ////////////////////////////////////////////// - // Standard methods: - ////////////////////////////////////////////// - */ - - /** - * Note: calling this method may not be as efficient as calling - * {@link #contentsAsString}, since it's not guaranteed that resulting - * String is cached. - */ - @Override - public String toString() { - return contentsAsString(); - } - - /* - ////////////////////////////////////////////// - // Internal methods: - ////////////////////////////////////////////// - */ - - /** - * Method called if/when we need to append content when we have been - * initialized to use shared buffer. - */ - private void unshare(int needExtra) - { - int sharedLen = _inputLen; - _inputLen = 0; - char[] inputBuf = _inputBuffer; - _inputBuffer = null; - int start = _inputStart; - _inputStart = -1; - - // Is buffer big enough, or do we need to reallocate? - int needed = sharedLen+needExtra; - if (_currentSegment == null || needed > _currentSegment.length) { - _currentSegment = findBuffer(needed); - } - if (sharedLen > 0) { - System.arraycopy(inputBuf, start, _currentSegment, 0, sharedLen); - } - _segmentSize = 0; - _currentSize = sharedLen; - } - - /** - * Method called when current segment is full, to allocate new - * segment. - */ - private void expand(int minNewSegmentSize) - { - // First, let's move current segment to segment list: - if (_segments == null) { - _segments = new ArrayList(); - } - char[] curr = _currentSegment; - _hasSegments = true; - _segments.add(curr); - _segmentSize += curr.length; - int oldLen = curr.length; - // Let's grow segments by 50% minimum - int sizeAddition = oldLen >> 1; - if (sizeAddition < minNewSegmentSize) { - sizeAddition = minNewSegmentSize; - } - curr = _charArray(Math.min(MAX_SEGMENT_LEN, oldLen + sizeAddition)); - _currentSize = 0; - _currentSegment = curr; - } - - private char[] buildResultArray() - { - if (_resultString != null) { // Can take a shortcut... - return _resultString.toCharArray(); - } - char[] result; - - // Do we use shared array? - if (_inputStart >= 0) { - if (_inputLen < 1) { - return NO_CHARS; - } - result = _charArray(_inputLen); - System.arraycopy(_inputBuffer, _inputStart, result, 0, - _inputLen); - } else { // nope - int size = size(); - if (size < 1) { - return NO_CHARS; - } - int offset = 0; - result = _charArray(size); - if (_segments != null) { - for (int i = 0, len = _segments.size(); i < len; ++i) { - char[] curr = (char[]) _segments.get(i); - int currLen = curr.length; - System.arraycopy(curr, 0, result, offset, currLen); - offset += currLen; - } - } - System.arraycopy(_currentSegment, 0, result, offset, _currentSize); - } - return result; - } - - private final char[] _charArray(int len) { - return new char[len]; - } -} diff --git a/src/org/codehaus/jackson/util/TokenBuffer.java b/src/org/codehaus/jackson/util/TokenBuffer.java deleted file mode 100644 index 9688c1103c..0000000000 --- a/src/org/codehaus/jackson/util/TokenBuffer.java +++ /dev/null @@ -1,1235 +0,0 @@ -package org.codehaus.jackson.util; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; - -import org.codehaus.jackson.*; -import org.codehaus.jackson.impl.JsonReadContext; -import org.codehaus.jackson.impl.JsonWriteContext; - -/** - * Utility class used for efficient storage of {@link JsonToken} - * sequences, needed for temporary buffering. - * Space efficient for different sequence lengths (especially so for smaller - * ones; but not significantly less efficient for larger), highly efficient - * for linear iteration and appending. Implemented as segmented/chunked - * linked list of tokens; only modifications are via appends. - * - * @since 1.5 - */ -public class TokenBuffer -/* Won't use JsonGeneratorBase, to minimize overhead for validity - * checking - */ - extends JsonGenerator -{ - final static int DEFAULT_FEATURES = JsonParser.Feature.collectDefaults(); - - /* - *********************************************** - * Configuration - *********************************************** - */ - - /** - * Object codec to use for stream-based object - * conversion through parser/generator interfaces. If null, - * such methods can not be used. - */ - protected ObjectCodec _objectCodec; - - /** - * Bit flag composed of bits that indicate which - * {@link org.codehaus.jackson.JsonGenerator.Feature}s - * are enabled. - *

- * NOTE: most features have no effect on this class - */ - protected int _generatorFeatures; - - protected boolean _closed; - - /* - *********************************************** - * Token buffering state - *********************************************** - */ - - /** - * First segment, for contents this buffer has - */ - protected Segment _first; - - /** - * Last segment of this buffer, one that is used - * for appending more tokens - */ - protected Segment _last; - - /** - * Offset within last segment, - */ - protected int _appendOffset; - - /* - *********************************************** - * Output state - *********************************************** - */ - - protected JsonWriteContext _writeContext; - - /* - *********************************************** - * Life-cycle - *********************************************** - */ - - /** - * @param codec Object codec to use for stream-based object - * conversion through parser/generator interfaces. If null, - * such methods can not be used. - */ - public TokenBuffer(ObjectCodec codec) - { - _objectCodec = codec; - _generatorFeatures = DEFAULT_FEATURES; - _writeContext = JsonWriteContext.createRootContext(); - // at first we have just one segment - _first = _last = new Segment(); - _appendOffset = 0; - } - - /** - * Method used to create a {@link JsonParser} that can read contents - * stored in this buffer. Will use default _objectCodec for - * object conversions. - *

- * Note: instances are not synchronized, that is, they are not thread-safe - * if there are concurrent appends to the underlying buffer. - * - * @return Parser that can be used for reading contents stored in this buffer - */ - public JsonParser asParser() - { - return asParser(_objectCodec); - } - - /** - * Method used to create a {@link JsonParser} that can read contents - * stored in this buffer. - *

- * Note: instances are not synchronized, that is, they are not thread-safe - * if there are concurrent appends to the underlying buffer. - * - * @param codec Object codec to use for stream-based object - * conversion through parser/generator interfaces. If null, - * such methods can not be used. - * - * @return Parser that can be used for reading contents stored in this buffer - */ - public JsonParser asParser(ObjectCodec codec) - { - return new Parser(_first, codec); - } - - /** - * @param src Parser to use for accessing source information - * like location, configured codec - */ - public JsonParser asParser(JsonParser src) - { - Parser p = new Parser(_first, src.getCodec()); - p.setLocation(src.getTokenLocation()); - return p; - } - - /* - ***************************************************************** - * Other custom methods not needed for implementing interfaces - ***************************************************************** - */ - - /** - * Helper method that will write all contents of this buffer - * using given {@link JsonGenerator}. - *

- * Note: this method would be enough to implement - * JsonSerializer for TokenBuffer type; - * but we can not have upwards - * references (from core to mapper package); and as such we also - * can not take second argument. - */ - public void serialize(JsonGenerator jgen) - throws IOException, JsonGenerationException - { - Segment segment = _first; - int ptr = -1; - - while (true) { - if (++ptr >= Segment.TOKENS_PER_SEGMENT) { - ptr = 0; - segment = segment.next(); - if (segment == null) break; - } - JsonToken t = segment.type(ptr); - if (t == null) break; - - // Note: copied from 'copyCurrentEvent'... - switch (t) { - case START_OBJECT: - jgen.writeStartObject(); - break; - case END_OBJECT: - jgen.writeEndObject(); - break; - case START_ARRAY: - jgen.writeStartArray(); - break; - case END_ARRAY: - jgen.writeEndArray(); - break; - case FIELD_NAME: - jgen.writeFieldName((String) segment.get(ptr)); - break; - case VALUE_STRING: - jgen.writeString((String) segment.get(ptr)); - break; - case VALUE_NUMBER_INT: - { - Number n = (Number) segment.get(ptr); - if (n instanceof BigInteger) { - jgen.writeNumber((BigInteger) n); - } else if (n instanceof Long) { - jgen.writeNumber(n.longValue()); - } else { - jgen.writeNumber(n.intValue()); - } - } - break; - case VALUE_NUMBER_FLOAT: - { - Number n = (Number) segment.get(ptr); - if (n instanceof BigDecimal) { - jgen.writeNumber((BigDecimal) n); - } else if (n instanceof Float) { - jgen.writeNumber(n.floatValue()); - } else { - jgen.writeNumber(n.doubleValue()); - } - } - break; - case VALUE_TRUE: - jgen.writeBoolean(true); - break; - case VALUE_FALSE: - jgen.writeBoolean(false); - break; - case VALUE_NULL: - jgen.writeNull(); - break; - case VALUE_EMBEDDED_OBJECT: - jgen.writeObject(segment.get(ptr)); - break; - default: - throw new RuntimeException("Internal error: should never end up through this code path"); - } - } - } - - @Override - public String toString() - { - // Let's print up to 100 first tokens... - final int MAX_COUNT = 100; - - StringBuilder sb = new StringBuilder(); - sb.append("[TokenBuffer: "); - JsonParser jp = asParser(); - int count = 0; - - while (true) { - JsonToken t; - try { - t = jp.nextToken(); - } catch (IOException ioe) { // should never occur - throw new IllegalStateException(ioe); - } - if (t == null) break; - if (count < MAX_COUNT) { - if (count > 0) { - sb.append(", "); - } - sb.append(t.toString()); - } - ++count; - } - - if (count >= MAX_COUNT) { - sb.append(" ... (truncated ").append(count-MAX_COUNT).append(" entries)"); - } - sb.append(']'); - return sb.toString(); - } - - /* - ***************************************************************** - * JsonGenerator implementation: configuration - ***************************************************************** - */ - - @Override - public JsonGenerator enable(Feature f) { - _generatorFeatures |= f.getMask(); - return this; - } - - @Override - public JsonGenerator disable(Feature f) { - _generatorFeatures &= ~f.getMask(); - return this; - } - - //public JsonGenerator configure(Feature f, boolean state) { } - - @Override - public boolean isEnabled(Feature f) { - return (_generatorFeatures & f.getMask()) != 0; - } - - public JsonGenerator useDefaultPrettyPrinter() { - // No-op: we don't indent - return this; - } - - public JsonGenerator setCodec(ObjectCodec oc) { - _objectCodec = oc; - return this; - } - - public ObjectCodec getCodec() { return _objectCodec; } - - public final JsonWriteContext getOutputContext() { return _writeContext; } - - /* - ***************************************************************** - * JsonGenerator implementation: low-level output handling - ***************************************************************** - */ - - public void flush() throws IOException { /* NOP */ } - - public void close() throws IOException { - _closed = true; - } - - public boolean isClosed() { return _closed; } - - /* - ***************************************************************** - * JsonGenerator implementation: write methods, structural - ***************************************************************** - */ - - @Override - public final void writeStartArray() - throws IOException, JsonGenerationException - { - _append(JsonToken.START_ARRAY); - _writeContext = _writeContext.createChildArrayContext(); - } - - @Override - public final void writeEndArray() - throws IOException, JsonGenerationException - { - _append(JsonToken.END_ARRAY); - // Let's allow unbalanced tho... i.e. not run out of root level, ever - JsonWriteContext c = _writeContext.getParent(); - if (c != null) { - _writeContext = c; - } - } - - @Override - public final void writeStartObject() - throws IOException, JsonGenerationException - { - _append(JsonToken.START_OBJECT); - _writeContext = _writeContext.createChildObjectContext(); - } - - public final void writeEndObject() - throws IOException, JsonGenerationException - { - _append(JsonToken.END_OBJECT); - // Let's allow unbalanced tho... i.e. not run out of root level, ever - JsonWriteContext c = _writeContext.getParent(); - if (c != null) { - _writeContext = c; - } - } - - public final void writeFieldName(String name) - throws IOException, JsonGenerationException - { - _append(JsonToken.FIELD_NAME, name); - _writeContext.writeFieldName(name); - } - - /* - ***************************************************************** - * JsonGenerator implementation: write methods, textual - ***************************************************************** - */ - - @Override - public void writeString(String text) throws IOException,JsonGenerationException { - if (text == null) { - writeNull(); - } else { - _append(JsonToken.VALUE_STRING, text); - } - } - - @Override - public void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException { - writeString(new String(text, offset, len)); - } - - @Override - public void writeRaw(String text) throws IOException, JsonGenerationException { - _reportUnsupportedOperation(); - } - - @Override - public void writeRaw(String text, int offset, int len) throws IOException, JsonGenerationException { - _reportUnsupportedOperation(); - } - - @Override - public void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException { - _reportUnsupportedOperation(); - } - - @Override - public void writeRaw(char c) throws IOException, JsonGenerationException { - _reportUnsupportedOperation(); - } - - @Override - public void writeRawValue(String text) throws IOException, JsonGenerationException { - _reportUnsupportedOperation(); - } - - @Override - public void writeRawValue(String text, int offset, int len) throws IOException, JsonGenerationException { - _reportUnsupportedOperation(); - } - - @Override - public void writeRawValue(char[] text, int offset, int len) throws IOException, JsonGenerationException { - _reportUnsupportedOperation(); - } - - /* - ***************************************************************** - * JsonGenerator implementation: write methods, primitive types - ***************************************************************** - */ - - @Override - public void writeNumber(int i) throws IOException, JsonGenerationException { - _append(JsonToken.VALUE_NUMBER_INT, Integer.valueOf(i)); - } - - @Override - public void writeNumber(long l) throws IOException, JsonGenerationException { - _append(JsonToken.VALUE_NUMBER_INT, Long.valueOf(l)); - } - - @Override - public void writeNumber(double d) throws IOException,JsonGenerationException { - _append(JsonToken.VALUE_NUMBER_FLOAT, Double.valueOf(d)); - } - - @Override - public void writeNumber(float f) throws IOException, JsonGenerationException { - _append(JsonToken.VALUE_NUMBER_FLOAT, Float.valueOf(f)); - } - - @Override - public void writeNumber(BigDecimal dec) throws IOException,JsonGenerationException { - if (dec == null) { - writeNull(); - } else { - _append(JsonToken.VALUE_NUMBER_FLOAT, dec); - } - } - - @Override - public void writeNumber(BigInteger v) throws IOException, JsonGenerationException { - if (v == null) { - writeNull(); - } else { - _append(JsonToken.VALUE_NUMBER_INT, v); - } - } - - @Override - public void writeNumber(String encodedValue) throws IOException, JsonGenerationException { - /* Hmmh... let's actually support this as regular String value write: - * should work since there is no quoting when buffering - */ - writeString(encodedValue); - } - - @Override - public void writeBoolean(boolean state) throws IOException,JsonGenerationException { - _append(state ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE); - } - - @Override - public void writeNull() throws IOException, JsonGenerationException { - _append(JsonToken.VALUE_NULL); - } - - /* - ***************************************************************** - * JsonGenerator implementation: write methods for POJOs/trees - ***************************************************************** - */ - - public void writeObject(Object value) - throws IOException, JsonProcessingException - { - // embedded means that no conversions should be done... - _append(JsonToken.VALUE_EMBEDDED_OBJECT, value); - } - - public void writeTree(JsonNode rootNode) - throws IOException, JsonProcessingException - { - /* 31-Dec-2009, tatu: no need to convert trees either is there? - * (note: may need to re-evaluate at some point) - */ - _append(JsonToken.VALUE_EMBEDDED_OBJECT, rootNode); - } - - /* - ***************************************************************** - * JsonGenerator implementation; binary - ***************************************************************** - */ - - @Override - public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) - throws IOException, JsonGenerationException - { - /* 31-Dec-2009, tatu: can do this using multiple alternatives; but for - * now, let's try to limit number of conversions. - * The only (?) tricky thing is that of whether to preserve variant, - * seems pointless, so let's not worry about it unless there's some - * compelling reason to. - */ - byte[] copy = new byte[len]; - System.arraycopy(data, offset, copy, 0, len); - writeObject(copy); - } - - /* - ***************************************************************** - * JsonGenerator implementation; pass-through copy - ***************************************************************** - */ - - @Override - public void copyCurrentEvent(JsonParser jp) throws IOException, JsonProcessingException - { - switch (jp.getCurrentToken()) { - case START_OBJECT: - writeStartObject(); - break; - case END_OBJECT: - writeEndObject(); - break; - case START_ARRAY: - writeStartArray(); - break; - case END_ARRAY: - writeEndArray(); - break; - case FIELD_NAME: - writeFieldName(jp.getCurrentName()); - break; - case VALUE_STRING: - writeString(jp.getTextCharacters(), jp.getTextOffset(), jp.getTextLength()); - break; - case VALUE_NUMBER_INT: - switch (jp.getNumberType()) { - case INT: - writeNumber(jp.getIntValue()); - break; - case BIG_INTEGER: - writeNumber(jp.getBigIntegerValue()); - break; - default: - writeNumber(jp.getLongValue()); - } - break; - case VALUE_NUMBER_FLOAT: - switch (jp.getNumberType()) { - case BIG_DECIMAL: - writeNumber(jp.getDecimalValue()); - break; - case FLOAT: - writeNumber(jp.getFloatValue()); - break; - default: - writeNumber(jp.getDoubleValue()); - } - break; - case VALUE_TRUE: - writeBoolean(true); - break; - case VALUE_FALSE: - writeBoolean(false); - break; - case VALUE_NULL: - writeNull(); - break; - case VALUE_EMBEDDED_OBJECT: - writeObject(jp.getEmbeddedObject()); - break; - default: - throw new RuntimeException("Internal error: should never end up through this code path"); - } - } - - @Override - public void copyCurrentStructure(JsonParser jp) throws IOException, JsonProcessingException { - JsonToken t = jp.getCurrentToken(); - - // Let's handle field-name separately first - if (t == JsonToken.FIELD_NAME) { - writeFieldName(jp.getCurrentName()); - t = jp.nextToken(); - // fall-through to copy the associated value - } - - switch (t) { - case START_ARRAY: - writeStartArray(); - while (jp.nextToken() != JsonToken.END_ARRAY) { - copyCurrentStructure(jp); - } - writeEndArray(); - break; - case START_OBJECT: - writeStartObject(); - while (jp.nextToken() != JsonToken.END_OBJECT) { - copyCurrentStructure(jp); - } - writeEndObject(); - break; - default: // others are simple: - copyCurrentEvent(jp); - } - } - - /* - ***************************************************************** - * Internal methods - ***************************************************************** - */ - protected final void _append(JsonToken type) { - Segment next = _last.append(_appendOffset, type); - if (next == null) { - ++_appendOffset; - } else { - _last = next; - _appendOffset = 1; // since we added first at 0 - } - } - - protected final void _append(JsonToken type, Object value) { - Segment next = _last.append(_appendOffset, type, value); - if (next == null) { - ++_appendOffset; - } else { - _last = next; - _appendOffset = 1; - } - } - - protected void _reportUnsupportedOperation() { - throw new UnsupportedOperationException("Called operation not supported for TokenBuffer"); - } - - /* - ***************************************************************** - * Supporting classes - ***************************************************************** - */ - - protected final static class Parser - extends JsonParser - { - protected ObjectCodec _codec; - - /* - //////////////////////////////////////////////////// - // Parsing state - //////////////////////////////////////////////////// - */ - - /** - * Currently active segment - */ - protected Segment _segment; - - /** - * Pointer to current token within current segment - */ - protected int _segmentPtr; - - /** - * Information about parser context, context in which - * the next token is to be parsed (root, array, object). - */ - protected JsonReadContext _parsingContext; - - protected boolean _closed; - - protected transient ByteArrayBuilder _byteBuilder; - - protected JsonLocation _location = null; - - /* - //////////////////////////////////////////////////// - // Construction, init - //////////////////////////////////////////////////// - */ - - public Parser(Segment firstSeg, ObjectCodec codec) { - _segment = firstSeg; - _segmentPtr = -1; // not yet read - _codec = codec; - _parsingContext = JsonReadContext.createRootContext(-1, -1); - } - - public void setLocation(JsonLocation l) { - _location = l; - } - - @Override - public ObjectCodec getCodec() { return _codec; } - - @Override - public void setCodec(ObjectCodec c) { _codec = c; } - - /* - //////////////////////////////////////////////////// - // Closeable implementation - //////////////////////////////////////////////////// - */ - - @Override - public void close() throws IOException { - if (!_closed) { - _closed = true; - } - } - - /* - //////////////////////////////////////////////////// - // Public API, traversal - //////////////////////////////////////////////////// - */ - - @Override - public JsonToken nextToken() throws IOException, JsonParseException - { - // If we are closed, nothing more to do - if (_closed || (_segment == null)) return null; - - // Ok, then: any more tokens? - if (++_segmentPtr >= Segment.TOKENS_PER_SEGMENT) { - _segmentPtr = 0; - _segment = _segment.next(); - if (_segment == null) { - return null; - } - } - _currToken = _segment.type(_segmentPtr); - // Field name? Need to update context - if (_currToken == JsonToken.FIELD_NAME) { - _parsingContext.setCurrentName((String) _currentObject()); - } else if (_currToken == JsonToken.START_OBJECT) { - _parsingContext = _parsingContext.createChildObjectContext(-1, -1); - } else if (_currToken == JsonToken.START_ARRAY) { - _parsingContext = _parsingContext.createChildArrayContext(-1, -1); - } else if (_currToken == JsonToken.END_OBJECT - || _currToken == JsonToken.END_ARRAY) { - // Closing JSON Object/Array? Close matching context - _parsingContext = _parsingContext.getParent(); - // but allow unbalanced cases too (more close markers) - if (_parsingContext == null) { - _parsingContext = JsonReadContext.createRootContext(-1, -1); - } - } - return _currToken; - } - - @Override - public JsonParser skipChildren() throws IOException, JsonParseException - { - if (_currToken != JsonToken.START_OBJECT && _currToken != JsonToken.START_ARRAY) { - return this; - } - int open = 1; - - /* Since proper matching of start/end markers is handled - * by nextToken(), we'll just count nesting levels here - */ - while (true) { - JsonToken t = nextToken(); - if (t == null) { - // error for most parsers, but ok here - return this; - } - switch (t) { - case START_OBJECT: - case START_ARRAY: - ++open; - break; - case END_OBJECT: - case END_ARRAY: - if (--open == 0) { - return this; - } - break; - } - } - } - - @Override - public boolean isClosed() { return _closed; } - - /* - //////////////////////////////////////////////////// - // Public API, token accessors - //////////////////////////////////////////////////// - */ - - @Override - public JsonStreamContext getParsingContext() { return _parsingContext; } - - @Override - public JsonLocation getTokenLocation() { return getCurrentLocation(); } - - @Override - public JsonLocation getCurrentLocation() { - return (_location == null) ? JsonLocation.NA : _location; - } - - @Override - public String getCurrentName() { return _parsingContext.getCurrentName(); } - - /* - //////////////////////////////////////////////////// - // Public API, access to token information, text - //////////////////////////////////////////////////// - */ - - @Override - public String getText() - { - if (_currToken != null) { // null only before/after document - switch (_currToken) { - case FIELD_NAME: - case VALUE_STRING: - return (String) _currentObject(); - // fall through - case VALUE_NUMBER_INT: - case VALUE_NUMBER_FLOAT: - Object ob = _currentObject(); - return (ob == null) ? null : ob.toString(); - default: - return _currToken.asString(); - } - } - return null; - } - - @Override - public char[] getTextCharacters() { - String str = getText(); - return (str == null) ? null : str.toCharArray(); - } - - @Override - public int getTextLength() { - String str = getText(); - return (str == null) ? 0 : str.length(); - } - - @Override - public int getTextOffset() { return 0; } - - /* - //////////////////////////////////////////////////// - // Public API, access to token information, numeric - //////////////////////////////////////////////////// - */ - - @Override - public BigInteger getBigIntegerValue() throws IOException, JsonParseException - { - Number n = getNumberValue(); - if (n instanceof BigInteger) { - return (BigInteger) n; - } - switch (getNumberType()) { - case BIG_DECIMAL: - return ((BigDecimal) n).toBigInteger(); - } - // int/long is simple, but let's also just truncate float/double: - return BigInteger.valueOf(n.longValue()); - } - - @Override - public BigDecimal getDecimalValue() throws IOException, JsonParseException - { - Number n = getNumberValue(); - if (n instanceof BigDecimal) { - return (BigDecimal) n; - } - switch (getNumberType()) { - case INT: - case LONG: - return BigDecimal.valueOf(n.longValue()); - case BIG_INTEGER: - return new BigDecimal((BigInteger) n); - } - // float or double - return BigDecimal.valueOf(n.doubleValue()); - } - - @Override - public double getDoubleValue() throws IOException, JsonParseException { - return getNumberValue().doubleValue(); - } - - @Override - public float getFloatValue() throws IOException, JsonParseException { - return getNumberValue().floatValue(); - } - - @Override - public int getIntValue() throws IOException, JsonParseException { - return getNumberValue().intValue(); - } - - @Override - public long getLongValue() throws IOException, JsonParseException { - return getNumberValue().longValue(); - } - - @Override - public NumberType getNumberType() throws IOException, JsonParseException - { - Number n = getNumberValue(); - if (n instanceof Integer) return NumberType.INT; - if (n instanceof Long) return NumberType.LONG; - if (n instanceof Double) return NumberType.DOUBLE; - if (n instanceof BigDecimal) return NumberType.BIG_DECIMAL; - if (n instanceof Float) return NumberType.FLOAT; - if (n instanceof BigInteger) return NumberType.BIG_INTEGER; - return null; - } - - @Override - public final Number getNumberValue() throws IOException, JsonParseException { - _checkIsNumber(); - return (Number) _currentObject(); - } - - /* - //////////////////////////////////////////////////// - // Public API, access to token information, other - //////////////////////////////////////////////////// - */ - - private final static int INT_SPACE = 0x0020; - - public Object getEmbeddedObject() - { - if (_currToken == JsonToken.VALUE_EMBEDDED_OBJECT) { - return _currentObject(); - } - return null; - } - - @Override - public byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException - { - // First: maybe we some special types? - if (_currToken == JsonToken.VALUE_EMBEDDED_OBJECT) { - // Embedded byte array would work nicely... - Object ob = _currentObject(); - if (ob instanceof byte[]) { - return (byte[]) ob; - } - // fall through to error case - } - if (_currToken != JsonToken.VALUE_STRING) { - throw _constructError("Current token ("+_currToken+") not VALUE_STRING (or VALUE_EMBEDDED_OBJECT with byte[]), can not access as binary"); - } - final String str = getText(); - if (str == null) { - return null; - } - ByteArrayBuilder builder = _byteBuilder; - if (builder == null) { - _byteBuilder = builder = new ByteArrayBuilder(100); - } - _decodeBase64(str, builder, b64variant); - return builder.toByteArray(); - } - - /* - //////////////////////////////////////////////////// - // Internal methods - //////////////////////////////////////////////////// - */ - - protected void _decodeBase64(String str, ByteArrayBuilder builder, Base64Variant b64variant) - throws IOException, JsonParseException - { - int ptr = 0; - int len = str.length(); - - main_loop: - while (ptr < len) { - // first, we'll skip preceding white space, if any - char ch; - do { - ch = str.charAt(ptr++); - if (ptr >= len) { - break main_loop; - } - } while (ch <= INT_SPACE); - int bits = b64variant.decodeBase64Char(ch); - if (bits < 0) { - _reportInvalidBase64(b64variant, ch, 0, null); - } - int decodedData = bits; - // then second base64 char; can't get padding yet, nor ws - if (ptr >= len) { - _reportBase64EOF(); - } - ch = str.charAt(ptr++); - bits = b64variant.decodeBase64Char(ch); - if (bits < 0) { - _reportInvalidBase64(b64variant, ch, 1, null); - } - decodedData = (decodedData << 6) | bits; - // third base64 char; can be padding, but not ws - if (ptr >= len) { - _reportBase64EOF(); - } - ch = str.charAt(ptr++); - bits = b64variant.decodeBase64Char(ch); - - // First branch: can get padding (-> 1 byte) - if (bits < 0) { - if (bits != Base64Variant.BASE64_VALUE_PADDING) { - _reportInvalidBase64(b64variant, ch, 2, null); - } - // Ok, must get padding - if (ptr >= len) { - _reportBase64EOF(); - } - ch = str.charAt(ptr++); - if (!b64variant.usesPaddingChar(ch)) { - _reportInvalidBase64(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'"); - } - // Got 12 bits, only need 8, need to shift - decodedData >>= 4; - builder.append(decodedData); - continue; - } - // Nope, 2 or 3 bytes - decodedData = (decodedData << 6) | bits; - // fourth and last base64 char; can be padding, but not ws - if (ptr >= len) { - _reportBase64EOF(); - } - ch = str.charAt(ptr++); - bits = b64variant.decodeBase64Char(ch); - if (bits < 0) { - if (bits != Base64Variant.BASE64_VALUE_PADDING) { - _reportInvalidBase64(b64variant, ch, 3, null); - } - decodedData >>= 2; - builder.appendTwoBytes(decodedData); - } else { - // otherwise, our triple is now complete - decodedData = (decodedData << 6) | bits; - builder.appendThreeBytes(decodedData); - } - } - } - - protected final Object _currentObject() { - return _segment.get(_segmentPtr); - } - - protected void _checkIsNumber() throws JsonParseException - { - if (_currToken == null || !_currToken.isNumeric()) { - throw _constructError("Current token ("+_currToken+") not numeric, can not use numeric value accessors"); - } - } - - /** - * @param bindex Relative index within base64 character unit; between 0 - * and 3 (as unit has exactly 4 characters) - */ - protected void _reportInvalidBase64(Base64Variant b64variant, char ch, int bindex, String msg) - throws JsonParseException - { - String base; - if (ch <= INT_SPACE) { - base = "Illegal white space character (code 0x"+Integer.toHexString(ch)+") as character #"+(bindex+1)+" of 4-char base64 unit: can only used between units"; - } else if (b64variant.usesPaddingChar(ch)) { - base = "Unexpected padding character ('"+b64variant.getPaddingChar()+"') as character #"+(bindex+1)+" of 4-char base64 unit: padding only legal as 3rd or 4th character"; - } else if (!Character.isDefined(ch) || Character.isISOControl(ch)) { - // Not sure if we can really get here... ? (most illegal xml chars are caught at lower level) - base = "Illegal character (code 0x"+Integer.toHexString(ch)+") in base64 content"; - } else { - base = "Illegal character '"+ch+"' (code 0x"+Integer.toHexString(ch)+") in base64 content"; - } - if (msg != null) { - base = base + ": " + msg; - } - throw _constructError(base); - } - - protected void _reportBase64EOF() throws JsonParseException { - throw _constructError("Unexpected end-of-String in base64 content"); - } - } - - /** - * Individual segment of TokenBuffer that can store up to 16 tokens - * (limited by 4 bits per token type marker requirement). - * Current implementation uses fixed length array; could alternatively - * use 16 distinct fields and switch statement (slightly more efficient - * storage, slightly slower access) - */ - protected final static class Segment - { - public final static int TOKENS_PER_SEGMENT = 16; - - /** - * Static array used for fast conversion between token markers and - * matching {@link JsonToken} instances - */ - private final static JsonToken[] TOKEN_TYPES_BY_INDEX; - static { - // ... here we know that there are <= 16 values in JsonToken enum - TOKEN_TYPES_BY_INDEX = new JsonToken[16]; - JsonToken[] t = JsonToken.values(); - System.arraycopy(t, 1, TOKEN_TYPES_BY_INDEX, 1, Math.min(15, t.length - 1)); - } - - // // // Linking - - protected Segment _next; - - // // // State - - /** - * Bit field used to store types of buffered tokens; 4 bits per token. - * Value 0 is reserved for "not in use" - */ - protected long _tokenTypes; - - - // Actual tokens - - protected final Object[] _tokens = new Object[TOKENS_PER_SEGMENT]; - - public Segment() { } - - // // // Accessors - - public JsonToken type(int index) - { - long l = _tokenTypes; - if (index > 0) { - l >>= (index << 2); - } - int ix = ((int) l) & 0xF; - return TOKEN_TYPES_BY_INDEX[ix]; - } - - public Object get(int index) { - return _tokens[index]; - } - - public Segment next() { return _next; } - - // // // Mutators - - public Segment append(int index, JsonToken tokenType) - { - if (index < TOKENS_PER_SEGMENT) { - set(index, tokenType); - return null; - } - _next = new Segment(); - _next.set(0, tokenType); - return _next; - } - - public Segment append(int index, JsonToken tokenType, Object value) - { - if (index < TOKENS_PER_SEGMENT) { - set(index, tokenType, value); - return null; - } - _next = new Segment(); - _next.set(0, tokenType, value); - return _next; - } - - public void set(int index, JsonToken tokenType) - { - long typeCode = tokenType.ordinal(); - /* Assumption here is that there are no overwrites, just appends; - * and so no masking is needed - */ - if (index > 0) { - typeCode <<= (index << 2); - } - _tokenTypes |= typeCode; - } - - public void set(int index, JsonToken tokenType, Object value) - { - _tokens[index] = value; - long typeCode = tokenType.ordinal(); - /* Assumption here is that there are no overwrites, just appends; - * and so no masking is needed - */ - if (index > 0) { - typeCode <<= (index << 2); - } - _tokenTypes |= typeCode; - } - } -}