diff --git a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/httpserver/AbstractPost.java b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/httpserver/AbstractPost.java index c8b2a90cd42a90c1f85694ee2eb31a3d12080369..90c945b297c4d2b1633d9cdcc5498dd7d5680060 100644 --- a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/httpserver/AbstractPost.java +++ b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/httpserver/AbstractPost.java @@ -6,8 +6,8 @@ import com.a.eye.skywalking.collector.actor.LocalAsyncWorkerRef; import com.a.eye.skywalking.collector.actor.LocalWorkerContext; import com.a.eye.skywalking.collector.actor.Role; import com.a.eye.skywalking.collector.worker.segment.entity.Segment; -import com.a.eye.skywalking.collector.worker.segment.entity.SegmentJsonReader; import com.google.gson.JsonObject; +import com.google.gson.stream.JsonReader; import java.io.BufferedReader; import java.io.IOException; import javax.servlet.ServletException; @@ -57,12 +57,12 @@ public abstract class AbstractPost extends AbstractLocalAsyncWorker { } private void streamReader(BufferedReader bufferedReader) throws Exception { - try (SegmentJsonReader reader = new SegmentJsonReader(bufferedReader)) { + try (JsonReader reader = new JsonReader(bufferedReader)) { readSegmentArray(reader); } } - private void readSegmentArray(SegmentJsonReader reader) throws Exception { + private void readSegmentArray(JsonReader reader) throws Exception { reader.beginArray(); while (reader.hasNext()) { Segment segment = new Segment(); diff --git a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/GlobalTraceId.java b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/GlobalTraceId.java index 5da3caaffcb57d03232ffd21c250c60ec8ba1cbe..c6db1527b0dd807e87decd7a3e8468c95f48cbd5 100644 --- a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/GlobalTraceId.java +++ b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/GlobalTraceId.java @@ -1,5 +1,6 @@ package com.a.eye.skywalking.collector.worker.segment.entity; +import com.google.gson.stream.JsonReader; import java.io.IOException; /** @@ -12,8 +13,8 @@ public class GlobalTraceId extends DeserializeObject { return globalTraceId; } - public GlobalTraceId deserialize(SegmentJsonReader reader) throws IOException { - this.globalTraceId = reader.nextString().getValue(); + public GlobalTraceId deserialize(JsonReader reader) throws IOException { + this.globalTraceId = reader.nextString(); this.setJsonStr("\"" + globalTraceId + "\""); return this; } diff --git a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/JsonBuilder.java b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/JsonBuilder.java index 7c72987e13fa3bc688108d03a75834119dbebb03..39d2a567d2f65ad584a71007d5c896a84a219d61 100644 --- a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/JsonBuilder.java +++ b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/JsonBuilder.java @@ -1,5 +1,6 @@ package com.a.eye.skywalking.collector.worker.segment.entity; +import com.google.gson.Gson; import java.util.List; import java.util.Map; @@ -9,6 +10,8 @@ import java.util.Map; public enum JsonBuilder { INSTANCE; + private final Gson gson = new Gson(); + public void append(StringBuilder builder, String name, String value, boolean first) { if (!first) { builder.append(","); @@ -58,7 +61,8 @@ public enum JsonBuilder { builder.append(","); } if (value instanceof String) { - builder.append("\"").append(key).append("\":\"").append(value).append("\""); +// builder.append("\"").append(key).append("\":\"").append(value).append("\""); + builder.append("\"").append(key).append("\":").append(gson.toJson(value)); } else { builder.append("\"").append(key).append("\":").append(value); } diff --git a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/LogData.java b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/LogData.java index 85163e17ef2138c245b0b138e78fdfe81e4b703d..48b7b4eb81093465f2b084263a67bf549941d99c 100644 --- a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/LogData.java +++ b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/LogData.java @@ -1,5 +1,6 @@ package com.a.eye.skywalking.collector.worker.segment.entity; +import com.google.gson.stream.JsonReader; import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -19,7 +20,7 @@ public class LogData extends DeserializeObject { return fields; } - public LogData deserialize(SegmentJsonReader reader) throws IOException { + public LogData deserialize(JsonReader reader) throws IOException { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("{"); @@ -38,7 +39,7 @@ public class LogData extends DeserializeObject { while (reader.hasNext()) { String key = reader.nextName(); - String value = reader.nextString().getOriginValue(); + String value = reader.nextString(); fields.put(key, value); } reader.endObject(); diff --git a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/Segment.java b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/Segment.java index 2b32d35d48439f5b758d53597067090a7f25a110..16aa806664cd80cebab4bbccefaefe0783073abd 100644 --- a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/Segment.java +++ b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/Segment.java @@ -1,5 +1,6 @@ package com.a.eye.skywalking.collector.worker.segment.entity; +import com.google.gson.stream.JsonReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -44,7 +45,7 @@ public class Segment extends DeserializeObject { return relatedGlobalTraces; } - public Segment deserialize(SegmentJsonReader reader) throws IOException { + public Segment deserialize(JsonReader reader) throws IOException { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("{"); @@ -53,14 +54,12 @@ public class Segment extends DeserializeObject { while (reader.hasNext()) { switch (reader.nextName()) { case "ts": - SegmentJsonReader.StringValue ts = reader.nextString(); - this.traceSegmentId = ts.getValue(); - JsonBuilder.INSTANCE.append(stringBuilder, "ts", ts.getOriginValue(), first); + this.traceSegmentId = reader.nextString(); + JsonBuilder.INSTANCE.append(stringBuilder, "ts", this.traceSegmentId, first); break; case "ac": - SegmentJsonReader.StringValue ac = reader.nextString(); - this.applicationCode = ac.getValue(); - JsonBuilder.INSTANCE.append(stringBuilder, "ac", ac.getOriginValue(), first); + this.applicationCode = reader.nextString(); + JsonBuilder.INSTANCE.append(stringBuilder, "ac", this.applicationCode, first); break; case "st": long st = reader.nextLong(); diff --git a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/SegmentDeserialize.java b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/SegmentDeserialize.java index 8f954f7f2876d1dcd7e52b58f027b0eb1ad65bae..4c85dae83fee016488d2a9a64cea90b87706092e 100644 --- a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/SegmentDeserialize.java +++ b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/SegmentDeserialize.java @@ -1,5 +1,6 @@ package com.a.eye.skywalking.collector.worker.segment.entity; +import com.google.gson.stream.JsonReader; import java.io.FileReader; import java.io.IOException; import java.io.StringReader; @@ -13,7 +14,7 @@ public enum SegmentDeserialize { INSTANCE; public Segment deserializeSingle(String singleSegmentJsonStr) throws IOException { - SegmentJsonReader reader = new SegmentJsonReader(new StringReader(singleSegmentJsonStr)); + JsonReader reader = new JsonReader(new StringReader(singleSegmentJsonStr)); Segment segment = new Segment(); segment.deserialize(reader); return segment; @@ -26,12 +27,12 @@ public enum SegmentDeserialize { } private void streamReader(List segmentList, FileReader fileReader) throws Exception { - try (SegmentJsonReader reader = new SegmentJsonReader(fileReader)) { + try (JsonReader reader = new JsonReader(fileReader)) { readSegmentArray(segmentList, reader); } } - private void readSegmentArray(List segmentList, SegmentJsonReader reader) throws Exception { + private void readSegmentArray(List segmentList, JsonReader reader) throws Exception { reader.beginArray(); while (reader.hasNext()) { Segment segment = new Segment(); diff --git a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/SegmentJsonReader.java b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/SegmentJsonReader.java deleted file mode 100644 index 6837ef9d9873ef327f6ae5b86573aa77aa3c2503..0000000000000000000000000000000000000000 --- a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/SegmentJsonReader.java +++ /dev/null @@ -1,1505 +0,0 @@ -package com.a.eye.skywalking.collector.worker.segment.entity; - -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.MalformedJsonException; -import java.io.Closeable; -import java.io.EOFException; -import java.io.IOException; -import java.io.Reader; - -/** - * Copy from {@link com.google.gson.stream.JsonReader}, modify the {@link #nextString()} method, make it return quoted - * string and unquoted string. - * - * @author pengys5 - */ -public class SegmentJsonReader implements Closeable { - /** The only non-execute prefix this parser permits */ - private static final char[] NON_EXECUTE_PREFIX = ")]}'\n".toCharArray(); - private static final long MIN_INCOMPLETE_INTEGER = Long.MIN_VALUE / 10; - - private static final int PEEKED_NONE = 0; - private static final int PEEKED_BEGIN_OBJECT = 1; - private static final int PEEKED_END_OBJECT = 2; - private static final int PEEKED_BEGIN_ARRAY = 3; - private static final int PEEKED_END_ARRAY = 4; - private static final int PEEKED_TRUE = 5; - private static final int PEEKED_FALSE = 6; - private static final int PEEKED_NULL = 7; - private static final int PEEKED_SINGLE_QUOTED = 8; - private static final int PEEKED_DOUBLE_QUOTED = 9; - private static final int PEEKED_UNQUOTED = 10; - /** When this is returned, the string value is stored in peekedString. */ - private static final int PEEKED_BUFFERED = 11; - private static final int PEEKED_SINGLE_QUOTED_NAME = 12; - private static final int PEEKED_DOUBLE_QUOTED_NAME = 13; - private static final int PEEKED_UNQUOTED_NAME = 14; - /** When this is returned, the integer value is stored in peekedLong. */ - private static final int PEEKED_LONG = 15; - private static final int PEEKED_NUMBER = 16; - private static final int PEEKED_EOF = 17; - - /* State machine when parsing numbers */ - private static final int NUMBER_CHAR_NONE = 0; - private static final int NUMBER_CHAR_SIGN = 1; - private static final int NUMBER_CHAR_DIGIT = 2; - private static final int NUMBER_CHAR_DECIMAL = 3; - private static final int NUMBER_CHAR_FRACTION_DIGIT = 4; - private static final int NUMBER_CHAR_EXP_E = 5; - private static final int NUMBER_CHAR_EXP_SIGN = 6; - private static final int NUMBER_CHAR_EXP_DIGIT = 7; - - /** The input JSON. */ - private final Reader in; - - /** True to accept non-spec compliant JSON */ - private boolean lenient = false; - - /** - * Use a manual buffer to easily read and unread upcoming characters, and - * also so we can create strings without an intermediate StringBuilder. - * We decode literals directly out of this buffer, so it must be at least as - * long as the longest token that can be reported as a number. - */ - private final char[] buffer = new char[1024]; - private int pos = 0; - private int limit = 0; - - private int lineNumber = 0; - private int lineStart = 0; - - int peeked = PEEKED_NONE; - - /** - * A peeked value that was composed entirely of digits with an optional - * leading dash. Positive values may not have a leading 0. - */ - private long peekedLong; - - /** - * The number of characters in a peeked number literal. Increment 'pos' by - * this after reading a number. - */ - private int peekedNumberLength; - - /** - * A peeked string that should be parsed on the next double, long or string. - * This is populated before a numeric value is parsed and used if that parsing - * fails. - */ - private String peekedString; - - /* - * The nesting stack. Using a manual array rather than an ArrayList saves 20%. - */ - private int[] stack = new int[32]; - private int stackSize = 0; - - { - stack[stackSize++] = SegmentJsonScope.EMPTY_DOCUMENT; - } - - /* - * The path members. It corresponds directly to stack: At indices where the - * stack contains an object (EMPTY_OBJECT, DANGLING_NAME or NONEMPTY_OBJECT), - * pathNames contains the name at this scope. Where it contains an array - * (EMPTY_ARRAY, NONEMPTY_ARRAY) pathIndices contains the current index in - * that array. Otherwise the value is undefined, and we take advantage of that - * by incrementing pathIndices when doing so isn't useful. - */ - private String[] pathNames = new String[32]; - private int[] pathIndices = new int[32]; - - /** - * Creates a new instance that reads a JSON-encoded stream from {@code in}. - */ - public SegmentJsonReader(Reader in) { - if (in == null) { - throw new NullPointerException("in == null"); - } - this.in = in; - } - - /** - * Configure this parser to be liberal in what it accepts. By default, - * this parser is strict and only accepts JSON as specified by RFC 4627. Setting the - * parser to lenient causes it to ignore the following syntax errors: - * - *
    - *
  • Streams that start with the non-execute - * prefix, ")]}'\n". - *
  • Streams that include multiple top-level values. With strict parsing, - * each stream must contain exactly one top-level value. - *
  • Top-level values of any type. With strict parsing, the top-level - * value must be an object or an array. - *
  • Numbers may be {@link Double#isNaN() NaNs} or {@link - * Double#isInfinite() infinities}. - *
  • End of line comments starting with {@code //} or {@code #} and - * ending with a newline character. - *
  • C-style comments starting with {@code /*} and ending with - * {@code *}{@code /}. Such comments may not be nested. - *
  • Names that are unquoted or {@code 'single quoted'}. - *
  • Strings that are unquoted or {@code 'single quoted'}. - *
  • Array elements separated by {@code ;} instead of {@code ,}. - *
  • Unnecessary array separators. These are interpreted as if null - * was the omitted value. - *
  • Names and values separated by {@code =} or {@code =>} instead of - * {@code :}. - *
  • Name/value pairs separated by {@code ;} instead of {@code ,}. - *
- */ - public final void setLenient(boolean lenient) { - this.lenient = lenient; - } - - /** - * Returns true if this parser is liberal in what it accepts. - */ - public final boolean isLenient() { - return lenient; - } - - /** - * Consumes the next token from the JSON stream and asserts that it is the - * beginning of a new array. - */ - public void beginArray() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - if (p == PEEKED_BEGIN_ARRAY) { - push(SegmentJsonScope.EMPTY_ARRAY); - pathIndices[stackSize - 1] = 0; - peeked = PEEKED_NONE; - } else { - throw new IllegalStateException("Expected BEGIN_ARRAY but was " + peek() + locationString()); - } - } - - /** - * Consumes the next token from the JSON stream and asserts that it is the - * end of the current array. - */ - public void endArray() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - if (p == PEEKED_END_ARRAY) { - stackSize--; - pathIndices[stackSize - 1]++; - peeked = PEEKED_NONE; - } else { - throw new IllegalStateException("Expected END_ARRAY but was " + peek() + locationString()); - } - } - - /** - * Consumes the next token from the JSON stream and asserts that it is the - * beginning of a new object. - */ - public void beginObject() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - if (p == PEEKED_BEGIN_OBJECT) { - push(SegmentJsonScope.EMPTY_OBJECT); - peeked = PEEKED_NONE; - } else { - throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek() + locationString()); - } - } - - /** - * Consumes the next token from the JSON stream and asserts that it is the - * end of the current object. - */ - public void endObject() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - if (p == PEEKED_END_OBJECT) { - stackSize--; - pathNames[stackSize] = null; // Free the last path name so that it can be garbage collected! - pathIndices[stackSize - 1]++; - peeked = PEEKED_NONE; - } else { - throw new IllegalStateException("Expected END_OBJECT but was " + peek() + locationString()); - } - } - - /** - * Returns true if the current array or object has another element. - */ - public boolean hasNext() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - return p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY; - } - - /** - * Returns the type of the next token without consuming it. - */ - public JsonToken peek() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - - switch (p) { - case PEEKED_BEGIN_OBJECT: - return JsonToken.BEGIN_OBJECT; - case PEEKED_END_OBJECT: - return JsonToken.END_OBJECT; - case PEEKED_BEGIN_ARRAY: - return JsonToken.BEGIN_ARRAY; - case PEEKED_END_ARRAY: - return JsonToken.END_ARRAY; - case PEEKED_SINGLE_QUOTED_NAME: - case PEEKED_DOUBLE_QUOTED_NAME: - case PEEKED_UNQUOTED_NAME: - return JsonToken.NAME; - case PEEKED_TRUE: - case PEEKED_FALSE: - return JsonToken.BOOLEAN; - case PEEKED_NULL: - return JsonToken.NULL; - case PEEKED_SINGLE_QUOTED: - case PEEKED_DOUBLE_QUOTED: - case PEEKED_UNQUOTED: - case PEEKED_BUFFERED: - return JsonToken.STRING; - case PEEKED_LONG: - case PEEKED_NUMBER: - return JsonToken.NUMBER; - case PEEKED_EOF: - return JsonToken.END_DOCUMENT; - default: - throw new AssertionError(); - } - } - - int doPeek() throws IOException { - int peekStack = stack[stackSize - 1]; - if (peekStack == SegmentJsonScope.EMPTY_ARRAY) { - stack[stackSize - 1] = SegmentJsonScope.NONEMPTY_ARRAY; - } else if (peekStack == SegmentJsonScope.NONEMPTY_ARRAY) { - // Look for a comma before the next element. - int c = nextNonWhitespace(true); - switch (c) { - case ']': - return peeked = PEEKED_END_ARRAY; - case ';': - checkLenient(); // fall-through - case ',': - break; - default: - throw syntaxError("Unterminated array"); - } - } else if (peekStack == SegmentJsonScope.EMPTY_OBJECT || peekStack == SegmentJsonScope.NONEMPTY_OBJECT) { - stack[stackSize - 1] = SegmentJsonScope.DANGLING_NAME; - // Look for a comma before the next element. - if (peekStack == SegmentJsonScope.NONEMPTY_OBJECT) { - int c = nextNonWhitespace(true); - switch (c) { - case '}': - return peeked = PEEKED_END_OBJECT; - case ';': - checkLenient(); // fall-through - case ',': - break; - default: - throw syntaxError("Unterminated object"); - } - } - int c = nextNonWhitespace(true); - switch (c) { - case '"': - return peeked = PEEKED_DOUBLE_QUOTED_NAME; - case '\'': - checkLenient(); - return peeked = PEEKED_SINGLE_QUOTED_NAME; - case '}': - if (peekStack != SegmentJsonScope.NONEMPTY_OBJECT) { - return peeked = PEEKED_END_OBJECT; - } else { - throw syntaxError("Expected name"); - } - default: - checkLenient(); - pos--; // Don't consume the first character in an unquoted string. - if (isLiteral((char)c)) { - return peeked = PEEKED_UNQUOTED_NAME; - } else { - throw syntaxError("Expected name"); - } - } - } else if (peekStack == SegmentJsonScope.DANGLING_NAME) { - stack[stackSize - 1] = SegmentJsonScope.NONEMPTY_OBJECT; - // Look for a colon before the value. - int c = nextNonWhitespace(true); - switch (c) { - case ':': - break; - case '=': - checkLenient(); - if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') { - pos++; - } - break; - default: - throw syntaxError("Expected ':'"); - } - } else if (peekStack == SegmentJsonScope.EMPTY_DOCUMENT) { - if (lenient) { - consumeNonExecutePrefix(); - } - stack[stackSize - 1] = SegmentJsonScope.NONEMPTY_DOCUMENT; - } else if (peekStack == SegmentJsonScope.NONEMPTY_DOCUMENT) { - int c = nextNonWhitespace(false); - if (c == -1) { - return peeked = PEEKED_EOF; - } else { - checkLenient(); - pos--; - } - } else if (peekStack == SegmentJsonScope.CLOSED) { - throw new IllegalStateException("JsonReader is closed"); - } - - int c = nextNonWhitespace(true); - switch (c) { - case ']': - if (peekStack == SegmentJsonScope.EMPTY_ARRAY) { - return peeked = PEEKED_END_ARRAY; - } - // fall-through to handle ",]" - case ';': - case ',': - // In lenient mode, a 0-length literal in an array means 'null'. - if (peekStack == SegmentJsonScope.EMPTY_ARRAY || peekStack == SegmentJsonScope.NONEMPTY_ARRAY) { - checkLenient(); - pos--; - return peeked = PEEKED_NULL; - } else { - throw syntaxError("Unexpected value"); - } - case '\'': - checkLenient(); - return peeked = PEEKED_SINGLE_QUOTED; - case '"': - return peeked = PEEKED_DOUBLE_QUOTED; - case '[': - return peeked = PEEKED_BEGIN_ARRAY; - case '{': - return peeked = PEEKED_BEGIN_OBJECT; - default: - pos--; // Don't consume the first character in a literal value. - } - - int result = peekKeyword(); - if (result != PEEKED_NONE) { - return result; - } - - result = peekNumber(); - if (result != PEEKED_NONE) { - return result; - } - - if (!isLiteral(buffer[pos])) { - throw syntaxError("Expected value"); - } - - checkLenient(); - return peeked = PEEKED_UNQUOTED; - } - - private int peekKeyword() throws IOException { - // Figure out which keyword we're matching against by its first character. - char c = buffer[pos]; - String keyword; - String keywordUpper; - int peeking; - if (c == 't' || c == 'T') { - keyword = "true"; - keywordUpper = "TRUE"; - peeking = PEEKED_TRUE; - } else if (c == 'f' || c == 'F') { - keyword = "false"; - keywordUpper = "FALSE"; - peeking = PEEKED_FALSE; - } else if (c == 'n' || c == 'N') { - keyword = "null"; - keywordUpper = "NULL"; - peeking = PEEKED_NULL; - } else { - return PEEKED_NONE; - } - - // Confirm that chars [1..length) match the keyword. - int length = keyword.length(); - for (int i = 1; i < length; i++) { - if (pos + i >= limit && !fillBuffer(i + 1)) { - return PEEKED_NONE; - } - c = buffer[pos + i]; - if (c != keyword.charAt(i) && c != keywordUpper.charAt(i)) { - return PEEKED_NONE; - } - } - - if ((pos + length < limit || fillBuffer(length + 1)) - && isLiteral(buffer[pos + length])) { - return PEEKED_NONE; // Don't match trues, falsey or nullsoft! - } - - // We've found the keyword followed either by EOF or by a non-literal character. - pos += length; - return peeked = peeking; - } - - private int peekNumber() throws IOException { - // Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access. - char[] buffer = this.buffer; - int p = pos; - int l = limit; - - long value = 0; // Negative to accommodate Long.MIN_VALUE more easily. - boolean negative = false; - boolean fitsInLong = true; - int last = NUMBER_CHAR_NONE; - - int i = 0; - - charactersOfNumber: - for (; true; i++) { - if (p + i == l) { - if (i == buffer.length) { - // Though this looks like a well-formed number, it's too long to continue reading. Give up - // and let the application handle this as an unquoted literal. - return PEEKED_NONE; - } - if (!fillBuffer(i + 1)) { - break; - } - p = pos; - l = limit; - } - - char c = buffer[p + i]; - switch (c) { - case '-': - if (last == NUMBER_CHAR_NONE) { - negative = true; - last = NUMBER_CHAR_SIGN; - continue; - } else if (last == NUMBER_CHAR_EXP_E) { - last = NUMBER_CHAR_EXP_SIGN; - continue; - } - return PEEKED_NONE; - - case '+': - if (last == NUMBER_CHAR_EXP_E) { - last = NUMBER_CHAR_EXP_SIGN; - continue; - } - return PEEKED_NONE; - - case 'e': - case 'E': - if (last == NUMBER_CHAR_DIGIT || last == NUMBER_CHAR_FRACTION_DIGIT) { - last = NUMBER_CHAR_EXP_E; - continue; - } - return PEEKED_NONE; - - case '.': - if (last == NUMBER_CHAR_DIGIT) { - last = NUMBER_CHAR_DECIMAL; - continue; - } - return PEEKED_NONE; - - default: - if (c < '0' || c > '9') { - if (!isLiteral(c)) { - break charactersOfNumber; - } - return PEEKED_NONE; - } - if (last == NUMBER_CHAR_SIGN || last == NUMBER_CHAR_NONE) { - value = -(c - '0'); - last = NUMBER_CHAR_DIGIT; - } else if (last == NUMBER_CHAR_DIGIT) { - if (value == 0) { - return PEEKED_NONE; // Leading '0' prefix is not allowed (since it could be octal). - } - long newValue = value * 10 - (c - '0'); - fitsInLong &= value > MIN_INCOMPLETE_INTEGER - || (value == MIN_INCOMPLETE_INTEGER && newValue < value); - value = newValue; - } else if (last == NUMBER_CHAR_DECIMAL) { - last = NUMBER_CHAR_FRACTION_DIGIT; - } else if (last == NUMBER_CHAR_EXP_E || last == NUMBER_CHAR_EXP_SIGN) { - last = NUMBER_CHAR_EXP_DIGIT; - } - } - } - - // We've read a complete number. Decide if it's a PEEKED_LONG or a PEEKED_NUMBER. - if (last == NUMBER_CHAR_DIGIT && fitsInLong && (value != Long.MIN_VALUE || negative)) { - peekedLong = negative ? value : -value; - pos += i; - return peeked = PEEKED_LONG; - } else if (last == NUMBER_CHAR_DIGIT || last == NUMBER_CHAR_FRACTION_DIGIT - || last == NUMBER_CHAR_EXP_DIGIT) { - peekedNumberLength = i; - return peeked = PEEKED_NUMBER; - } else { - return PEEKED_NONE; - } - } - - private boolean isLiteral(char c) throws IOException { - switch (c) { - case '/': - case '\\': - case ';': - case '#': - case '=': - checkLenient(); // fall-through - case '{': - case '}': - case '[': - case ']': - case ':': - case ',': - case ' ': - case '\t': - case '\f': - case '\r': - case '\n': - return false; - default: - return true; - } - } - - /** - * Returns the next token, a {@link com.google.gson.stream.JsonToken#NAME property name}, and - * consumes it. - * - * @throws java.io.IOException if the next token in the stream is not a property name. - */ - public String nextName() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - String result; - if (p == PEEKED_UNQUOTED_NAME) { - result = nextUnquotedValue(); - } else if (p == PEEKED_SINGLE_QUOTED_NAME) { - result = nextQuotedValue('\''); - } else if (p == PEEKED_DOUBLE_QUOTED_NAME) { - result = nextQuotedValue('"'); - } else { - throw new IllegalStateException("Expected a name but was " + peek() + locationString()); - } - peeked = PEEKED_NONE; - pathNames[stackSize - 1] = result; - return result; - } - - /** - * Returns the {@link com.google.gson.stream.JsonToken#STRING string} value of the next token, - * consuming it. If the next token is a number, this method will return its - * string form. - * - * @throws IllegalStateException if the next token is not a string or if this reader is closed. - */ - public StringValue nextString() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - StringValue result = new StringValue(); - if (p == PEEKED_UNQUOTED) { - result.setValue(nextUnquotedValue()); - result.setOriginValue(nextUnquotedValue()); - } else if (p == PEEKED_SINGLE_QUOTED) { - result.setValue(nextQuotedValue('\'')); - result.setOriginValue(nextQuotedValue('\'')); - } else if (p == PEEKED_DOUBLE_QUOTED) { - result = nextQuotedValueForString('"'); - } else if (p == PEEKED_BUFFERED) { - result.setValue(peekedString); - result.setOriginValue(peekedString); - peekedString = null; - } else if (p == PEEKED_LONG) { - result.setValue(Long.toString(peekedLong)); - result.setOriginValue(Long.toString(peekedLong)); - } else if (p == PEEKED_NUMBER) { - result.setValue(new String(buffer, pos, peekedNumberLength)); - result.setOriginValue(new String(buffer, pos, peekedNumberLength)); - pos += peekedNumberLength; - } else { - throw new IllegalStateException("Expected a string but was " + peek() + locationString()); - } - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - return result; - } - - /** - * Returns the {@link com.google.gson.stream.JsonToken#BOOLEAN boolean} value of the next token, - * consuming it. - * - * @throws IllegalStateException if the next token is not a boolean or if this reader is closed. - */ - public boolean nextBoolean() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - if (p == PEEKED_TRUE) { - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - return true; - } else if (p == PEEKED_FALSE) { - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - return false; - } - throw new IllegalStateException("Expected a boolean but was " + peek() + locationString()); - } - - /** - * Consumes the next token from the JSON stream and asserts that it is a - * literal null. - * - * @throws IllegalStateException if the next token is not null or if this reader is closed. - */ - public void nextNull() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - if (p == PEEKED_NULL) { - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - } else { - throw new IllegalStateException("Expected null but was " + peek() + locationString()); - } - } - - /** - * Returns the {@link com.google.gson.stream.JsonToken#NUMBER double} value of the next token, - * consuming it. If the next token is a string, this method will attempt to - * parse it as a double using {@link Double#parseDouble(String)}. - * - * @throws IllegalStateException if the next token is not a literal value. - * @throws NumberFormatException if the next literal value cannot be parsed as a double, or is non-finite. - */ - public double nextDouble() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - - if (p == PEEKED_LONG) { - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - return (double)peekedLong; - } - - if (p == PEEKED_NUMBER) { - peekedString = new String(buffer, pos, peekedNumberLength); - pos += peekedNumberLength; - } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED) { - peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"'); - } else if (p == PEEKED_UNQUOTED) { - peekedString = nextUnquotedValue(); - } else if (p != PEEKED_BUFFERED) { - throw new IllegalStateException("Expected a double but was " + peek() + locationString()); - } - - peeked = PEEKED_BUFFERED; - double result = Double.parseDouble(peekedString); // don't catch this NumberFormatException. - if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) { - throw new MalformedJsonException( - "JSON forbids NaN and infinities: " + result + locationString()); - } - peekedString = null; - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - return result; - } - - /** - * Returns the {@link com.google.gson.stream.JsonToken#NUMBER long} value of the next token, - * consuming it. If the next token is a string, this method will attempt to - * parse it as a long. If the next token's numeric value cannot be exactly - * represented by a Java {@code long}, this method throws. - * - * @throws IllegalStateException if the next token is not a literal value. - * @throws NumberFormatException if the next literal value cannot be parsed as a number, or exactly represented as a - * long. - */ - public long nextLong() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - - if (p == PEEKED_LONG) { - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - return peekedLong; - } - - if (p == PEEKED_NUMBER) { - peekedString = new String(buffer, pos, peekedNumberLength); - pos += peekedNumberLength; - } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED || p == PEEKED_UNQUOTED) { - if (p == PEEKED_UNQUOTED) { - peekedString = nextUnquotedValue(); - } else { - peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"'); - } - try { - long result = Long.parseLong(peekedString); - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - return result; - } catch (NumberFormatException ignored) { - // Fall back to parse as a double below. - } - } else { - throw new IllegalStateException("Expected a long but was " + peek() + locationString()); - } - - peeked = PEEKED_BUFFERED; - double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException. - long result = (long)asDouble; - if (result != asDouble) { // Make sure no precision was lost casting to 'long'. - throw new NumberFormatException("Expected a long but was " + peekedString + locationString()); - } - peekedString = null; - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - return result; - } - - /** - * Returns the string up to but not including {@code quote}, unescaping any - * character escape sequences encountered along the way. The opening quote - * should have already been read. This consumes the closing quote, but does - * not include it in the returned string. - * - * @param quote either ' or ". - * @throws NumberFormatException if any unicode escape sequences are malformed. - */ - private String nextQuotedValue(char quote) throws IOException { - // Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access. - char[] buffer = this.buffer; - StringBuilder builder = new StringBuilder(); - while (true) { - int p = pos; - int l = limit; - /* the index of the first character not yet appended to the builder. */ - int start = p; - while (p < l) { - int c = buffer[p++]; - - if (c == quote) { - pos = p; - builder.append(buffer, start, p - start - 1); - return builder.toString(); - } else if (c == '\\') { - pos = p; - builder.append(buffer, start, p - start - 1); - builder.append(readEscapeCharacter()); - p = pos; - l = limit; - start = p; - } else if (c == '\n') { - lineNumber++; - lineStart = p; - } - } - - builder.append(buffer, start, p - start); - pos = p; - if (!fillBuffer(1)) { - throw syntaxError("Unterminated string"); - } - } - } - - private StringValue nextQuotedValueForString(char quote) throws IOException { - // Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access. - StringValue result = new StringValue(); - char[] buffer = this.buffer; - StringBuilder nonQuoteBuilder = new StringBuilder(); - StringBuilder quoteBuilder = new StringBuilder(); - while (true) { - int p = pos; - int l = limit; - /* the index of the first character not yet appended to the builder. */ - int start = p; - while (p < l) { - int c = buffer[p++]; - - if (c == quote) { - pos = p; - nonQuoteBuilder.append(buffer, start, p - start - 1); - quoteBuilder.append(buffer, start, p - start - 1); - - result.setValue(nonQuoteBuilder.toString()); - result.setOriginValue(quoteBuilder.toString()); - return result; - } else if (c == '\\') { - pos = p; - nonQuoteBuilder.append(buffer, start, p - start - 1); - quoteBuilder.append(buffer, start, p - start - 1); - - char character = readEscapeCharacter(); - nonQuoteBuilder.append(character); - - switch (character) { - case '\t': - quoteBuilder.append('\\').append('t'); - break; - case '\b': - quoteBuilder.append('\\').append('b'); - break; - case '\n': - quoteBuilder.append('\\').append('n'); - break; - case '\r': - quoteBuilder.append('\\').append('r'); - break; - case '\f': - quoteBuilder.append('\\').append('f'); - break; - case '\'': - case '"': - case '\\': - case '/': - quoteBuilder.append('\\'); - default: - quoteBuilder.append(character); - } - - p = pos; - l = limit; - start = p; - } else if (c == '\n') { - lineNumber++; - lineStart = p; - } - } - - nonQuoteBuilder.append(buffer, start, p - start); - quoteBuilder.append(buffer, start, p - start); - pos = p; - if (!fillBuffer(1)) { - throw syntaxError("Unterminated string"); - } - } - } - - /** - * Returns an unquoted value as a string. - */ - @SuppressWarnings("fallthrough") - private String nextUnquotedValue() throws IOException { - StringBuilder builder = null; - int i = 0; - - findNonLiteralCharacter: - while (true) { - for (; pos + i < limit; i++) { - switch (buffer[pos + i]) { - case '/': - case '\\': - case ';': - case '#': - case '=': - checkLenient(); // fall-through - case '{': - case '}': - case '[': - case ']': - case ':': - case ',': - case ' ': - case '\t': - case '\f': - case '\r': - case '\n': - break findNonLiteralCharacter; - } - } - - // Attempt to load the entire literal into the buffer at once. - if (i < buffer.length) { - if (fillBuffer(i + 1)) { - continue; - } else { - break; - } - } - - // use a StringBuilder when the value is too long. This is too long to be a number! - if (builder == null) { - builder = new StringBuilder(); - } - builder.append(buffer, pos, i); - pos += i; - i = 0; - if (!fillBuffer(1)) { - break; - } - } - - String result; - if (builder == null) { - result = new String(buffer, pos, i); - } else { - builder.append(buffer, pos, i); - result = builder.toString(); - } - pos += i; - return result; - } - - private void skipQuotedValue(char quote) throws IOException { - // Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access. - char[] buffer = this.buffer; - do { - int p = pos; - int l = limit; - /* the index of the first character not yet appended to the builder. */ - while (p < l) { - int c = buffer[p++]; - if (c == quote) { - pos = p; - return; - } else if (c == '\\') { - pos = p; - readEscapeCharacter(); - p = pos; - l = limit; - } else if (c == '\n') { - lineNumber++; - lineStart = p; - } - } - pos = p; - } - while (fillBuffer(1)); - throw syntaxError("Unterminated string"); - } - - private void skipUnquotedValue() throws IOException { - do { - int i = 0; - for (; pos + i < limit; i++) { - switch (buffer[pos + i]) { - case '/': - case '\\': - case ';': - case '#': - case '=': - checkLenient(); // fall-through - case '{': - case '}': - case '[': - case ']': - case ':': - case ',': - case ' ': - case '\t': - case '\f': - case '\r': - case '\n': - pos += i; - return; - } - } - pos += i; - } - while (fillBuffer(1)); - } - - /** - * Returns the {@link com.google.gson.stream.JsonToken#NUMBER int} value of the next token, - * consuming it. If the next token is a string, this method will attempt to - * parse it as an int. If the next token's numeric value cannot be exactly - * represented by a Java {@code int}, this method throws. - * - * @throws IllegalStateException if the next token is not a literal value. - * @throws NumberFormatException if the next literal value cannot be parsed as a number, or exactly represented as - * an int. - */ - public int nextInt() throws IOException { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - - int result; - if (p == PEEKED_LONG) { - result = (int)peekedLong; - if (peekedLong != result) { // Make sure no precision was lost casting to 'int'. - throw new NumberFormatException("Expected an int but was " + peekedLong + locationString()); - } - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - return result; - } - - if (p == PEEKED_NUMBER) { - peekedString = new String(buffer, pos, peekedNumberLength); - pos += peekedNumberLength; - } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED || p == PEEKED_UNQUOTED) { - if (p == PEEKED_UNQUOTED) { - peekedString = nextUnquotedValue(); - } else { - peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"'); - } - try { - result = Integer.parseInt(peekedString); - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - return result; - } catch (NumberFormatException ignored) { - // Fall back to parse as a double below. - } - } else { - throw new IllegalStateException("Expected an int but was " + peek() + locationString()); - } - - peeked = PEEKED_BUFFERED; - double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException. - result = (int)asDouble; - if (result != asDouble) { // Make sure no precision was lost casting to 'int'. - throw new NumberFormatException("Expected an int but was " + peekedString + locationString()); - } - peekedString = null; - peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - return result; - } - - /** - * Closes this JSON reader and the underlying {@link java.io.Reader}. - */ - public void close() throws IOException { - peeked = PEEKED_NONE; - stack[0] = SegmentJsonScope.CLOSED; - stackSize = 1; - in.close(); - } - - /** - * Skips the next value recursively. If it is an object or array, all nested - * elements are skipped. This method is intended for use when the JSON token - * stream contains unrecognized or unhandled values. - */ - public void skipValue() throws IOException { - int count = 0; - do { - int p = peeked; - if (p == PEEKED_NONE) { - p = doPeek(); - } - - if (p == PEEKED_BEGIN_ARRAY) { - push(SegmentJsonScope.EMPTY_ARRAY); - count++; - } else if (p == PEEKED_BEGIN_OBJECT) { - push(SegmentJsonScope.EMPTY_OBJECT); - count++; - } else if (p == PEEKED_END_ARRAY) { - stackSize--; - count--; - } else if (p == PEEKED_END_OBJECT) { - stackSize--; - count--; - } else if (p == PEEKED_UNQUOTED_NAME || p == PEEKED_UNQUOTED) { - skipUnquotedValue(); - } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_SINGLE_QUOTED_NAME) { - skipQuotedValue('\''); - } else if (p == PEEKED_DOUBLE_QUOTED || p == PEEKED_DOUBLE_QUOTED_NAME) { - skipQuotedValue('"'); - } else if (p == PEEKED_NUMBER) { - pos += peekedNumberLength; - } - peeked = PEEKED_NONE; - } - while (count != 0); - - pathIndices[stackSize - 1]++; - pathNames[stackSize - 1] = "null"; - } - - private void push(int newTop) { - if (stackSize == stack.length) { - int[] newStack = new int[stackSize * 2]; - int[] newPathIndices = new int[stackSize * 2]; - String[] newPathNames = new String[stackSize * 2]; - System.arraycopy(stack, 0, newStack, 0, stackSize); - System.arraycopy(pathIndices, 0, newPathIndices, 0, stackSize); - System.arraycopy(pathNames, 0, newPathNames, 0, stackSize); - stack = newStack; - pathIndices = newPathIndices; - pathNames = newPathNames; - } - stack[stackSize++] = newTop; - } - - /** - * Returns true once {@code limit - pos >= minimum}. If the data is - * exhausted before that many characters are available, this returns - * false. - */ - private boolean fillBuffer(int minimum) throws IOException { - char[] buffer = this.buffer; - lineStart -= pos; - if (limit != pos) { - limit -= pos; - System.arraycopy(buffer, pos, buffer, 0, limit); - } else { - limit = 0; - } - - pos = 0; - int total; - while ((total = in.read(buffer, limit, buffer.length - limit)) != -1) { - limit += total; - - // if this is the first read, consume an optional byte order mark (BOM) if it exists - if (lineNumber == 0 && lineStart == 0 && limit > 0 && buffer[0] == '\ufeff') { - pos++; - lineStart++; - minimum++; - } - - if (limit >= minimum) { - return true; - } - } - return false; - } - - /** - * Returns the next character in the stream that is neither whitespace nor a - * part of a comment. When this returns, the returned character is always at - * {@code buffer[pos-1]}; this means the caller can always push back the - * returned character by decrementing {@code pos}. - */ - private int nextNonWhitespace(boolean throwOnEof) throws IOException { - /* - * This code uses ugly local variables 'p' and 'l' representing the 'pos' - * and 'limit' fields respectively. Using locals rather than fields saves - * a few field reads for each whitespace character in a pretty-printed - * document, resulting in a 5% speedup. We need to flush 'p' to its field - * before any (potentially indirect) call to fillBuffer() and reread both - * 'p' and 'l' after any (potentially indirect) call to the same method. - */ - char[] buffer = this.buffer; - int p = pos; - int l = limit; - while (true) { - if (p == l) { - pos = p; - if (!fillBuffer(1)) { - break; - } - p = pos; - l = limit; - } - - int c = buffer[p++]; - if (c == '\n') { - lineNumber++; - lineStart = p; - continue; - } else if (c == ' ' || c == '\r' || c == '\t') { - continue; - } - - if (c == '/') { - pos = p; - if (p == l) { - pos--; // push back '/' so it's still in the buffer when this method returns - boolean charsLoaded = fillBuffer(2); - pos++; // consume the '/' again - if (!charsLoaded) { - return c; - } - } - - checkLenient(); - char peek = buffer[pos]; - switch (peek) { - case '*': - // skip a /* c-style comment */ - pos++; - if (!skipTo("*/")) { - throw syntaxError("Unterminated comment"); - } - p = pos + 2; - l = limit; - continue; - - case '/': - // skip a // end-of-line comment - pos++; - skipToEndOfLine(); - p = pos; - l = limit; - continue; - - default: - return c; - } - } else if (c == '#') { - pos = p; - /* - * Skip a # hash end-of-line comment. The JSON RFC doesn't - * specify this behaviour, but it's required to parse - * existing documents. See http://b/2571423. - */ - checkLenient(); - skipToEndOfLine(); - p = pos; - l = limit; - } else { - pos = p; - return c; - } - } - if (throwOnEof) { - throw new EOFException("End of input" + locationString()); - } else { - return -1; - } - } - - private void checkLenient() throws IOException { - if (!lenient) { - throw syntaxError("Use JsonReader.setLenient(true) to accept malformed JSON"); - } - } - - /** - * Advances the position until after the next newline character. If the line - * is terminated by "\r\n", the '\n' must be consumed as whitespace by the - * caller. - */ - private void skipToEndOfLine() throws IOException { - while (pos < limit || fillBuffer(1)) { - char c = buffer[pos++]; - if (c == '\n') { - lineNumber++; - lineStart = pos; - break; - } else if (c == '\r') { - break; - } - } - } - - /** - * @param toFind a string to search for. Must not contain a newline. - */ - private boolean skipTo(String toFind) throws IOException { - outer: - for (; pos + toFind.length() <= limit || fillBuffer(toFind.length()); pos++) { - if (buffer[pos] == '\n') { - lineNumber++; - lineStart = pos + 1; - continue; - } - for (int c = 0; c < toFind.length(); c++) { - if (buffer[pos + c] != toFind.charAt(c)) { - continue outer; - } - } - return true; - } - return false; - } - - @Override public String toString() { - return getClass().getSimpleName() + locationString(); - } - - private String locationString() { - int line = lineNumber + 1; - int column = pos - lineStart + 1; - return " at line " + line + " column " + column + " path " + getPath(); - } - - /** - * Returns a JsonPath to - * the current location in the JSON value. - */ - public String getPath() { - StringBuilder result = new StringBuilder().append('$'); - for (int i = 0, size = stackSize; i < size; i++) { - switch (stack[i]) { - case SegmentJsonScope.EMPTY_ARRAY: - case SegmentJsonScope.NONEMPTY_ARRAY: - result.append('[').append(pathIndices[i]).append(']'); - break; - - case SegmentJsonScope.EMPTY_OBJECT: - case SegmentJsonScope.DANGLING_NAME: - case SegmentJsonScope.NONEMPTY_OBJECT: - result.append('.'); - if (pathNames[i] != null) { - result.append(pathNames[i]); - } - break; - - case SegmentJsonScope.NONEMPTY_DOCUMENT: - case SegmentJsonScope.EMPTY_DOCUMENT: - case SegmentJsonScope.CLOSED: - break; - } - } - return result.toString(); - } - - /** - * Unescapes the character identified by the character or characters that - * immediately follow a backslash. The backslash '\' should have already - * been read. This supports both unicode escapes "u000A" and two-character - * escapes "\n". - * - * @throws NumberFormatException if any unicode escape sequences are malformed. - */ - private char readEscapeCharacter() throws IOException { - if (pos == limit && !fillBuffer(1)) { - throw syntaxError("Unterminated escape sequence"); - } - - char escaped = buffer[pos++]; - switch (escaped) { - case 'u': - if (pos + 4 > limit && !fillBuffer(4)) { - throw syntaxError("Unterminated escape sequence"); - } - // Equivalent to Integer.parseInt(stringPool.get(buffer, pos, 4), 16); - char result = 0; - for (int i = pos, end = i + 4; i < end; i++) { - char c = buffer[i]; - result <<= 4; - if (c >= '0' && c <= '9') { - result += c - '0'; - } else if (c >= 'a' && c <= 'f') { - result += c - 'a' + 10; - } else if (c >= 'A' && c <= 'F') { - result += c - 'A' + 10; - } else { - throw new NumberFormatException("\\u" + new String(buffer, pos, 4)); - } - } - pos += 4; - return result; - - case 't': - return '\t'; - - case 'b': - return '\b'; - - case 'n': - return '\n'; - - case 'r': - return '\r'; - - case 'f': - return '\f'; - - case '\n': - lineNumber++; - lineStart = pos; - // fall-through - - case '\'': - case '"': - case '\\': - case '/': - return escaped; - default: - // throw error when none of the above cases are matched - throw syntaxError("Invalid escape sequence"); - } - } - - /** - * Throws a new IO exception with the given message and a context snippet - * with this reader's content. - */ - private IOException syntaxError(String message) throws IOException { - throw new MalformedJsonException(message + locationString()); - } - - /** - * Consumes the non-execute prefix if it exists. - */ - private void consumeNonExecutePrefix() throws IOException { - // fast forward through the leading whitespace - nextNonWhitespace(true); - pos--; - - if (pos + NON_EXECUTE_PREFIX.length > limit && !fillBuffer(NON_EXECUTE_PREFIX.length)) { - return; - } - - for (int i = 0; i < NON_EXECUTE_PREFIX.length; i++) { - if (buffer[pos + i] != NON_EXECUTE_PREFIX[i]) { - return; // not a security token! - } - } - - // we consumed a security token! - pos += NON_EXECUTE_PREFIX.length; - } - - public static class StringValue { - private String value; - private String originValue; - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public String getOriginValue() { - return originValue; - } - - public void setOriginValue(String originValue) { - this.originValue = originValue; - } - } -} \ No newline at end of file diff --git a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/SegmentJsonScope.java b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/SegmentJsonScope.java deleted file mode 100644 index 479ab4d985958c33d003323501ab96ef92c15116..0000000000000000000000000000000000000000 --- a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/SegmentJsonScope.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.a.eye.skywalking.collector.worker.segment.entity; - -/** - * Copy from {@link com.google.gson.stream.JsonScope}, this class is invisible, {@link SegmentJsonReader} can not use it - * because of the package is different - * - * @author pengys5 - */ -public class SegmentJsonScope { - - /** - * An array with no elements requires no separators or newlines before - * it is closed. - */ - static final int EMPTY_ARRAY = 1; - - /** - * A array with at least one value requires a comma and newline before - * the next element. - */ - static final int NONEMPTY_ARRAY = 2; - - /** - * An object with no name/value pairs requires no separators or newlines - * before it is closed. - */ - static final int EMPTY_OBJECT = 3; - - /** - * An object whose most recent element is a key. The next element must - * be a value. - */ - static final int DANGLING_NAME = 4; - - /** - * An object with at least one name/value pair requires a comma and - * newline before the next element. - */ - static final int NONEMPTY_OBJECT = 5; - - /** - * No object or array has been started. - */ - static final int EMPTY_DOCUMENT = 6; - - /** - * A document with at an array or object. - */ - static final int NONEMPTY_DOCUMENT = 7; - - /** - * A document that's been closed and cannot be accessed. - */ - static final int CLOSED = 8; -} diff --git a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/Span.java b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/Span.java index 21f95626e1eb90610e569e698aee6e7e2ec4b33e..0a813ea4724f14474d0f27786835ff1c04563e28 100644 --- a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/Span.java +++ b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/Span.java @@ -1,5 +1,6 @@ package com.a.eye.skywalking.collector.worker.segment.entity; +import com.google.gson.stream.JsonReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -56,7 +57,7 @@ public class Span extends DeserializeObject { return logs; } - public Span deserialize(SegmentJsonReader reader) throws IOException { + public Span deserialize(JsonReader reader) throws IOException { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("{"); @@ -85,7 +86,7 @@ public class Span extends DeserializeObject { JsonBuilder.INSTANCE.append(stringBuilder, "et", et, first); break; case "on": - String on = reader.nextString().getValue(); + String on = reader.nextString(); this.operationName = on; JsonBuilder.INSTANCE.append(stringBuilder, "on", on, first); break; @@ -95,7 +96,7 @@ public class Span extends DeserializeObject { while (reader.hasNext()) { String key = reader.nextName(); - String value = reader.nextString().getOriginValue(); + String value = reader.nextString(); tagsWithStr.put(key, value); } reader.endObject(); diff --git a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/TraceSegmentRef.java b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/TraceSegmentRef.java index a90654596eab488b5d15996faf043515bc32a855..3386ec462a95f40cf5fd22034892d57359c06059 100644 --- a/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/TraceSegmentRef.java +++ b/skywalking-collector/skywalking-collector-worker/src/main/java/com/a/eye/skywalking/collector/worker/segment/entity/TraceSegmentRef.java @@ -1,5 +1,6 @@ package com.a.eye.skywalking.collector.worker.segment.entity; +import com.google.gson.stream.JsonReader; import java.io.IOException; /** @@ -31,7 +32,7 @@ public class TraceSegmentRef extends DeserializeObject { return peerHost; } - public TraceSegmentRef deserialize(SegmentJsonReader reader) throws IOException { + public TraceSegmentRef deserialize(JsonReader reader) throws IOException { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("{"); @@ -40,7 +41,7 @@ public class TraceSegmentRef extends DeserializeObject { while (reader.hasNext()) { switch (reader.nextName()) { case "ts": - String ts = reader.nextString().getValue(); + String ts = reader.nextString(); this.traceSegmentId = ts; JsonBuilder.INSTANCE.append(stringBuilder, "ts", ts, first); break; @@ -50,12 +51,12 @@ public class TraceSegmentRef extends DeserializeObject { JsonBuilder.INSTANCE.append(stringBuilder, "si", si, first); break; case "ac": - String ac = reader.nextString().getValue(); + String ac = reader.nextString(); this.applicationCode = ac; JsonBuilder.INSTANCE.append(stringBuilder, "ac", ac, first); break; case "ph": - String ph = reader.nextString().getValue(); + String ph = reader.nextString(); this.peerHost = ph; JsonBuilder.INSTANCE.append(stringBuilder, "ph", ph, first); break; diff --git a/skywalking-collector/skywalking-collector-worker/src/test/java/com/a/eye/skywalking/collector/worker/segment/entity/LogDataTestCase.java b/skywalking-collector/skywalking-collector-worker/src/test/java/com/a/eye/skywalking/collector/worker/segment/entity/LogDataTestCase.java index 439086279c93c3400b98f1d7fc16777e48c59aa0..63bd6ee891825bc57ea351fb8b19adf61c645142 100644 --- a/skywalking-collector/skywalking-collector-worker/src/test/java/com/a/eye/skywalking/collector/worker/segment/entity/LogDataTestCase.java +++ b/skywalking-collector/skywalking-collector-worker/src/test/java/com/a/eye/skywalking/collector/worker/segment/entity/LogDataTestCase.java @@ -1,5 +1,6 @@ package com.a.eye.skywalking.collector.worker.segment.entity; +import com.google.gson.stream.JsonReader; import java.io.IOException; import java.io.StringReader; import java.util.Map; @@ -15,7 +16,7 @@ public class LogDataTestCase { public void deserialize() throws IOException { LogData logData = new LogData(); - SegmentJsonReader reader = new SegmentJsonReader(new StringReader("{\"tm\":1, \"fi\": {\"test1\":\"test1\",\"test2\":\"test2\"}, \"skip\":\"skip\"}")); + JsonReader reader = new JsonReader(new StringReader("{\"tm\":1, \"fi\": {\"test1\":\"test1\",\"test2\":\"test2\"}, \"skip\":\"skip\"}")); logData.deserialize(reader); Assert.assertEquals(1L, logData.getTime()); diff --git a/skywalking-collector/skywalking-collector-worker/src/test/java/com/a/eye/skywalking/collector/worker/segment/entity/TraceSegmentRefTestCase.java b/skywalking-collector/skywalking-collector-worker/src/test/java/com/a/eye/skywalking/collector/worker/segment/entity/TraceSegmentRefTestCase.java index e7b72739a2aa1bc337fb68ce41736d33cd28bbb3..6bb6a0ee338c8abf41ac4df4364d4cc0517a3c43 100644 --- a/skywalking-collector/skywalking-collector-worker/src/test/java/com/a/eye/skywalking/collector/worker/segment/entity/TraceSegmentRefTestCase.java +++ b/skywalking-collector/skywalking-collector-worker/src/test/java/com/a/eye/skywalking/collector/worker/segment/entity/TraceSegmentRefTestCase.java @@ -1,5 +1,6 @@ package com.a.eye.skywalking.collector.worker.segment.entity; +import com.google.gson.stream.JsonReader; import java.io.IOException; import java.io.StringReader; import org.junit.Assert; @@ -13,7 +14,7 @@ public class TraceSegmentRefTestCase { @Test public void deserialize() throws IOException { TraceSegmentRef traceSegmentRef = new TraceSegmentRef(); - SegmentJsonReader reader = new SegmentJsonReader(new StringReader("{\"ts\" :\"ts\",\"si\":0,\"ac\":\"ac\",\"ph\":\"ph\", \"skip\":\"skip\"}")); + JsonReader reader = new JsonReader(new StringReader("{\"ts\" :\"ts\",\"si\":0,\"ac\":\"ac\",\"ph\":\"ph\", \"skip\":\"skip\"}")); traceSegmentRef.deserialize(reader); Assert.assertEquals("ts", traceSegmentRef.getTraceSegmentId()); diff --git a/skywalking-collector/skywalking-collector-worker/src/test/resources/json/segment/post/normal/cache-service.json b/skywalking-collector/skywalking-collector-worker/src/test/resources/json/segment/post/normal/cache-service.json index 7612746dc1645384c08a533444574ff2ad24fa13..ef049c8bee699f19bd7609372a4865927858b30f 100644 --- a/skywalking-collector/skywalking-collector-worker/src/test/resources/json/segment/post/normal/cache-service.json +++ b/skywalking-collector/skywalking-collector-worker/src/test/resources/json/segment/post/normal/cache-service.json @@ -367,6 +367,7 @@ "tm": 1490923010332, "fi": { "stack": "com.weibo.api.motan.exception.MotanBizException: error_message: provider call process error, status: 503, error_code: 30001,r\n\tat com.weibo.api.motan.rpc.DefaultProvider.invoke(DefaultProvider.java:62)\n\tat com.weibo.api.motan.rpc.AbstractProvider.call(AbstractProvider.java:47)\n\tat com.weibo.api.motan.filter.opentracing.OpenTracingFilter.process(OpenTracingFilter.java:94)\n\tat com.weibo.api.motan.filter.opentracing.OpenTracingFilter.processProviderTrace(OpenTracingFilter.java:148)\n\tat com.weibo.api.motan.filter.opentracing.OpenTracingFilter.filter(OpenTracingFilter.java:58)\n\tat com.weibo.api.motan.protocol.support.ProtocolFilterDecorator$2.call(ProtocolFilterDecorator.java:150)\n\tat com.weibo.api.motan.transport.ProviderMessageRouter.call$original$doBagGo8(ProviderMessageRouter.java:96)\n\tat com.weibo.api.motan.transport.ProviderMessageRouter.call$original$doBagGo8$accessor$PEWyOMYz(ProviderMessageRouter.java)\n\tat com.weibo.api.motan.transport.ProviderMessageRouter$auxiliary$s7ixnKeK.call(Unknown Source)\n\tat com.a.eye.skywalking.api.plugin.interceptor.enhance.ClassInstanceMethodsInterceptor.intercept(ClassInstanceMethodsInterceptor.java:66)\n\tat com.weibo.api.motan.transport.ProviderMessageRouter.call(ProviderMessageRouter.java)\n\tat com.weibo.api.motan.transport.ProviderProtectedMessageRouter.call(ProviderProtectedMessageRouter.java:79)\n\tat com.weibo.api.motan.transport.ProviderMessageRouter.handle(ProviderMessageRouter.java:91)\n\tat com.weibo.api.motan.transport.support.DefaultRpcHeartbeatFactory$HeartMessageHandleWrapper.handle(DefaultRpcHeartbeatFactory.java:82)\n\tat com.weibo.api.motan.transport.netty.NettyChannelHandler.processRequest(NettyChannelHandler.java:139)\n\tat com.weibo.api.motan.transport.netty.NettyChannelHandler.access$000(NettyChannelHandler.java:47)\n\tat com.weibo.api.motan.transport.netty.NettyChannelHandler$1.run(NettyChannelHandler.java:116)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)\n\tat java.lang.Thread.run(Thread.java:745)\nCaused by: java.lang.NullPointerException\n\tat com.a.eye.skywalking.test.cache.jedis.JedisServiceManager.findWithException(JedisServiceManager.java:49)\n\tat com.a.eye.skywalking.test.cache.CacheServiceImpl.findCacheWithException(CacheServiceImpl.java:46)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.lang.reflect.Method.invoke(Method.java:498)\n\tat com.weibo.api.motan.rpc.DefaultProvider.invoke(DefaultProvider.java:57)\n\t... 19 more\ncom.weibo.api.motan.exception.MotanBizException: error_message: provider call process error, status: 503, error_code: 30001,r\n\tat com.weibo.api.motan.rpc.DefaultProvider.invoke(DefaultProvider.java:62)\n\tat com.weibo.api.motan.rpc.AbstractProvider.call(AbstractProvider.java:47)\n\tat com.weibo.api.motan.filter.opentracing.OpenTracingFilter.process(OpenTracingFilter.java:94)\n\tat com.weibo.api.motan.filter.opentracing.OpenTracingFilter.processProviderTrace(OpenTracingFilter.java:148)\n\tat com.weibo.api.motan.filter.opentracing.OpenTracingFilter.filter(OpenTracingFilter.java:58)\n\tat com.weibo.api.motan.protocol.support.ProtocolFilterDecorator$2.call(ProtocolFilterDecorator.java:150)\n\tat com.weibo.api.motan.transport.ProviderMessageRouter.call$original$doBagGo8(ProviderMessageRouter.java:96)\n\tat com.weibo.api.motan.transport.ProviderMessageRouter.call$original$doBagGo8$accessor$PEWyOMYz(ProviderMessageRouter.java)\n\tat com.weibo.api.motan.transport.ProviderMessageRouter$auxiliary$s7ixnKeK.call(Unknown Source)\n\tat com.a.eye.skywalking.api.plugin.interceptor.enhance.ClassInstanceMethodsInterceptor.intercept(ClassInstanceMethodsInterceptor.java:66)\n\tat com.weibo.api.motan.transport.ProviderMessageRouter.call(ProviderMessageRouter.java)\n\tat com.weibo.api.motan.", + "message": "error_message: provider call process error, status: 503, error_code: 30001,r\u003d0", "special.character": "\'\" \\ /" } }