bson/src/main/org/bson/AbstractBsonWriter.java
protected void throwInvalidState(final String methodName, final State... validStates) {
        if (state == State.INITIAL || state == State.SCOPE_DOCUMENT || state == State.DONE) {
            if (!methodName.startsWith("end") && !methodName.equals("writeName")) { // NOPMD
                //NOPMD collapsing these if statements will not aid readability
                String typeName = methodName.substring(5);
                if (typeName.startsWith("start")) {
                    typeName = typeName.substring(5);
                }
                String article = "A";
                if (Arrays.asList('A', 'E', 'I', 'O', 'U').contains(typeName.charAt(0))) {
                    article = "An";
                }
                throw new BsonInvalidOperationException(format("%s %s value cannot be written to the root level of a BSON document.",
                                                               article, typeName));
            }
        }

        String validStatesString = StringUtils.join(" or ", Arrays.asList(validStates));
        throw new BsonInvalidOperationException(format("%s can only be called when State is %s, not when State is %s",
                                                       methodName, validStatesString, state));
    }
protected void throwInvalidState(final String methodName, final State... validStates) {
        if (state == State.INITIAL || state == State.SCOPE_DOCUMENT || state == State.DONE) {
            if (!methodName.startsWith("end") && !methodName.equals("writeName")) { // NOPMD
                //NOPMD collapsing these if statements will not aid readability
                String typeName = methodName.substring(5);
                if (typeName.startsWith("start")) {
                    typeName = typeName.substring(5);
                }
                String article = "A";
                if (Arrays.asList('A', 'E', 'I', 'O', 'U').contains(typeName.charAt(0))) {
                    article = "An";
                }
                throw new BsonInvalidOperationException(format("%s %s value cannot be written to the root level of a BSON document.",
                                                               article, typeName));
            }
        }

        String validStatesString = StringUtils.join(" or ", Arrays.asList(validStates));
        throw new BsonInvalidOperationException(format("%s can only be called when State is %s, not when State is %s",
                                                       methodName, validStatesString, state));
    }
Throws a {@link BsonInvalidOperationException} 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.