All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bson.json.JsonReader Maven / Gradle / Ivy

Go to download

The MongoDB Java Driver uber-artifact, containing mongodb-driver, mongodb-driver-core, and bson

The newest version!
/*
 * Copyright (c) 2008-2014 MongoDB, Inc.
 *
 * Licensed 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.bson.json;


import org.bson.AbstractBsonReader;
import org.bson.BSONException;
import org.bson.BsonBinary;
import org.bson.BsonBinarySubType;
import org.bson.BsonContextType;
import org.bson.BsonDbPointer;
import org.bson.BsonInvalidOperationException;
import org.bson.BsonRegularExpression;
import org.bson.BsonTimestamp;
import org.bson.BsonType;
import org.bson.BsonUndefined;
import org.bson.types.MaxKey;
import org.bson.types.MinKey;
import org.bson.types.ObjectId;

import javax.xml.bind.DatatypeConverter;
import java.text.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;


/**
 * Reads a JSON in one of the following modes:
 * 
    *
  • Strict mode that conforms to the JSON RFC specifications.
  • *
  • JavaScript mode that that most JavaScript interpreters can process
  • *
  • Shell mode that the mongo shell can process. * This is also called "extended" JavaScript format.
  • *
* For more information about this modes please see * * http://docs.mongodb.org/manual/reference/mongodb-extended-json/ * * * @since 3.0 */ public class JsonReader extends AbstractBsonReader { private final JsonScanner scanner; private JsonToken pushedToken; private Object currentValue; private Mark mark; /** * Constructs a new instance with the given JSON string. * * @param json A string representation of a JSON. */ public JsonReader(final String json) { super(); scanner = new JsonScanner(json); setContext(new Context(null, BsonContextType.TOP_LEVEL)); } @Override protected BsonBinary doReadBinaryData() { return (BsonBinary) currentValue; } @Override protected byte doPeekBinarySubType() { return doReadBinaryData().getType(); } @Override protected boolean doReadBoolean() { return (Boolean) currentValue; } //CHECKSTYLE:OFF @Override public BsonType readBsonType() { if (isClosed()) { throw new IllegalStateException("This instance has been closed"); } if (getState() == State.INITIAL || getState() == State.DONE || getState() == State.SCOPE_DOCUMENT) { // in JSON the top level value can be of any type so fall through setState(State.TYPE); } if (getState() != State.TYPE) { throwInvalidState("readBSONType", State.TYPE); } if (getContext().getContextType() == BsonContextType.DOCUMENT) { JsonToken nameToken = popToken(); switch (nameToken.getType()) { case STRING: case UNQUOTED_STRING: setCurrentName(nameToken.getValue(String.class)); break; case END_OBJECT: setState(State.END_OF_DOCUMENT); return BsonType.END_OF_DOCUMENT; default: throw new JsonParseException("JSON reader was expecting a name but found '%s'.", nameToken.getValue()); } JsonToken colonToken = popToken(); if (colonToken.getType() != JsonTokenType.COLON) { throw new JsonParseException("JSON reader was expecting ':' but found '%s'.", colonToken.getValue()); } } JsonToken token = popToken(); if (getContext().getContextType() == BsonContextType.ARRAY && token.getType() == JsonTokenType.END_ARRAY) { setState(State.END_OF_ARRAY); return BsonType.END_OF_DOCUMENT; } boolean noValueFound = false; switch (token.getType()) { case BEGIN_ARRAY: setCurrentBsonType(BsonType.ARRAY); break; case BEGIN_OBJECT: visitExtendedJSON(); break; case DOUBLE: setCurrentBsonType(BsonType.DOUBLE); currentValue = token.getValue(); break; case END_OF_FILE: setCurrentBsonType(BsonType.END_OF_DOCUMENT); break; case INT32: setCurrentBsonType(BsonType.INT32); currentValue = token.getValue(); break; case INT64: setCurrentBsonType(BsonType.INT64); currentValue = token.getValue(); break; case REGULAR_EXPRESSION: setCurrentBsonType(BsonType.REGULAR_EXPRESSION); currentValue = token.getValue(); break; case STRING: setCurrentBsonType(BsonType.STRING); currentValue = token.getValue(); break; case UNQUOTED_STRING: String value = token.getValue(String.class); if ("false".equals(value) || "true".equals(value)) { setCurrentBsonType(BsonType.BOOLEAN); currentValue = Boolean.parseBoolean(value); } else if ("Infinity".equals(value)) { setCurrentBsonType(BsonType.DOUBLE); currentValue = Double.POSITIVE_INFINITY; } else if ("NaN".equals(value)) { setCurrentBsonType(BsonType.DOUBLE); currentValue = Double.NaN; } else if ("null".equals(value)) { setCurrentBsonType(BsonType.NULL); } else if ("undefined".equals(value)) { setCurrentBsonType(BsonType.UNDEFINED); } else if ("BinData".equals(value)) { setCurrentBsonType(BsonType.BINARY); currentValue = visitBinDataConstructor(); } else if ("Date".equals(value)) { setCurrentBsonType(BsonType.DATE_TIME); currentValue = visitDateTimeConstructor(); // withNew = false } else if ("HexData".equals(value)) { setCurrentBsonType(BsonType.BINARY); currentValue = visitHexDataConstructor(); } else if ("ISODate".equals(value)) { setCurrentBsonType(BsonType.DATE_TIME); currentValue = visitISODateTimeConstructor(); } else if ("NumberLong".equals(value)) { setCurrentBsonType(BsonType.INT64); currentValue = visitNumberLongConstructor(); } else if ("ObjectId".equals(value)) { setCurrentBsonType(BsonType.OBJECT_ID); currentValue = visitObjectIdConstructor(); } else if ("Timestamp".equals(value)) { setCurrentBsonType(BsonType.TIMESTAMP); currentValue = visitTimestampConstructor(); } else if ("RegExp".equals(value)) { setCurrentBsonType(BsonType.REGULAR_EXPRESSION); currentValue = visitRegularExpressionConstructor(); } else if ("DBPointer".equals(value)) { setCurrentBsonType(BsonType.DB_POINTER); currentValue = visitDBPointerConstructor(); } else if ("UUID".equals(value) || "GUID".equals(value) || "CSUUID".equals(value) || "CSGUID".equals(value) || "JUUID".equals(value) || "JGUID".equals(value) || "PYUUID".equals(value) || "PYGUID".equals(value)) { setCurrentBsonType(BsonType.BINARY); currentValue = visitUUIDConstructor(value); } else if ("new".equals(value)) { visitNew(); } else { noValueFound = true; } break; default: noValueFound = true; break; } if (noValueFound) { throw new JsonParseException("JSON reader was expecting a value but found '%s'.", token.getValue()); } if (getContext().getContextType() == BsonContextType.ARRAY || getContext().getContextType() == BsonContextType.DOCUMENT) { JsonToken commaToken = popToken(); if (commaToken.getType() != JsonTokenType.COMMA) { pushToken(commaToken); } } switch (getContext().getContextType()) { case DOCUMENT: case SCOPE_DOCUMENT: default: setState(State.NAME); break; case ARRAY: case JAVASCRIPT_WITH_SCOPE: case TOP_LEVEL: setState(State.VALUE); break; } return getCurrentBsonType(); } //CHECKSTYLE:ON @Override protected long doReadDateTime() { return (Long) currentValue; } @Override protected double doReadDouble() { return (Double) currentValue; } @Override protected void doReadEndArray() { setContext(getContext().getParentContext()); if (getContext().getContextType() == BsonContextType.ARRAY || getContext().getContextType() == BsonContextType.DOCUMENT) { JsonToken commaToken = popToken(); if (commaToken.getType() != JsonTokenType.COMMA) { pushToken(commaToken); } } } private void setStateOnEnd() { switch (getContext().getContextType()) { case ARRAY: case DOCUMENT: setState(State.TYPE); break; case TOP_LEVEL: setState(State.DONE); break; default: throw new JsonParseException("Unexpected ContextType %s.", getContext().getContextType()); } } @Override protected void doReadEndDocument() { setContext(getContext().getParentContext()); if (getContext() != null && getContext().getContextType() == BsonContextType.SCOPE_DOCUMENT) { setContext(getContext().getParentContext()); // JavaScriptWithScope verifyToken("}"); // outermost closing bracket for JavaScriptWithScope } if (getContext() == null) { throw new JsonParseException("Unexpected end of document."); } if (getContext().getContextType() == BsonContextType.ARRAY || getContext().getContextType() == BsonContextType.DOCUMENT) { JsonToken commaToken = popToken(); if (commaToken.getType() != JsonTokenType.COMMA) { pushToken(commaToken); } } } @Override protected int doReadInt32() { return (Integer) currentValue; } @Override protected long doReadInt64() { return (Long) currentValue; } @Override protected String doReadJavaScript() { return (String) currentValue; } @Override protected String doReadJavaScriptWithScope() { return (String) currentValue; } @Override protected void doReadMaxKey() { } @Override protected void doReadMinKey() { } @Override protected void doReadNull() { } @Override protected ObjectId doReadObjectId() { return (ObjectId) currentValue; } @Override protected BsonRegularExpression doReadRegularExpression() { return (BsonRegularExpression) currentValue; } @Override protected BsonDbPointer doReadDBPointer() { return (BsonDbPointer) currentValue; } @Override protected void doReadStartArray() { setContext(new Context(getContext(), BsonContextType.ARRAY)); } @Override protected void doReadStartDocument() { setContext(new Context(getContext(), BsonContextType.DOCUMENT)); } @Override protected String doReadString() { return (String) currentValue; } @Override protected String doReadSymbol() { return (String) currentValue; } @Override protected BsonTimestamp doReadTimestamp() { return (BsonTimestamp) currentValue; } @Override protected void doReadUndefined() { } @Override protected void doSkipName() { } @Override protected void doSkipValue() { switch (getCurrentBsonType()) { case ARRAY: readStartArray(); while (readBsonType() != BsonType.END_OF_DOCUMENT) { skipValue(); } readEndArray(); break; case BINARY: readBinaryData(); break; case BOOLEAN: readBoolean(); break; case DATE_TIME: readDateTime(); break; case DOCUMENT: readStartDocument(); while (readBsonType() != BsonType.END_OF_DOCUMENT) { skipName(); skipValue(); } readEndDocument(); break; case DOUBLE: readDouble(); break; case INT32: readInt32(); break; case INT64: readInt64(); break; case JAVASCRIPT: readJavaScript(); break; case JAVASCRIPT_WITH_SCOPE: readJavaScriptWithScope(); readStartDocument(); while (readBsonType() != BsonType.END_OF_DOCUMENT) { skipName(); skipValue(); } readEndDocument(); break; case MAX_KEY: readMaxKey(); break; case MIN_KEY: readMinKey(); break; case NULL: readNull(); break; case OBJECT_ID: readObjectId(); break; case REGULAR_EXPRESSION: readRegularExpression(); break; case STRING: readString(); break; case SYMBOL: readSymbol(); break; case TIMESTAMP: readTimestamp(); break; case UNDEFINED: readUndefined(); break; default: } } private JsonToken popToken() { if (pushedToken != null) { JsonToken token = pushedToken; pushedToken = null; return token; } else { return scanner.nextToken(); } } private void pushToken(final JsonToken token) { if (pushedToken == null) { pushedToken = token; } else { throw new BsonInvalidOperationException("There is already a pending token."); } } private void verifyToken(final Object expected) { if (expected == null) { throw new IllegalArgumentException("Can't be null"); } JsonToken token = popToken(); if (!expected.equals(token.getValue())) { throw new JsonParseException("JSON reader expected '%s' but found '%s'.", expected, token.getValue()); } } private void verifyString(final String expected) { if (expected == null) { throw new IllegalArgumentException("Can't be null"); } JsonToken token = popToken(); JsonTokenType type = token.getType(); if ((type != JsonTokenType.STRING && type != JsonTokenType.UNQUOTED_STRING) && !expected.equals(token.getValue())) { throw new JsonParseException("JSON reader expected '%s' but found '%s'.", expected, token.getValue()); } } private void visitNew() { JsonToken typeToken = popToken(); if (typeToken.getType() != JsonTokenType.UNQUOTED_STRING) { throw new JsonParseException("JSON reader expected a type name but found '%s'.", typeToken.getValue()); } String value = typeToken.getValue(String.class); if ("BinData".equals(value)) { currentValue = visitBinDataConstructor(); setCurrentBsonType(BsonType.BINARY); } else if ("Date".equals(value)) { currentValue = visitDateTimeConstructor(); setCurrentBsonType(BsonType.DATE_TIME); } else if ("HexData".equals(value)) { currentValue = visitHexDataConstructor(); setCurrentBsonType(BsonType.BINARY); } else if ("ISODate".equals(value)) { currentValue = visitISODateTimeConstructor(); setCurrentBsonType(BsonType.DATE_TIME); } else if ("NumberLong".equals(value)) { currentValue = visitNumberLongConstructor(); setCurrentBsonType(BsonType.INT64); } else if ("ObjectId".equals(value)) { currentValue = visitObjectIdConstructor(); setCurrentBsonType(BsonType.OBJECT_ID); } else if ("RegExp".equals(value)) { currentValue = visitRegularExpressionConstructor(); setCurrentBsonType(BsonType.REGULAR_EXPRESSION); } else if ("DBPointer".equals(value)) { currentValue = visitDBPointerConstructor(); setCurrentBsonType(BsonType.DB_POINTER); } else if ("UUID".equals(value) || "GUID".equals(value) || "CSUUID".equals(value) || "CSGUID".equals(value) || "JUUID".equals(value) || "JGUID".equals(value) || "PYUUID".equals(value) || "PYGUID".equals(value)) { currentValue = visitUUIDConstructor(value); setCurrentBsonType(BsonType.BINARY); } else { throw new JsonParseException("JSON reader expected a type name but found '%s'.", value); } } private void visitExtendedJSON() { JsonToken nameToken = popToken(); String value = nameToken.getValue(String.class); JsonTokenType type = nameToken.getType(); if (type == JsonTokenType.STRING || type == JsonTokenType.UNQUOTED_STRING) { if ("$binary".equals(value)) { currentValue = visitBinDataExtendedJson(); setCurrentBsonType(BsonType.BINARY); return; } else if ("$code".equals(value)) { visitJavaScriptExtendedJson(); return; } else if ("$date".equals(value)) { currentValue = visitDateTimeExtendedJson(); setCurrentBsonType(BsonType.DATE_TIME); return; } else if ("$maxKey".equals(value)) { currentValue = visitMaxKeyExtendedJson(); setCurrentBsonType(BsonType.MAX_KEY); return; } else if ("$minKey".equals(value)) { currentValue = visitMinKeyExtendedJson(); setCurrentBsonType(BsonType.MIN_KEY); return; } else if ("$oid".equals(value)) { currentValue = visitObjectIdExtendedJson(); setCurrentBsonType(BsonType.OBJECT_ID); return; } else if ("$regex".equals(value)) { currentValue = visitRegularExpressionExtendedJson(); setCurrentBsonType(BsonType.REGULAR_EXPRESSION); return; } else if ("$symbol".equals(value)) { currentValue = visitSymbolExtendedJson(); setCurrentBsonType(BsonType.SYMBOL); return; } else if ("$timestamp".equals(value)) { currentValue = visitTimestampExtendedJson(); setCurrentBsonType(BsonType.TIMESTAMP); return; } else if ("$undefined".equals(value)) { currentValue = visitUndefinedExtendedJson(); setCurrentBsonType(BsonType.UNDEFINED); return; } else if ("$numberLong".equals(value)) { currentValue = visitNumberLongExtendedJson(); setCurrentBsonType(BsonType.INT64); return; } } pushToken(nameToken); setCurrentBsonType(BsonType.DOCUMENT); } private BsonBinary visitBinDataConstructor() { verifyToken("("); JsonToken subTypeToken = popToken(); if (subTypeToken.getType() != JsonTokenType.INT32) { throw new JsonParseException("JSON reader expected a binary subtype but found '%s'.", subTypeToken.getValue()); } verifyToken(","); JsonToken bytesToken = popToken(); if (bytesToken.getType() != JsonTokenType.UNQUOTED_STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", bytesToken.getValue()); } verifyToken(")"); byte[] bytes = DatatypeConverter.parseBase64Binary(bytesToken.getValue(String.class)); return new BsonBinary(subTypeToken.getValue(Integer.class).byteValue(), bytes); } private BsonBinary visitUUIDConstructor(final String uuidConstructorName) { //TODO verify information related to https://jira.mongodb.org/browse/SERVER-3168 verifyToken("("); JsonToken bytesToken = popToken(); if (bytesToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", bytesToken.getValue()); } verifyToken(")"); String hexString = bytesToken.getValue(String.class).replaceAll("\\{", "").replaceAll("\\}", "").replaceAll("-", ""); byte[] bytes = DatatypeConverter.parseHexBinary(hexString); BsonBinarySubType subType = BsonBinarySubType.UUID_STANDARD; if (!"UUID".equals(uuidConstructorName) || !"GUID".equals(uuidConstructorName)) { subType = BsonBinarySubType.UUID_LEGACY; } return new BsonBinary(subType, bytes); } private BsonRegularExpression visitRegularExpressionConstructor() { verifyToken("("); JsonToken patternToken = popToken(); if (patternToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", patternToken.getValue()); } String options = ""; JsonToken commaToken = popToken(); if (commaToken.getType() == JsonTokenType.COMMA) { JsonToken optionsToken = popToken(); if (optionsToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", optionsToken.getValue()); } options = optionsToken.getValue(String.class); } else { pushToken(commaToken); } verifyToken(")"); return new BsonRegularExpression(patternToken.getValue(String.class), options); } private ObjectId visitObjectIdConstructor() { verifyToken("("); JsonToken valueToken = popToken(); if (valueToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", valueToken.getValue()); } verifyToken(")"); return new ObjectId(valueToken.getValue(String.class)); } private BsonTimestamp visitTimestampConstructor() { verifyToken("("); JsonToken timeToken = popToken(); int time; if (timeToken.getType() != JsonTokenType.INT32) { throw new JsonParseException("JSON reader expected an integer but found '%s'.", timeToken.getValue()); } else { time = timeToken.getValue(Integer.class); } verifyToken(","); JsonToken incrementToken = popToken(); int increment; if (incrementToken.getType() != JsonTokenType.INT32) { throw new JsonParseException("JSON reader expected an integer but found '%s'.", timeToken.getValue()); } else { increment = incrementToken.getValue(Integer.class); } verifyToken(")"); return new BsonTimestamp(time, increment); } private BsonDbPointer visitDBPointerConstructor() { verifyToken("("); JsonToken namespaceToken = popToken(); if (namespaceToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", namespaceToken.getValue()); } verifyToken(","); JsonToken idToken = popToken(); if (namespaceToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", idToken.getValue()); } verifyToken(")"); return new BsonDbPointer(namespaceToken.getValue(String.class), new ObjectId(idToken.getValue(String.class))); } private long visitNumberLongConstructor() { verifyToken("("); JsonToken valueToken = popToken(); long value; if (valueToken.getType() == JsonTokenType.INT32 || valueToken.getType() == JsonTokenType.INT64) { value = valueToken.getValue(Long.class); } else if (valueToken.getType() == JsonTokenType.STRING) { value = Long.parseLong(valueToken.getValue(String.class)); } else { throw new JsonParseException("JSON reader expected an integer or a string but found '%s'.", valueToken.getValue()); } verifyToken(")"); return value; } private long visitISODateTimeConstructor() { verifyToken("("); JsonToken valueToken = popToken(); if (valueToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", valueToken.getValue()); } verifyToken(")"); String[] patterns = {"yyyy-MM-dd", "yyyy-MM-dd'T'HH:mm:ssz", "yyyy-MM-dd'T'HH:mm:ss.SSSz"}; SimpleDateFormat format = new SimpleDateFormat(patterns[0], Locale.ENGLISH); ParsePosition pos = new ParsePosition(0); String s = valueToken.getValue(String.class); if (s.endsWith("Z")) { s = s.substring(0, s.length() - 1) + "GMT-00:00"; } for (final String pattern : patterns) { format.applyPattern(pattern); format.setLenient(true); pos.setIndex(0); Date date = format.parse(s, pos); if (date != null && pos.getIndex() == s.length()) { return date.getTime(); } } throw new JsonParseException("Invalid date format."); } private BsonBinary visitHexDataConstructor() { verifyToken("("); JsonToken subTypeToken = popToken(); if (subTypeToken.getType() != JsonTokenType.INT32) { throw new JsonParseException("JSON reader expected a binary subtype but found '%s'.", subTypeToken.getValue()); } verifyToken(","); JsonToken bytesToken = popToken(); if (bytesToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", bytesToken.getValue()); } verifyToken(")"); String hex = bytesToken.getValue(String.class); if ((hex.length() & 1) != 0) { hex = "0" + hex; } for (final BsonBinarySubType subType : BsonBinarySubType.values()) { if (subType.getValue() == subTypeToken.getValue(Integer.class)) { return new BsonBinary(subType, DatatypeConverter.parseHexBinary(hex)); } } return new BsonBinary(DatatypeConverter.parseHexBinary(hex)); } private long visitDateTimeConstructor() { DateFormat format = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss z", Locale.ENGLISH); verifyToken("("); JsonToken token = popToken(); if (token.getType() == JsonTokenType.RIGHT_PAREN) { return new Date().getTime(); } else if (token.getType() == JsonTokenType.STRING) { verifyToken(")"); String s = token.getValue(String.class); ParsePosition pos = new ParsePosition(0); Date dateTime = format.parse(s, pos); if (dateTime != null && pos.getIndex() == s.length()) { return dateTime.getTime(); } else { throw new JsonParseException("JSON reader expected a date in 'EEE MMM dd yyyy HH:mm:ss z' format but found '%s'.", s); } } else if (token.getType() == JsonTokenType.INT32 || token.getType() == JsonTokenType.INT64) { long[] values = new long[7]; int pos = 0; while (true) { if (pos < values.length) { values[pos++] = token.getValue(Long.class); } token = popToken(); if (token.getType() == JsonTokenType.RIGHT_PAREN) { break; } if (token.getType() != JsonTokenType.COMMA) { throw new JsonParseException("JSON reader expected a ',' or a ')' but found '%s'.", token.getValue()); } token = popToken(); if (token.getType() != JsonTokenType.INT32 && token.getType() != JsonTokenType.INT64) { throw new JsonParseException("JSON reader expected an integer but found '%s'.", token.getValue()); } } if (pos == 1) { return values[0]; } else if (pos < 3 || pos > 7) { throw new JsonParseException("JSON reader expected 1 or 3-7 integers but found %d.", pos); } Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); calendar.set(Calendar.YEAR, (int) values[0]); calendar.set(Calendar.MONTH, (int) values[1]); calendar.set(Calendar.DAY_OF_MONTH, (int) values[2]); calendar.set(Calendar.HOUR_OF_DAY, (int) values[3]); calendar.set(Calendar.MINUTE, (int) values[4]); calendar.set(Calendar.SECOND, (int) values[5]); calendar.set(Calendar.MILLISECOND, (int) values[6]); return calendar.getTimeInMillis(); } else { throw new JsonParseException("JSON reader expected an integer or a string but found '%s'.", token.getValue()); } } private BsonBinary visitBinDataExtendedJson() { verifyToken(":"); JsonToken bytesToken = popToken(); if (bytesToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", bytesToken.getValue()); } verifyToken(","); verifyString("$type"); verifyToken(":"); JsonToken subTypeToken = popToken(); if (subTypeToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", subTypeToken.getValue()); } verifyToken("}"); byte subType = (byte) Integer.parseInt(subTypeToken.getValue(String.class), 16); for (final BsonBinarySubType st : BsonBinarySubType.values()) { if (st.getValue() == subType) { return new BsonBinary(st, DatatypeConverter.parseBase64Binary(bytesToken.getValue(String.class))); } } return new BsonBinary(DatatypeConverter.parseBase64Binary(bytesToken.getValue(String.class))); } private long visitDateTimeExtendedJson() { verifyToken(":"); JsonToken valueToken = popToken(); verifyToken("}"); if (valueToken.getType() == JsonTokenType.INT32 || valueToken.getType() == JsonTokenType.INT64) { return valueToken.getValue(Long.class); } else if (valueToken.getType() == JsonTokenType.STRING) { String dateTimeString = valueToken.getValue(String.class); try { return DatatypeConverter.parseDateTime(dateTimeString).getTimeInMillis(); } catch (IllegalArgumentException e) { throw new JsonParseException("JSON reader expected an ISO-8601 date time string but found.", dateTimeString); } } else { throw new JsonParseException("JSON reader expected an integer or string but found '%s'.", valueToken.getValue()); } } private MaxKey visitMaxKeyExtendedJson() { verifyToken(":"); verifyToken(1); verifyToken("}"); return new MaxKey(); } private MinKey visitMinKeyExtendedJson() { verifyToken(":"); verifyToken(1); verifyToken("}"); return new MinKey(); } private ObjectId visitObjectIdExtendedJson() { verifyToken(":"); JsonToken valueToken = popToken(); if (valueToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", valueToken.getValue()); } verifyToken("}"); return new ObjectId(valueToken.getValue(String.class)); } private BsonRegularExpression visitRegularExpressionExtendedJson() { verifyToken(":"); JsonToken patternToken = popToken(); if (patternToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", patternToken.getValue()); } String options = ""; JsonToken commaToken = popToken(); if (commaToken.getType() == JsonTokenType.COMMA) { verifyString("$options"); verifyToken(":"); JsonToken optionsToken = popToken(); if (optionsToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", optionsToken.getValue()); } options = optionsToken.getValue(String.class); } else { pushToken(commaToken); } verifyToken("}"); return new BsonRegularExpression(patternToken.getValue(String.class), options); } private String visitSymbolExtendedJson() { verifyToken(":"); JsonToken nameToken = popToken(); if (nameToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", nameToken.getValue()); } verifyToken("}"); return nameToken.getValue(String.class); } private BsonTimestamp visitTimestampExtendedJson() { verifyToken(":"); verifyToken("{"); verifyString("t"); verifyToken(":"); JsonToken timeToken = popToken(); int time; if (timeToken.getType() == JsonTokenType.INT32) { time = timeToken.getValue(Integer.class); } else { throw new JsonParseException("JSON reader expected an integer but found '%s'.", timeToken.getValue()); } verifyToken(","); verifyString("i"); verifyToken(":"); JsonToken incrementToken = popToken(); int increment; if (incrementToken.getType() == JsonTokenType.INT32) { increment = incrementToken.getValue(Integer.class); } else { throw new JsonParseException("JSON reader expected an integer but found '%s'.", timeToken.getValue()); } verifyToken("}"); verifyToken("}"); return new BsonTimestamp(time, increment); } private void visitJavaScriptExtendedJson() { verifyToken(":"); JsonToken codeToken = popToken(); if (codeToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", codeToken.getValue()); } JsonToken nextToken = popToken(); switch (nextToken.getType()) { case COMMA: verifyString("$scope"); verifyToken(":"); setState(State.VALUE); currentValue = codeToken.getValue(); setCurrentBsonType(BsonType.JAVASCRIPT_WITH_SCOPE); setContext(new Context(getContext(), BsonContextType.SCOPE_DOCUMENT)); break; case END_OBJECT: currentValue = codeToken.getValue(); setCurrentBsonType(BsonType.JAVASCRIPT); break; default: throw new JsonParseException("JSON reader expected ',' or '}' but found '%s'.", codeToken.getValue()); } } private BsonUndefined visitUndefinedExtendedJson() { verifyToken(":"); JsonToken nameToken = popToken(); if (!nameToken.getValue(String.class).equals("true")) { throw new JsonParseException("JSON reader requires $undefined to have the value of true but found '%s'.", nameToken.getValue()); } verifyToken("}"); return new BsonUndefined(); } private Long visitNumberLongExtendedJson() { verifyToken(":"); JsonToken nameToken = popToken(); if (nameToken.getType() != JsonTokenType.STRING) { throw new JsonParseException("JSON reader expected a string but found '%s'.", nameToken.getValue()); } verifyToken("}"); return nameToken.getValue(Long.class); } @Override public void mark() { if (mark != null) { throw new BSONException("A mark already exists; it needs to be reset before creating a new one"); } mark = new Mark(); } @Override public void reset() { if (mark == null) { throw new BSONException("trying to reset a mark before creating it"); } mark.reset(); mark = null; } @Override protected Context getContext() { return (Context) super.getContext(); } protected class Mark extends AbstractBsonReader.Mark { private JsonToken pushedToken; private Object currentValue; private int position; protected Mark() { super(); pushedToken = JsonReader.this.pushedToken; currentValue = JsonReader.this.currentValue; position = JsonReader.this.scanner.getBufferPosition(); } protected void reset() { super.reset(); JsonReader.this.pushedToken = pushedToken; JsonReader.this.currentValue = currentValue; JsonReader.this.scanner.setBufferPosition(position); JsonReader.this.setContext(new Context(getParentContext(), getContextType())); } } protected class Context extends AbstractBsonReader.Context { protected Context(final AbstractBsonReader.Context parentContext, final BsonContextType contextType) { super(parentContext, contextType); } protected Context getParentContext() { return (Context) super.getParentContext(); } protected BsonContextType getContextType() { return super.getContextType(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy