/*
 * Copyright 2008-present 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;

import org.bson.types.Decimal128;
import org.bson.types.ObjectId;

import static java.lang.String.format;
import static java.util.Arrays.asList;

Abstract base class for BsonReader implementations.
Since:3.0
/** * Abstract base class for BsonReader implementations. * * @since 3.0 */
public abstract class AbstractBsonReader implements BsonReader { private State state; private Context context; private BsonType currentBsonType; private String currentName; private boolean closed;
Initializes a new instance of the BsonReader class.
/** * Initializes a new instance of the BsonReader class. */
protected AbstractBsonReader() { state = State.INITIAL; } @Override public BsonType getCurrentBsonType() { return currentBsonType; } @Override public String getCurrentName() { if (state != State.VALUE) { throwInvalidState("getCurrentName", State.VALUE); } return currentName; }
Sets the type of the current value being read.
Params:
  • newType – the BSON Type.
/** * Sets the type of the current value being read. * * @param newType the BSON Type. */
protected void setCurrentBsonType(final BsonType newType) { currentBsonType = newType; }
Returns:The current state of the reader.
/** * @return The current state of the reader. */
public State getState() { return state; }
Sets the new current state of this reader.
Params:
  • newState – the state to set this reader to.
/** * Sets the new current state of this reader. * * @param newState the state to set this reader to. */
protected void setState(final State newState) { state = newState; }
Sets the field name for the key/value pair being read.
Params:
  • newName – the field name
/** * Sets the field name for the key/value pair being read. * * @param newName the field name */
protected void setCurrentName(final String newName) { currentName = newName; }
Closes the reader.
/** * Closes the reader. */
public void close() { closed = true; }
Return true if the reader has been closed.
Returns:true if closed
/** * Return true if the reader has been closed. * * @return true if closed */
protected boolean isClosed() { return closed; }
Handles the logic to read binary data
Returns:the BsonBinary value
/** * Handles the logic to read binary data * * @return the BsonBinary value */
protected abstract BsonBinary doReadBinaryData();
Handles the logic to peek at the binary subtype.
Returns:the binary subtype
/** * Handles the logic to peek at the binary subtype. * * @return the binary subtype */
protected abstract byte doPeekBinarySubType();
Handles the logic to peek at the binary size.
Returns:the binary size
Since:3.4
/** * Handles the logic to peek at the binary size. * * @return the binary size * @since 3.4 */
protected abstract int doPeekBinarySize();
Handles the logic to read booleans
Returns:the boolean value
/** * Handles the logic to read booleans * * @return the boolean value */
protected abstract boolean doReadBoolean();
Handles the logic to read date time
Returns:the long value
/** * Handles the logic to read date time * * @return the long value */
protected abstract long doReadDateTime();
Handles the logic to read doubles
Returns:the double value
/** * Handles the logic to read doubles * * @return the double value */
protected abstract double doReadDouble();
Handles the logic when reading the end of an array
/** * Handles the logic when reading the end of an array */
protected abstract void doReadEndArray();
Handles the logic when reading the end of a document
/** * Handles the logic when reading the end of a document */
protected abstract void doReadEndDocument();
Handles the logic to read 32 bit ints
Returns:the int value
/** * Handles the logic to read 32 bit ints * * @return the int value */
protected abstract int doReadInt32();
Handles the logic to read 64 bit ints
Returns:the long value
/** * Handles the logic to read 64 bit ints * * @return the long value */
protected abstract long doReadInt64();
Handles the logic to read Decimal128
Returns:the Decimal128 value
Since:3.4
/** * Handles the logic to read Decimal128 * * @return the Decimal128 value * @since 3.4 */
protected abstract Decimal128 doReadDecimal128();
Handles the logic to read Javascript functions
Returns:the String value
/** * Handles the logic to read Javascript functions * * @return the String value */
protected abstract String doReadJavaScript();
Handles the logic to read scoped Javascript functions
Returns:the String value
/** * Handles the logic to read scoped Javascript functions * * @return the String value */
protected abstract String doReadJavaScriptWithScope();
Handles the logic to read a Max key
/** * Handles the logic to read a Max key */
protected abstract void doReadMaxKey();
Handles the logic to read a Min key
/** * Handles the logic to read a Min key */
protected abstract void doReadMinKey();
Handles the logic to read a null value
/** * Handles the logic to read a null value */
protected abstract void doReadNull();
Handles the logic to read an ObjectId
Returns:the ObjectId value
/** * Handles the logic to read an ObjectId * * @return the ObjectId value */
protected abstract ObjectId doReadObjectId();
Handles the logic to read a regular expression
Returns:the BsonRegularExpression value
/** * Handles the logic to read a regular expression * * @return the BsonRegularExpression value */
protected abstract BsonRegularExpression doReadRegularExpression();
Handles the logic to read a DBPointer
Returns:the BsonDbPointer value
/** * Handles the logic to read a DBPointer * * @return the BsonDbPointer value */
protected abstract BsonDbPointer doReadDBPointer();
Handles the logic to read the start of an array
/** * Handles the logic to read the start of an array */
protected abstract void doReadStartArray();
Handles the logic to read the start of a document
/** * Handles the logic to read the start of a document */
protected abstract void doReadStartDocument();
Handles the logic to read a String
Returns:the String value
/** * Handles the logic to read a String * * @return the String value */
protected abstract String doReadString();
Handles the logic to read a Symbol
Returns:the String value
/** * Handles the logic to read a Symbol * * @return the String value */
protected abstract String doReadSymbol();
Handles the logic to read a timestamp
Returns:the BsonTimestamp value
/** * Handles the logic to read a timestamp * * @return the BsonTimestamp value */
protected abstract BsonTimestamp doReadTimestamp();
Handles the logic to read an Undefined value
/** * Handles the logic to read an Undefined value */
protected abstract void doReadUndefined();
Handles any logic required to skip the name (reader must be positioned on a name).
/** * Handles any logic required to skip the name (reader must be positioned on a name). */
protected abstract void doSkipName();
Handles any logic required to skip the value (reader must be positioned on a value).
/** * Handles any logic required to skip the value (reader must be positioned on a value). */
protected abstract void doSkipValue(); @Override public BsonBinary readBinaryData() { checkPreconditions("readBinaryData", BsonType.BINARY); setState(getNextState()); return doReadBinaryData(); } @Override public byte peekBinarySubType() { checkPreconditions("readBinaryData", BsonType.BINARY); return doPeekBinarySubType(); } @Override public int peekBinarySize() { checkPreconditions("readBinaryData", BsonType.BINARY); return doPeekBinarySize(); } @Override public boolean readBoolean() { checkPreconditions("readBoolean", BsonType.BOOLEAN); setState(getNextState()); return doReadBoolean(); } @Override public abstract BsonType readBsonType(); @Override public long readDateTime() { checkPreconditions("readDateTime", BsonType.DATE_TIME); setState(getNextState()); return doReadDateTime(); } @Override public double readDouble() { checkPreconditions("readDouble", BsonType.DOUBLE); setState(getNextState()); return doReadDouble(); } @Override public void readEndArray() { if (isClosed()) { throw new IllegalStateException("BSONBinaryWriter"); } if (getContext().getContextType() != BsonContextType.ARRAY) { throwInvalidContextType("readEndArray", getContext().getContextType(), BsonContextType.ARRAY); } if (getState() == State.TYPE) { readBsonType(); // will set state to EndOfArray if at end of array } if (getState() != State.END_OF_ARRAY) { throwInvalidState("ReadEndArray", State.END_OF_ARRAY); } doReadEndArray(); setStateOnEnd(); } @Override public void readEndDocument() { if (isClosed()) { throw new IllegalStateException("BSONBinaryWriter"); } if (getContext().getContextType() != BsonContextType.DOCUMENT && getContext().getContextType() != BsonContextType.SCOPE_DOCUMENT) { throwInvalidContextType("readEndDocument", getContext().getContextType(), BsonContextType.DOCUMENT, BsonContextType.SCOPE_DOCUMENT); } if (getState() == State.TYPE) { readBsonType(); // will set state to EndOfDocument if at end of document } if (getState() != State.END_OF_DOCUMENT) { throwInvalidState("readEndDocument", State.END_OF_DOCUMENT); } doReadEndDocument(); setStateOnEnd(); } @Override public int readInt32() { checkPreconditions("readInt32", BsonType.INT32); setState(getNextState()); return doReadInt32(); } @Override public long readInt64() { checkPreconditions("readInt64", BsonType.INT64); setState(getNextState()); return doReadInt64(); } @Override public Decimal128 readDecimal128() { checkPreconditions("readDecimal", BsonType.DECIMAL128); setState(getNextState()); return doReadDecimal128(); } @Override public String readJavaScript() { checkPreconditions("readJavaScript", BsonType.JAVASCRIPT); setState(getNextState()); return doReadJavaScript(); } @Override public String readJavaScriptWithScope() { checkPreconditions("readJavaScriptWithScope", BsonType.JAVASCRIPT_WITH_SCOPE); setState(State.SCOPE_DOCUMENT); return doReadJavaScriptWithScope(); } @Override public void readMaxKey() { checkPreconditions("readMaxKey", BsonType.MAX_KEY); setState(getNextState()); doReadMaxKey(); } @Override public void readMinKey() { checkPreconditions("readMinKey", BsonType.MIN_KEY); setState(getNextState()); doReadMinKey(); } @Override public void readNull() { checkPreconditions("readNull", BsonType.NULL); setState(getNextState()); doReadNull(); } @Override public ObjectId readObjectId() { checkPreconditions("readObjectId", BsonType.OBJECT_ID); setState(getNextState()); return doReadObjectId(); } @Override public BsonRegularExpression readRegularExpression() { checkPreconditions("readRegularExpression", BsonType.REGULAR_EXPRESSION); setState(getNextState()); return doReadRegularExpression(); } @Override public BsonDbPointer readDBPointer() { checkPreconditions("readDBPointer", BsonType.DB_POINTER); setState(getNextState()); return doReadDBPointer(); } @Override public void readStartArray() { checkPreconditions("readStartArray", BsonType.ARRAY); doReadStartArray(); setState(State.TYPE); } @Override public void readStartDocument() { checkPreconditions("readStartDocument", BsonType.DOCUMENT); doReadStartDocument(); setState(State.TYPE); } @Override public String readString() { checkPreconditions("readString", BsonType.STRING); setState(getNextState()); return doReadString(); } @Override public String readSymbol() { checkPreconditions("readSymbol", BsonType.SYMBOL); setState(getNextState()); return doReadSymbol(); } @Override public BsonTimestamp readTimestamp() { checkPreconditions("readTimestamp", BsonType.TIMESTAMP); setState(getNextState()); return doReadTimestamp(); } @Override public void readUndefined() { checkPreconditions("readUndefined", BsonType.UNDEFINED); setState(getNextState()); doReadUndefined(); } @Override public void skipName() { if (isClosed()) { throw new IllegalStateException("This instance has been closed"); } if (getState() != State.NAME) { throwInvalidState("skipName", State.NAME); } setState(State.VALUE); doSkipName(); } @Override public void skipValue() { if (isClosed()) { throw new IllegalStateException("BSONBinaryWriter"); } if (getState() != State.VALUE) { throwInvalidState("skipValue", State.VALUE); } doSkipValue(); setState(State.TYPE); } @Override public BsonBinary readBinaryData(final String name) { verifyName(name); return readBinaryData(); } @Override public boolean readBoolean(final String name) { verifyName(name); return readBoolean(); } @Override public long readDateTime(final String name) { verifyName(name); return readDateTime(); } @Override public double readDouble(final String name) { verifyName(name); return readDouble(); } @Override public int readInt32(final String name) { verifyName(name); return readInt32(); } @Override public long readInt64(final String name) { verifyName(name); return readInt64(); } @Override public Decimal128 readDecimal128(final String name) { verifyName(name); return readDecimal128(); } @Override public String readJavaScript(final String name) { verifyName(name); return readJavaScript(); } @Override public String readJavaScriptWithScope(final String name) { verifyName(name); return readJavaScriptWithScope(); } @Override public void readMaxKey(final String name) { verifyName(name); readMaxKey(); } @Override public void readMinKey(final String name) { verifyName(name); readMinKey(); } @Override public String readName() { if (state == State.TYPE) { readBsonType(); } if (state != State.NAME) { throwInvalidState("readName", State.NAME); } state = State.VALUE; return currentName; } @Override public void readName(final String name) { verifyName(name); } @Override public void readNull(final String name) { verifyName(name); readNull(); } @Override public ObjectId readObjectId(final String name) { verifyName(name); return readObjectId(); } @Override public BsonRegularExpression readRegularExpression(final String name) { verifyName(name); return readRegularExpression(); } @Override public BsonDbPointer readDBPointer(final String name) { verifyName(name); return readDBPointer(); } @Override public String readString(final String name) { verifyName(name); return readString(); } @Override public String readSymbol(final String name) { verifyName(name); return readSymbol(); } @Override public BsonTimestamp readTimestamp(final String name) { verifyName(name); return readTimestamp(); } @Override public void readUndefined(final String name) { verifyName(name); readUndefined(); }
Throws an InvalidOperationException when the method called is not valid for the current ContextType.
Params:
  • methodName – The name of the method.
  • actualContextType – The actual ContextType.
  • validContextTypes – The valid ContextTypes.
Throws:
/** * Throws an InvalidOperationException when the method called is not valid for the current ContextType. * * @param methodName The name of the method. * @param actualContextType The actual ContextType. * @param validContextTypes The valid ContextTypes. * @throws BsonInvalidOperationException when the method called is not valid for the current ContextType. */
protected void throwInvalidContextType(final String methodName, final BsonContextType actualContextType, final BsonContextType... validContextTypes) { String validContextTypesString = StringUtils.join(" or ", asList(validContextTypes)); String message = format("%s can only be called when ContextType is %s, not when ContextType is %s.", methodName, validContextTypesString, actualContextType); throw new BsonInvalidOperationException(message); }
Throws an InvalidOperationException when the method called is not valid for the current state.
Params:
  • methodName – The name of the method.
  • validStates – The valid states.
Throws:
/** * Throws an InvalidOperationException when the method called is not valid for the current state. * * @param methodName The name of the method. * @param validStates The valid states. * @throws BsonInvalidOperationException when the method called is not valid for the current state. */
protected void throwInvalidState(final String methodName, final State... validStates) { String validStatesString = StringUtils.join(" or ", asList(validStates)); String message = format("%s can only be called when State is %s, not when State is %s.", methodName, validStatesString, state); throw new BsonInvalidOperationException(message); }
Verifies the current state and BSONType of the reader.
Params:
  • methodName – The name of the method calling this one.
  • requiredBsonType – The required BSON type.
/** * Verifies the current state and BSONType of the reader. * * @param methodName The name of the method calling this one. * @param requiredBsonType The required BSON type. */
protected void verifyBSONType(final String methodName, final BsonType requiredBsonType) { if (state == State.INITIAL || state == State.SCOPE_DOCUMENT || state == State.TYPE) { readBsonType(); } if (state == State.NAME) { // ignore name skipName(); } if (state != State.VALUE) { throwInvalidState(methodName, State.VALUE); } if (currentBsonType != requiredBsonType) { throw new BsonInvalidOperationException(format("%s can only be called when CurrentBSONType is %s, " + "not when CurrentBSONType is %s.", methodName, requiredBsonType, currentBsonType)); } }
Verifies the name of the current element.
Params:
  • expectedName – The expected name.
Throws:
/** * Verifies the name of the current element. * * @param expectedName The expected name. * @throws BsonSerializationException when the name read is not the expected name */
protected void verifyName(final String expectedName) { readBsonType(); String actualName = readName(); if (!actualName.equals(expectedName)) { throw new BsonSerializationException(format("Expected element name to be '%s', not '%s'.", expectedName, actualName)); } }
Ensures any conditions are met before reading commences. Throws exceptions if the conditions are not met.
Params:
  • methodName – the name of the current method, which will indicate the field being read
  • type – the type of this field
/** * Ensures any conditions are met before reading commences. Throws exceptions if the conditions are not met. * * @param methodName the name of the current method, which will indicate the field being read * @param type the type of this field */
protected void checkPreconditions(final String methodName, final BsonType type) { if (isClosed()) { throw new IllegalStateException("BsonWriter is closed"); } verifyBSONType(methodName, type); }
Get the context, which will indicate which state the reader is in, for example which part of a document it's currently reading.
Returns:the context
/** * Get the context, which will indicate which state the reader is in, for example which part of a document it's currently reading. * * @return the context */
protected Context getContext() { return context; }
Set the context, which will indicate which state the reader is in, for example which part of a document it's currently reading.
Params:
  • context – the current context.
/** * Set the context, which will indicate which state the reader is in, for example which part of a document it's currently reading. * * @param context the current context. */
protected void setContext(final Context context) { this.context = context; }
Returns the next State to transition to, based on the Context of this reader.
Returns:the next state
/** * Returns the next {@code State} to transition to, based on the {@link org.bson.AbstractBsonReader.Context} of this reader. * * @return the next state */
protected State getNextState() { switch (context.getContextType()) { case ARRAY: case DOCUMENT: case SCOPE_DOCUMENT: return State.TYPE; case TOP_LEVEL: return State.DONE; default: throw new BSONException(format("Unexpected ContextType %s.", context.getContextType())); } } private void setStateOnEnd() { switch (getContext().getContextType()) { case ARRAY: case DOCUMENT: setState(State.TYPE); break; case TOP_LEVEL: setState(State.DONE); break; default: throw new BSONException(format("Unexpected ContextType %s.", getContext().getContextType())); } } protected class Mark implements BsonReaderMark { private final State state; private final Context parentContext; private final BsonContextType contextType; private final BsonType currentBsonType; private final String currentName; protected Context getParentContext() { return parentContext; } protected BsonContextType getContextType() { return contextType; } protected Mark() { state = AbstractBsonReader.this.state; parentContext = AbstractBsonReader.this.context.parentContext; contextType = AbstractBsonReader.this.context.contextType; currentBsonType = AbstractBsonReader.this.currentBsonType; currentName = AbstractBsonReader.this.currentName; } public void reset() { AbstractBsonReader.this.state = state; AbstractBsonReader.this.currentBsonType = currentBsonType; AbstractBsonReader.this.currentName = currentName; } }
The context for the reader. Records the parent context, creating a bread crumb trail to trace back up to the root context of the reader. Also records the BsonContextType, indicating whether the reader is reading a document, array, or other complex sub-structure.
/** * The context for the reader. Records the parent context, creating a bread crumb trail to trace back up to the root context of the * reader. Also records the {@link org.bson.BsonContextType}, indicating whether the reader is reading a document, array, or other * complex sub-structure. */
protected abstract class Context { private final Context parentContext; private final BsonContextType contextType;
Creates a new instance.
Params:
  • parentContext – a possibly null value for the context that came before this one
  • contextType – the type of this context
/** * Creates a new instance. * * @param parentContext a possibly null value for the context that came before this one * @param contextType the type of this context */
protected Context(final Context parentContext, final BsonContextType contextType) { this.parentContext = parentContext; this.contextType = contextType; }
Returns the parent context. Allows users of this context object to transition to this parent context.
Returns:the context that came before this one
/** * Returns the parent context. Allows users of this context object to transition to this parent context. * * @return the context that came before this one */
protected Context getParentContext() { return parentContext; }
Return the type of this context.
Returns:the context type.
/** * Return the type of this context. * * @return the context type. */
protected BsonContextType getContextType() { return contextType; } }
The state of a reader. Indicates where in a document the reader is.
/** * The state of a reader. Indicates where in a document the reader is. */
public enum State {
The initial state.
/** * The initial state. */
INITIAL,
The reader is positioned at the type of an element or value.
/** * The reader is positioned at the type of an element or value. */
TYPE,
The reader is positioned at the name of an element.
/** * The reader is positioned at the name of an element. */
NAME,
The reader is positioned at a value.
/** * The reader is positioned at a value. */
VALUE,
The reader is positioned at a scope document.
/** * The reader is positioned at a scope document. */
SCOPE_DOCUMENT,
The reader is positioned at the end of a document.
/** * The reader is positioned at the end of a document. */
END_OF_DOCUMENT,
The reader is positioned at the end of an array.
/** * The reader is positioned at the end of an array. */
END_OF_ARRAY,
The reader has finished reading a document.
/** * The reader has finished reading a document. */
DONE,
The reader is closed.
/** * The reader is closed. */
CLOSED } }