From f19afa33d3956d63f8f0f77936d28b77a18960e0 Mon Sep 17 00:00:00 2001 From: salyh Date: Mon, 7 Jul 2014 00:30:59 +0200 Subject: [PATCH 3/4] New JSON Parser which pass all tests, minor testcasefix, minor other fixes to conform to api (readonly map returned for getConfig()) Signed-off-by: salyh --- .../apache/fleece/core/JsonBaseStreamParser.java | 820 +++++++++++++++++++++ .../apache/fleece/core/JsonBuilderFactoryImpl.java | 4 +- .../fleece/core/JsonCharBufferStreamParser.java | 134 ++++ .../fleece/core/JsonGeneratorFactoryImpl.java | 4 +- .../org/apache/fleece/core/JsonLocationImpl.java | 5 + .../apache/fleece/core/JsonParserFactoryImpl.java | 22 +- .../apache/fleece/core/JsonReaderFactoryImpl.java | 4 +- .../org/apache/fleece/core/JsonReaderImpl.java | 19 +- .../java/org/apache/fleece/mapper/MapperTest.java | 4 +- 9 files changed, 998 insertions(+), 18 deletions(-) create mode 100644 fleece-core/src/main/java/org/apache/fleece/core/JsonBaseStreamParser.java create mode 100644 fleece-core/src/main/java/org/apache/fleece/core/JsonCharBufferStreamParser.java diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonBaseStreamParser.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonBaseStreamParser.java new file mode 100644 index 0000000..a46bf4b --- /dev/null +++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonBaseStreamParser.java @@ -0,0 +1,820 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.apache.fleece.core; + +import static org.apache.fleece.core.Strings.asEscapedChar; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.NoSuchElementException; + +import javax.json.JsonException; +import javax.json.stream.JsonLocation; +import javax.json.stream.JsonParsingException; + +public abstract class JsonBaseStreamParser implements JsonChars, + EscapedStringAwareJsonParser { + + // private static BufferCache VBUFFER_CACHE; + + protected final static boolean log = false; + private final int maxStringSize; + + // current state + private Event event = null; + private Event lastEvent = null; + private int lastSignificantChar = -1; + + private final char[] currentValue; + private int valueLength = 0; + + // location + private int line = 1; + private int column = 1; + private int offset = 0; + + private boolean constructingStringValue = false; + private boolean withinArray = false; + private boolean stringValueIsKey = false; + + private int openObjects = 0; + private int openArrays = 0; + private boolean escaped = false; + + protected JsonBaseStreamParser(final int maxStringLength) { + + /* + * if(VBUFFER_CACHE == null) { VBUFFER_CACHE = new BufferCache( + * maxStringLength) { + * + * @Override protected char[] newValue(final int defaultSize) { return + * new char[defaultSize]; } };} + */ + + this.maxStringSize = maxStringLength < 0 ? 8192 : maxStringLength; + // currentValue = VBUFFER_CACHE.getCache(); + currentValue = new char[maxStringLength]; + } + + private void appendValue(final char c) { + if (valueLength >= maxStringSize) { + throw new JsonParsingException("to many chars", createLocation()); + } + + currentValue[valueLength] = c; + valueLength++; + } + + private void resetValue() { + valueLength = 0; + + } + + private String getValue() { + return new String(currentValue, 0, valueLength); + } + + @Override + public final boolean hasNext() { + + if (event == null) { + return true; + } + + return !(openArrays == 0 && openObjects == 0); + + } + + private static boolean isAsciiDigit(final char value) { + return value >= ZERO && value <= NINE; + } + + private static boolean isHexDigit(final char value) { + return isAsciiDigit(value) || (value >= 'a' && value <= 'f') + || (value >= 'A' && value <= 'F'); + } + + private JsonLocationImpl createLocation() { + return new JsonLocationImpl(line, column, offset); + } + + private boolean ifConstructingStringValueAdd(char c) throws IOException { + if (escaped) { + + if (c == 'u') { + final char[] tmp = read(4); + + for (int i = 0; i < tmp.length; i++) { + if (!isHexDigit(tmp[i])) { + throw new JsonParsingException("unexpected character " + + tmp[i], createLocation()); + } + } + + if (log) { + System.out.println((int) tmp[3] + "/" + (int) tmp[2] + "/" + + (int) tmp[1] + "/" + (int) tmp[0]); + } + + final int decimal = ((tmp[3]) - 48) * 1 + ((tmp[2]) - 48) * 16 + + ((tmp[1]) - 48) * 256 + ((tmp[0]) - 48) * 4096; + c = (char) decimal; + + } else { + c = asEscapedChar(c); + } + + escaped = false; + } + + return ifConstructingStringValueAdd(c, false); + } + + private boolean ifConstructingStringValueAdd(final char c, + final boolean escape) { + if (constructingStringValue) { + + appendValue(escape ? Strings.asEscapedChar(c) : c); + } + return constructingStringValue; + } + + protected abstract char readNextChar() throws IOException; + + protected abstract void mark(); + + private void resetToMark() { + + reset(); + offset--; + column--; + } + + protected abstract void reset(); + + private char read() throws IOException { + final char c = readNextChar(); + + if (log) { + System.out.println("reading: " + c + " -> " + ((int) c)); + } + + if (c == -1) { + // hasNext = false; + throw new NoSuchElementException(); + } + + offset++; + column++; + + return c; + } + + private char[] read(final int count) throws IOException { + final char[] tmp = new char[count]; + + for (int i = 0; i < tmp.length; i++) { + tmp[i] = read(); + + } + + return tmp; + } + + // Event.START_ARRAY + // Event.START_OBJECT + + // Event.END_ARRAY + // Event.END_OBJECT + + // Event.KEY_NAME + + // ** 5 Value Event + // Event.VALUE_FALSE + // Event.VALUE_NULL + // Event.VALUE_NUMBER + // Event.VALUE_STRING + // Event.VALUE_TRUE + + // *********************** + // *********************** + // Significant chars (8) + + // 0 - start doc + // " - quote + // , - comma + + // : - separator + // { - start obj + // } - end obj + // [ - start arr + // ] - end arr + + @Override + public final Event next() { + + int dosCount = 0; + lastEvent = event; + event = null; + + resetValue(); + + try { + while (true) { + final char c = read(); + + switch (c) { + + case START_OBJECT_CHAR: + + if (ifConstructingStringValueAdd(c)) { + continue; + } + + handleStartObject(c); + + break; + + case END_OBJECT_CHAR: + + if (ifConstructingStringValueAdd(c)) { + continue; + } + + handleEndObject(c); + + break; + case START_ARRAY_CHAR: + + if (ifConstructingStringValueAdd(c)) { + continue; + } + + handleStartArray(c); + + break; + case END_ARRAY_CHAR: + + if (ifConstructingStringValueAdd(c)) { + continue; + } + + handleEndArray(c); + break; + case EOL: + if (ifConstructingStringValueAdd(c)) { + throw new JsonParsingException("Unexpected character " + + c + " (" + (int) c + ")", createLocation()); + } + line++; + continue; // eol no allowed within a value + + case TAB: + case CR: + case SPACE: + if (ifConstructingStringValueAdd(c)) { // escaping + + continue; + + } else { + // dos check + if (dosCount >= maxStringSize) { + throw new JsonParsingException( + "max string size reached", createLocation()); + } + dosCount++; + } + + break; + case COMMA: + if (ifConstructingStringValueAdd(c)) { + continue; + } + + if (lastSignificantChar >= 0 + && (char) lastSignificantChar != QUOTE + && (char) lastSignificantChar != END_ARRAY_CHAR + && (char) lastSignificantChar != END_OBJECT_CHAR) { + throw new JsonParsingException("Unexpected character " + + c + " (last significant was " + + lastSignificantChar + ")", createLocation()); + } + + lastSignificantChar = c; + + stringValueIsKey = true; + if (log) { + System.out.println(" VAL_IS_KEY"); + } + + break; + case KEY_SEPARATOR: + if (ifConstructingStringValueAdd(c)) { + continue; + } + + if (lastSignificantChar >= 0 + && (char) lastSignificantChar != QUOTE) { + throw new JsonParsingException("Unexpected character " + + c, createLocation()); + } + + lastSignificantChar = c; + + stringValueIsKey = false; + if (log) { + System.out.println(" VAL_IS_VALUE"); + } + + break; + + case QUOTE: // must be escaped within a value + + if (handleQuote(c)) { + continue; + } else { + break; + } + + // non string values (literals) + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case MINUS: + case FALSE_F: // false + case TRUE_T: // true + case NULL_N: // null + + if (ifConstructingStringValueAdd(c)) { + continue; + } + + handleLiteral(c); + + break; + + // escape char + case ESCAPE_CHAR:// must be escaped within a value + if (!constructingStringValue) { + throw new JsonParsingException("Unexpected character " + + c, createLocation()); + } + + if (escaped) { + if (log) { + System.out.println(" ESCAPEDESCAPED"); + } + + appendValue(ESCAPE_CHAR); + escaped = false; + } else { + if (log) { + System.out.println(" ESCAPECHAR"); + } + escaped = true; + } + + break; + + // eof + case EOF: + + throw new NoSuchElementException(); + + default: + if (ifConstructingStringValueAdd(c)) { + continue; + } + lastSignificantChar = -2; + throw new JsonParsingException("Unexpected character " + c, + createLocation()); + + } + + if (event != null) { + + if (log) { + System.out.println(" +++ +++ +++ +++ +++ +++" + event + + "::" + getValue()); + } + + return event; + + } + + } + } catch (final IOException e) { + new JsonParsingException("Unexpected IO Excpetion", e, + createLocation()); + } + + throw new JsonParsingException("Unexpected error due to invalid json", + createLocation()); + } + + private void handleStartObject(final char c) { + + if (log) { + System.out.println(" LASIC " + lastSignificantChar); + } + + if (lastSignificantChar == -2 + || (lastSignificantChar != -1 + && (char) lastSignificantChar != KEY_SEPARATOR + && (char) lastSignificantChar != COMMA && (char) lastSignificantChar != START_ARRAY_CHAR)) { + throw new JsonParsingException("Unexpected character " + c + + " (last significant was " + lastSignificantChar + ")", + createLocation()); + } + + stringValueIsKey = true; + withinArray = false; + if (log) { + System.out.println(" VAL_IS_KEY"); + } + + lastSignificantChar = c; + openObjects++; + event = Event.START_OBJECT; + + } + + private void handleEndObject(final char c) { + if (lastSignificantChar >= 0 + && (char) lastSignificantChar != START_OBJECT_CHAR + && (char) lastSignificantChar != END_ARRAY_CHAR + && (char) lastSignificantChar != QUOTE + && (char) lastSignificantChar != END_OBJECT_CHAR) { + throw new JsonParsingException("Unexpected character " + c + + " (last significant was " + lastSignificantChar + ")", + createLocation()); + } + + if (openObjects == 0) { + throw new JsonParsingException("Unexpected character " + c, + createLocation()); + } + + lastSignificantChar = c; + openObjects--; + event = Event.END_OBJECT; + } + + private void handleStartArray(final char c) { + withinArray = true; + + if (lastSignificantChar == -2 + || (lastSignificantChar != -1 + && (char) lastSignificantChar != KEY_SEPARATOR + && (char) lastSignificantChar != COMMA && (char) lastSignificantChar != START_ARRAY_CHAR)) { + throw new JsonParsingException("Unexpected character " + c + + " (last significant was " + lastSignificantChar + ")", + createLocation()); + } + + lastSignificantChar = c; + openArrays++; + event = Event.START_ARRAY; + } + + private void handleEndArray(final char c) { + withinArray = false; + + if (lastSignificantChar >= 0 + && (char) lastSignificantChar != START_ARRAY_CHAR + && (char) lastSignificantChar != END_ARRAY_CHAR + && (char) lastSignificantChar != END_OBJECT_CHAR + && (char) lastSignificantChar != QUOTE) { + throw new JsonParsingException("Unexpected character " + c + + " (last significant was " + lastSignificantChar + ")", + createLocation()); + } + + if (openArrays == 0) { + throw new JsonParsingException("Unexpected character " + c, + createLocation()); + } + + lastSignificantChar = c; + openArrays--; + + event = Event.END_ARRAY; + } + + private boolean handleQuote(final char c) { + + if (lastSignificantChar >= 0 && (char) lastSignificantChar != QUOTE + && (char) lastSignificantChar != KEY_SEPARATOR + && (char) lastSignificantChar != START_OBJECT_CHAR + && (char) lastSignificantChar != START_ARRAY_CHAR + && (char) lastSignificantChar != COMMA) { + throw new JsonParsingException("Unexpected character " + c + + " (last significant was " + lastSignificantChar + ")", + createLocation()); + } + + lastSignificantChar = c; + + if (constructingStringValue) { + + if (escaped) { + appendValue(QUOTE); + escaped = false; + return true; + } else { + + if (!withinArray && stringValueIsKey) { + event = Event.KEY_NAME; + stringValueIsKey = false; + if (log) { + System.out.println(" VAL_IS_VALUE"); + } + } else { + + if (lastEvent != Event.KEY_NAME && !withinArray) { + throw new JsonParsingException("Unexpected character " + + c + " (lastevent " + lastEvent + + ", comma missing)", createLocation()); + } + + // string value end + event = Event.VALUE_STRING; + } + + constructingStringValue = false; + + return false; + } + } else { + + if (escaped) { + throw new JsonParsingException("Unexpected character " + c, + createLocation()); + } + + // string value start + resetValue(); + constructingStringValue = true; + return false; + } + + } + + private void handleLiteral(final char c) throws IOException { + if (lastSignificantChar >= 0 && lastSignificantChar != KEY_SEPARATOR + && lastSignificantChar != COMMA + && lastSignificantChar != START_ARRAY_CHAR) { + throw new JsonParsingException("unexpected character " + c, + createLocation()); + } + + lastSignificantChar = -2; + + resetValue(); + + if (lastSignificantChar != QUOTE) { + // probe literals + switch (c) { + case TRUE_T: + final char[] tmpt = read(3); + if (tmpt[0] != TRUE_R || tmpt[1] != TRUE_U || tmpt[2] != TRUE_E) { + throw new JsonParsingException("Unexpected literal " + c + + new String(tmpt), createLocation()); + } + event = Event.VALUE_TRUE; + break; + case FALSE_F: + final char[] tmpf = read(4); + if (tmpf[0] != FALSE_A || tmpf[1] != FALSE_L + || tmpf[2] != FALSE_S || tmpf[3] != FALSE_E) { + throw new JsonParsingException("Unexpected literal " + c + + new String(tmpf), createLocation()); + } + + event = Event.VALUE_FALSE; + break; + case NULL_N: + final char[] tmpn = read(3); + if (tmpn[0] != NULL_U || tmpn[1] != NULL_L || tmpn[2] != NULL_L) { + throw new JsonParsingException("Unexpected literal " + c + + new String(tmpn), createLocation()); + } + event = Event.VALUE_NULL; + break; + + default: // number + appendValue(c); + + boolean endExpected = false; + final boolean zeropassed = c == '0'; + boolean dotpassed = false; + boolean epassed = false; + char last = c; + int i = -1; + + while (true) { + i++; + + if (log) { + System.out.println("while i:" + i); + } + + final char n = read(); + mark(); + + if (n == COMMA || n == END_ARRAY_CHAR + || n == END_OBJECT_CHAR) { + resetToMark(); + + event = Event.VALUE_NUMBER; + break; + } + + if (n == EOL) { + last = n; + continue; + } + + if (endExpected && n != SPACE && n != TAB && n != CR) { + throw new JsonParsingException("unexpected character " + + n + " (" + (int) n + ")", createLocation()); + } + + if (n == SPACE || n == TAB || n == CR) { + endExpected = true; + last = n; + continue; + } + + if (!isNumber(n)) { + throw new JsonParsingException("unexpected character " + + n, createLocation()); + } + + // minus only allowed as first char or after e/E + if (n == MINUS && i != 0 && last != EXP_LOWERCASE + && last != EXP_UPPERCASE) { + throw new JsonParsingException("unexpected character " + + n, createLocation()); + } + + // plus only allowed after e/E + if (n == PLUS && last != EXP_LOWERCASE + && last != EXP_UPPERCASE) { + throw new JsonParsingException("unexpected character " + + n, createLocation()); + } + + if (!dotpassed && zeropassed && i == 0 && n != DOT) { + throw new JsonParsingException("unexpected character " + + n + " (no leading zeros allowed)", + createLocation()); + } + + if (log) { + System.out.println("dotpassed:" + dotpassed + + "/zeropassed:" + zeropassed + "/i:" + i + + "/n:" + n); + } + + if (n == DOT) { + + if (dotpassed) { + throw new JsonParsingException("more than one dot", + createLocation()); + } + + dotpassed = true; + + } + + if (n == EXP_LOWERCASE || n == EXP_UPPERCASE) { + + if (epassed) { + throw new JsonParsingException("more than one e/E", + createLocation()); + } + + epassed = true; + } + + appendValue(n); + last = n; + + } + + break; + + } + + } else { + throw new JsonParsingException("Unexpected character " + c, + createLocation()); + } + + } + + private boolean isNumber(final char c) { + return isAsciiDigit(c) || c == DOT || c == MINUS || c == PLUS + || c == EXP_LOWERCASE || c == EXP_UPPERCASE; + } + + @Override + public String getString() { + if (event == Event.KEY_NAME || event == Event.VALUE_STRING + || event == Event.VALUE_NUMBER) { + return getValue(); + } + throw new IllegalStateException(event + " doesn't support getString()"); + } + + @Override + public boolean isIntegralNumber() { + + if (event != Event.VALUE_NUMBER) { + throw new IllegalStateException(event + + " doesn't supportisIntegralNumber()"); + } + + for (int i = 0; i < valueLength; i++) { + if (!isAsciiDigit(currentValue[i])) { + return false; + } + } + + return true; + } + + @Override + public int getInt() { + if (event != Event.VALUE_NUMBER) { + throw new IllegalStateException(event + " doesn't supportgetInt()"); + } + return Integer.parseInt(getValue()); + } + + @Override + public long getLong() { + if (event != Event.VALUE_NUMBER) { + throw new IllegalStateException(event + " doesn't supporgetLong()"); + } + return Long.parseLong(getValue()); + } + + @Override + public BigDecimal getBigDecimal() { + if (event != Event.VALUE_NUMBER) { + throw new IllegalStateException(event + + " doesn't support getBigDecimal()"); + } + return new BigDecimal(getValue()); + } + + @Override + public JsonLocation getLocation() { + return createLocation(); + } + + protected abstract void closeUnderlyingSource() throws IOException; + + @Override + public void close() { + + // VBUFFER_CACHE.release(currentValue); + + try { + closeUnderlyingSource(); + } catch (final IOException e) { + throw new JsonException(e.getMessage(), e); + } + } + + @Override + public String getEscapedString() { + return Strings.escape(getValue()); + } + +} \ No newline at end of file diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonBuilderFactoryImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonBuilderFactoryImpl.java index 710aa54..5e59640 100644 --- a/fleece-core/src/main/java/org/apache/fleece/core/JsonBuilderFactoryImpl.java +++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonBuilderFactoryImpl.java @@ -21,6 +21,8 @@ package org.apache.fleece.core; import javax.json.JsonArrayBuilder; import javax.json.JsonBuilderFactory; import javax.json.JsonObjectBuilder; + +import java.util.Collections; import java.util.Map; public class JsonBuilderFactoryImpl implements JsonBuilderFactory { @@ -42,6 +44,6 @@ public class JsonBuilderFactoryImpl implements JsonBuilderFactory { @Override public Map getConfigInUse() { - return config; + return Collections.unmodifiableMap(config); } } diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonCharBufferStreamParser.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonCharBufferStreamParser.java new file mode 100644 index 0000000..8bd4866 --- /dev/null +++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonCharBufferStreamParser.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.apache.fleece.core; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +public class JsonCharBufferStreamParser extends JsonBaseStreamParser { + + /* + * private static final BufferCache BUFFER_CACHE = new + * BufferCache( + * Integer.getInteger("org.apache.fleece.default-char-buffer", 8192) ) { + * + * @Override protected char[] newValue(final int defaultSize) { return new + * char[defaultSize]; } }; + */ + + private final char[] buffer0 = new char[Integer.getInteger( + "org.apache.fleece.default-char-buffer", 8192)];// BUFFER_CACHE.getCache(); + private final Reader in; + private int pointer = -1; + private int avail; + private char mark; + private boolean reset; + + // private int availOnMark; + + // Test increment buffer sizes + + public JsonCharBufferStreamParser(final Reader reader, + final int maxStringLength) { + super(maxStringLength); + in = reader; + + } + + public JsonCharBufferStreamParser(final InputStream stream, + final int maxStringLength) { + this(new InputStreamReader(stream), maxStringLength); + } + + public JsonCharBufferStreamParser(final InputStream in, + final Charset charset, final int maxStringLength) { + this(new InputStreamReader(in, charset), maxStringLength); + } + + @Override + protected char readNextChar() throws IOException { + + if (buffer0.length == 0) { + throw new IllegalArgumentException( + "buffer length must be greater than zero"); + } + + if (reset) { + reset = false; + return mark; + } + + if (avail <= 0) { + if (log) { + System.out.println("avail:" + avail + "/pointer:" + pointer); + } + + avail = in.read(buffer0, 0, buffer0.length); + + pointer = -1; + + if (log) { + System.out.println("******* Fill buffer with " + avail + + " chars"); + } + + if (avail <= 0) { + throw new IOException("EOF"); + } + + } + + pointer++; + avail--; + return buffer0[pointer]; + + } + + @Override + protected void mark() { + if (log) { + System.out.println(" MARK " + buffer0[pointer] + " (" + + (int) buffer0[pointer] + ")"); + } + mark = buffer0[pointer]; + } + + @Override + protected void reset() { + if (log) { + System.out.println(" RESET "); + } + reset = true; + } + + @Override + protected void closeUnderlyingSource() throws IOException { + + // BUFFER_CACHE.release(buffer0); + + if (in != null) { + in.close(); + } + + } + +} diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorFactoryImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorFactoryImpl.java index f88e80f..fafc2c0 100644 --- a/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorFactoryImpl.java +++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorFactoryImpl.java @@ -20,10 +20,12 @@ package org.apache.fleece.core; import javax.json.stream.JsonGenerator; import javax.json.stream.JsonGeneratorFactory; + import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.nio.charset.Charset; +import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -62,6 +64,6 @@ public class JsonGeneratorFactoryImpl implements JsonGeneratorFactory { @Override public Map getConfigInUse() { - return config; + return Collections.unmodifiableMap(config); } } diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java index 7b20e5b..d76ce39 100644 --- a/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java +++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java @@ -68,4 +68,9 @@ public class JsonLocationImpl implements JsonLocation, Serializable { result = 31 * result + (int) (streamOffset ^ (streamOffset >>> 32)); return result; } + + @Override + public String toString() { + return "JsonLocationImpl [lineNumber=" + lineNumber + ", columnNumber=" + columnNumber + ", streamOffset=" + streamOffset + "]"; + } } diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java index b138d84..ceeef70 100644 --- a/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java +++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java @@ -22,9 +22,11 @@ import javax.json.JsonArray; import javax.json.JsonObject; import javax.json.stream.JsonParser; import javax.json.stream.JsonParserFactory; + import java.io.InputStream; import java.io.Reader; import java.nio.charset.Charset; +import java.util.Collections; import java.util.Map; public class JsonParserFactoryImpl implements JsonParserFactory { @@ -45,20 +47,32 @@ public class JsonParserFactoryImpl implements JsonParserFactory { maxSize = Integer.parseInt(maxStringSize.toString()); } } + + JsonParser getDefaultJsonParserImpl(InputStream in) { + return new JsonCharBufferStreamParser(in, maxSize); + } + + JsonParser getDefaultJsonParserImpl(InputStream in, Charset charset) { + return new JsonCharBufferStreamParser(in, charset, maxSize); + } + + JsonParser getDefaultJsonParserImpl(Reader in) { + return new JsonCharBufferStreamParser(in, maxSize); + } @Override public JsonParser createParser(final Reader reader) { - return new JsonStreamParser(reader, maxSize); + return getDefaultJsonParserImpl(reader); } @Override public JsonParser createParser(final InputStream in) { - return new JsonStreamParser(in, maxSize); + return getDefaultJsonParserImpl(in); } @Override public JsonParser createParser(final InputStream in, final Charset charset) { - return new JsonStreamParser(in, charset, maxSize); + return getDefaultJsonParserImpl(in, charset); } @Override @@ -73,6 +87,6 @@ public class JsonParserFactoryImpl implements JsonParserFactory { @Override public Map getConfigInUse() { - return config; + return Collections.unmodifiableMap(config); } } diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderFactoryImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderFactoryImpl.java index 934a299..82c5cba 100644 --- a/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderFactoryImpl.java +++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderFactoryImpl.java @@ -20,10 +20,12 @@ package org.apache.fleece.core; import javax.json.JsonReader; import javax.json.JsonReaderFactory; + import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.Charset; +import java.util.Collections; import java.util.Map; public class JsonReaderFactoryImpl implements JsonReaderFactory { @@ -50,6 +52,6 @@ public class JsonReaderFactoryImpl implements JsonReaderFactory { @Override public Map getConfigInUse() { - return config; + return Collections.unmodifiableMap(config); } } diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java index 03d52f2..6f6b71c 100644 --- a/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java +++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java @@ -18,6 +18,7 @@ */ package org.apache.fleece.core; +import javax.json.Json; import javax.json.JsonArray; import javax.json.JsonObject; import javax.json.JsonReader; @@ -25,6 +26,7 @@ import javax.json.JsonStructure; import javax.json.JsonValue; import javax.json.stream.JsonParser; import javax.json.stream.JsonParsingException; + import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; @@ -32,13 +34,13 @@ import java.math.BigDecimal; public class JsonReaderImpl implements JsonReader { private final EscapedStringAwareJsonParser parser; private final JsonReaderListenerFactory listenerFactory; - + public JsonReaderImpl(final InputStream in) { - this(new JsonStreamParser(in, JsonParserFactoryImpl.DEFAULT_MAX_SIZE), new JsonListenerFactory()); + this((EscapedStringAwareJsonParser)Json.createParser(in), new JsonListenerFactory()); } public JsonReaderImpl(final Reader in) { - this(new JsonStreamParser(in, JsonParserFactoryImpl.DEFAULT_MAX_SIZE), new JsonListenerFactory()); + this((EscapedStringAwareJsonParser)Json.createParser(in), new JsonListenerFactory()); } public JsonReaderImpl(final EscapedStringAwareJsonParser parser, final JsonReaderListenerFactory listenerFactory) { @@ -157,7 +159,6 @@ public class JsonReaderImpl implements JsonReader { private static class JsonArrayListener implements JsonReaderListener { private JsonArrayImpl array = new JsonArrayImpl(); - private String key = null; @Override public Object getObject() { @@ -266,10 +267,10 @@ public class JsonReaderImpl implements JsonReader { return; case END_ARRAY: - throw new JsonParsingException("']', shouldn't occur", JsonStreamParser.location(parser)); + throw new JsonParsingException("']', shouldn't occur", parser.getLocation()); default: - throw new JsonParsingException(next.name() + ", shouldn't occur", JsonStreamParser.location(parser)); + throw new JsonParsingException(next.name() + ", shouldn't occur", parser.getLocation()); } } } @@ -318,13 +319,13 @@ public class JsonReaderImpl implements JsonReader { break; case KEY_NAME: - throw new JsonParsingException("array doesn't have keys", JsonStreamParser.location(parser)); + throw new JsonParsingException("array doesn't have keys", parser.getLocation()); case END_OBJECT: - throw new JsonParsingException("'}', shouldn't occur", JsonStreamParser.location(parser)); + throw new JsonParsingException("'}', shouldn't occur", parser.getLocation()); default: - throw new JsonParsingException(next.name() + ", shouldn't occur", JsonStreamParser.location(parser)); + throw new JsonParsingException(next.name() + ", shouldn't occur", parser.getLocation()); } } } diff --git a/fleece-mapper/src/test/java/org/apache/fleece/mapper/MapperTest.java b/fleece-mapper/src/test/java/org/apache/fleece/mapper/MapperTest.java index 17afd4b..b01c3d3 100644 --- a/fleece-mapper/src/test/java/org/apache/fleece/mapper/MapperTest.java +++ b/fleece-mapper/src/test/java/org/apache/fleece/mapper/MapperTest.java @@ -56,7 +56,7 @@ public class MapperTest { "\"integer\":3," + "\"longnumber\":4" + "}" + - "]" + + "]," + "\"list\":[" + "{" + "\"name\":\"a3\"," + @@ -68,7 +68,7 @@ public class MapperTest { "\"integer\":7," + "\"longnumber\":8" + "}" + - "]" + + "]," + "\"primitives\":[1,2,3,4,5]," + "\"collectionWrapper\":[1,2,3,4,5]," + "\"map\":{\"uno\":\"true\",\"duos\":false}" + -- 1.8.5.2 (Apple Git-48)