private JsonToken nextInObject(boolean firstElement) throws IOException { /* * Read delimiters. Either a comma/semicolon separating this and the * previous name-value pair, or a close brace to denote the end of the * object. */ if (firstElement) { /* Peek to see if this is the empty object. */ switch (nextNonWhitespace()) { case '}': pop(); return token = JsonToken.END_OBJECT; default: pos--; } } else { switch (nextNonWhitespace()) { case '}': pop(); return token = JsonToken.END_OBJECT; case ';': case ',': break; default: throw syntaxError("Unterminated object"); } } /* Read the name. */ int quote = nextNonWhitespace(); switch (quote) { case '\'': checkLenient(); // fall-through case '"': name = nextString((char) quote); break; default: checkLenient(); pos--; name = nextLiteral(false); if (name.isEmpty()) { throw syntaxError("Expected name"); } } replaceTop(JsonScope.DANGLING_NAME); return token = JsonToken.NAME; }
private JsonToken objectValue() throws IOException { /* * Read the name/value separator. Usually a colon ':'. In lenient mode * we also accept an equals sign '=', or an arrow "=>". */ switch (nextNonWhitespace()) { case ':': break; case '=': checkLenient(); if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') { pos++; } break; default: throw syntaxError("Expected ':'"); } replaceTop(JsonScope.NONEMPTY_OBJECT); return nextValue(); }
/** Returns the type of the next token without consuming it. */ public JsonToken peek() throws IOException { if (token != null) { return token; } switch (peekStack()) { case EMPTY_DOCUMENT: replaceTop(JsonScope.NONEMPTY_DOCUMENT); JsonToken firstToken = nextValue(); if (!lenient && token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) { throw new IOException("Expected JSON document to start with '[' or '{' but was " + token); } return firstToken; case EMPTY_ARRAY: return nextInArray(true); case NONEMPTY_ARRAY: return nextInArray(false); case EMPTY_OBJECT: return nextInObject(true); case DANGLING_NAME: return objectValue(); case NONEMPTY_OBJECT: return nextInObject(false); case NONEMPTY_DOCUMENT: try { JsonToken token = nextValue(); if (lenient) { return token; } throw syntaxError("Expected EOF"); } catch (EOFException e) { return token = JsonToken.END_DOCUMENT; // TODO: avoid throwing here? } case CLOSED: throw new IllegalStateException("JsonReader is closed"); default: throw new AssertionError(); } }
private JsonToken nextInArray(boolean firstElement) throws IOException { if (firstElement) { replaceTop(JsonScope.NONEMPTY_ARRAY); } else { /* Look for a comma before each element after the first element. */ switch (nextNonWhitespace()) { case ']': pop(); return token = JsonToken.END_ARRAY; case ';': checkLenient(); // fall-through case ',': break; default: throw syntaxError("Unterminated array"); } } switch (nextNonWhitespace()) { case ']': if (firstElement) { pop(); return token = JsonToken.END_ARRAY; } // fall-through to handle ",]" case ';': case ',': /* In lenient mode, a 0-length literal means 'null' */ checkLenient(); pos--; value = "null"; return token = JsonToken.NULL; default: pos--; return nextValue(); } }