Merge branch '2.8'
diff --git a/.travis.yml b/.travis.yml
index 75db9cc..73b3221 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,8 +14,8 @@
 branches:
   only:
     - master
+    - "2.8"
     - "2.7"
-    - "2.6"
 
 env:
   global:
diff --git a/README.md b/README.md
index b93f417..413657c 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,7 @@
 
 [![Build Status](https://travis-ci.org/FasterXML/jackson-core.svg?branch=master)](https://travis-ci.org/FasterXML/jackson-core) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.fasterxml.jackson.core/jackson-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.fasterxml.jackson.core/jackson-core)
 [![Javadoc](https://javadoc-emblem.rhcloud.com/doc/com.fasterxml.jackson.core/jackson-core/badge.svg)](http://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-core)
+[![Coverage Status](https://coveralls.io/repos/github/FasterXML/jackson-core/badge.svg?branch=master)](https://coveralls.io/github/FasterXML/jackson-core?branch=master)
 
 # Get it!
 
diff --git a/pom.xml b/pom.xml
index 0869333..53ca4bf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,13 +3,13 @@
   <parent>
     <groupId>com.fasterxml.jackson</groupId>
     <artifactId>jackson-parent</artifactId>
-    <version>2.8</version>
+    <version>2.9-rc1-SNAPSHOT</version>
   </parent>
 
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-core</artifactId>
   <name>Jackson-core</name>
-  <version>2.8.6-SNAPSHOT</version>
+  <version>2.9.0-SNAPSHOT</version>
   <packaging>bundle</packaging>
   <description>Core Jackson abstractions, basic JSON streaming API implementation</description>
   <inceptionYear>2008</inceptionYear>
@@ -23,7 +23,7 @@
   </scm>
 
   <properties>
-    <!-- 29-Apr-2016, tatu: Retain Java6/JDK1.6 compatibility for streaming for Jackson 2.8 -->
+    <!-- 16-Sep-2016, tatu: Retain Java6/JDK1.6 compatibility for streaming for Jackson 2.x -->
     <javac.src.version>1.6</javac.src.version>
     <javac.target.version>1.6</javac.target.version>
 
diff --git a/release-notes/CREDITS b/release-notes/CREDITS
index 4aaca26..fd88262 100644
--- a/release-notes/CREDITS
+++ b/release-notes/CREDITS
@@ -107,3 +107,14 @@
 Kevin Gallardo (newkek@github)
   * Reported #296: JsonParserSequence skips a token on a switched Parser
    (2.8.0)
+
+Alex Yursha (AlexYursha@github)
+  * Contributed #312: Add `JsonProcessingException.clearLocation()` to allow clearing
+    possibly security-sensitive information
+   (2.9.0)
+
+Brad Hess (bdhess@github)
+  * Contributed #323: Add `JsonParser.ALLOW_TRAILING_COMMA` to work for Arrays and Objects
+   (2.9.0)
+  * Reported #325: `DataInput` backed parser should handle `EOFException` at end of doc
+   (2.9.0)
diff --git a/release-notes/VERSION b/release-notes/VERSION
index d902d17..7d53acf 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -17,6 +17,13 @@
 2.9.0 (not yet released)
 
 #304: Optimize `NumberOutput.outputLong()` method
+#312: Add `JsonProcessingException.clearLocation()` to allow clearing
+  possibly security-sensitive information
+ (contributed by Alex Y)
+#323: Add `JsonParser.ALLOW_TRAILING_COMMA` to work for Arrays and Objects
+ (contributed by Brad H)
+#325: `DataInput` backed parser should handle `EOFException` at end of doc
+ (reported by Brad H)
 
 2.8.6 (not yet released)
 
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParser.java b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
index 92f16de..36c7df5 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
@@ -227,7 +227,30 @@
           * 
           * @since 2.8
           */
-         ALLOW_MISSING_VALUES(false)
+         ALLOW_MISSING_VALUES(false),
+
+         /**
+          * Feature that determines whether {@link JsonParser} will allow for a single trailing
+          * comma following the final value (in an Array) or member (in an Object). These commas
+          * will simply be ignored.
+          * <p>
+          * For example, when this feature is enabled, <code>[true,true,]</code> is equivalent to
+          * <code>[true, true]</code> and <code>{"a": true,}</code> is equivalent to
+          * <code>{"a": true}</code>.
+          * <p>
+          * When combined with <code>ALLOW_MISSING_VALUES</code>, this feature takes priority, and
+          * the final trailing comma in an array declaration does not imply a missing
+          * (<code>null</code>) value. For example, when both <code>ALLOW_MISSING_VALUES</code>
+          * and <code>ALLOW_TRAILING_COMMA</code> are enabled, <code>[true,true,]</code> is
+          * equivalent to <code>[true, true]</code>, and <code>[true,true,,]</code> is equivalent to
+          * <code>[true, true, null]</code>.
+          * <p>
+          * Since the JSON specification does not permit trailing commas, this is a non-standard
+          * feature, and as such disabled by default.
+          *
+          * @since 2.9
+          */
+         ALLOW_TRAILING_COMMA(false)
          ;
 
         /**
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonPointer.java b/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
index f927336..6681992 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
@@ -20,6 +20,13 @@
 public class JsonPointer
 {
     /**
+     * Character used to separate segments.
+     *
+     * @since 2.9
+     */
+    public final static char SEPARATOR = '/';
+
+    /**
      * Marker instance used to represent segment that matches current
      * node or position (that is, returns true for
      * {@link #matches()}).
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java b/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java
index 44be053..23599b1 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java
@@ -54,6 +54,15 @@
     public JsonLocation getLocation() { return _location; }
     
     /**
+     * Method that allows to remove context information from this exception's message.
+     * Useful when you are parsing security-sensitive data and don't want original data excerpts
+     * to be present in Jackson parser error messages.
+     *
+     * @since 2.9
+     */
+    public void clearLocation() { _location = null; }
+
+    /**
      * Method that allows accessing the original "message" argument,
      * without additional decorations (like location information)
      * that overridden {@link #getMessage} adds.
diff --git a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
index dc80f62..7033d84 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
@@ -19,6 +19,8 @@
 public class ReaderBasedJsonParser // final in 2.3, earlier
     extends ParserBase
 {
+    protected final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask();
+
     // Latin1 encoding is not supported, but we do use 8-bit subset for
     // pre-processing task, to simplify first pass, keep it fast.
     protected final static int[] _icLatin1 = CharTypes.getInputCodeLatin1();
@@ -443,13 +445,13 @@
     @Override
     public byte[] getBinaryValue(Base64Variant b64variant) throws IOException
     {
-        if (_currToken != JsonToken.VALUE_STRING &&
-                (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT || _binaryValue == null)) {
+        if ((_currToken == JsonToken.VALUE_EMBEDDED_OBJECT) && (_binaryValue != null)) {
+            return _binaryValue;
+        }
+        if (_currToken != JsonToken.VALUE_STRING) {
             _reportError("Current token ("+_currToken+") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary");
         }
-        /* To ensure that we won't see inconsistent data, better clear up
-         * state...
-         */
+        // To ensure that we won't see inconsistent data, better clear up state
         if (_tokenIncomplete) {
             try {
                 _binaryValue = _decodeBase64(b64variant);
@@ -652,26 +654,22 @@
         _binaryValue = null;
 
         // Closing scope?
-        if (i == INT_RBRACKET) {
-            _updateLocation();
-            if (!_parsingContext.inArray()) {
-                _reportMismatchedEndMarker(i, '}');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
-            return (_currToken = JsonToken.END_ARRAY);
-        }
-        if (i == INT_RCURLY) {
-            _updateLocation();
-            if (!_parsingContext.inObject()) {
-                _reportMismatchedEndMarker(i, ']');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
-            return (_currToken = JsonToken.END_OBJECT);
+        if (i == INT_RBRACKET || i == INT_RCURLY) {
+            _closeScope(i);
+            return _currToken;
         }
 
         // Nope: do we then expect a comma?
         if (_parsingContext.expectComma()) {
             i = _skipComma(i);
+
+            // Was that a trailing comma?
+            if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
+                if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
+                    _closeScope(i);
+                    return _currToken;
+                }
+            }
         }
 
         /* And should we now have a name? Always true for Object contexts, since
@@ -811,26 +809,22 @@
         }
         _binaryValue = null;
 
-        if (i == INT_RBRACKET) {
-            _updateLocation();
-            if (!_parsingContext.inArray()) {
-                _reportMismatchedEndMarker(i, '}');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
-            _currToken = JsonToken.END_ARRAY;
+        // Closing scope?
+        if (i == INT_RBRACKET || i == INT_RCURLY) {
+            _closeScope(i);
             return false;
         }
-        if (i == INT_RCURLY) {
-            _updateLocation();
-            if (!_parsingContext.inObject()) {
-                _reportMismatchedEndMarker(i, ']');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
-            _currToken = JsonToken.END_OBJECT;
-            return false;
-        }
+
         if (_parsingContext.expectComma()) {
             i = _skipComma(i);
+
+            // Was that a trailing comma?
+            if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
+                if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
+                    _closeScope(i);
+                    return false;
+                }
+            }
         }
 
         if (!_parsingContext.inObject()) {
@@ -1898,7 +1892,7 @@
             }
             return _handleInvalidNumberStart(_inputBuffer[_inputPtr++], false);
         }
-        // [Issue#77] Try to decode most likely token
+        // [core#77] Try to decode most likely token
         if (Character.isJavaIdentifierStart(i)) {
             _reportInvalidToken(""+((char) i), "('true', 'false' or 'null')");
         }
@@ -2834,4 +2828,29 @@
         }
         _reportError("Unrecognized token '"+sb.toString()+"': was expecting "+msg);
     }
+
+    /*
+    /**********************************************************
+    /* Internal methods, other
+    /**********************************************************
+     */
+
+    private void _closeScope(int i) throws JsonParseException {
+        if (i == INT_RBRACKET) {
+            _updateLocation();
+            if (!_parsingContext.inArray()) {
+                _reportMismatchedEndMarker(i, '}');
+            }
+            _parsingContext = _parsingContext.clearAndGetParent();
+            _currToken = JsonToken.END_ARRAY;
+        }
+        if (i == INT_RCURLY) {
+            _updateLocation();
+            if (!_parsingContext.inObject()) {
+                _reportMismatchedEndMarker(i, ']');
+            }
+            _parsingContext = _parsingContext.clearAndGetParent();
+            _currToken = JsonToken.END_OBJECT;
+        }
+    }
 }
diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java
index 8bc3789..66f96e5 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java
@@ -569,25 +569,20 @@
         if (_tokenIncomplete) {
             _skipString(); // only strings can be partial
         }
-        int i = _skipWS();
+        int i = _skipWSOrEnd();
+        if (i < 0) { // end-of-input
+            // Close/release things like input source, symbol table and recyclable buffers
+            close();
+            return (_currToken = null);
+        }
         // clear any data retained so far
         _binaryValue = null;
         _tokenInputRow = _currInputRow;
 
         // Closing scope?
-        if (i == INT_RBRACKET) {
-            if (!_parsingContext.inArray()) {
-                _reportMismatchedEndMarker(i, '}');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
-            return (_currToken = JsonToken.END_ARRAY);
-        }
-        if (i == INT_RCURLY) {
-            if (!_parsingContext.inObject()) {
-                _reportMismatchedEndMarker(i, ']');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
-            return (_currToken = JsonToken.END_OBJECT);
+        if (i == INT_RBRACKET || i == INT_RCURLY) {
+            _closeScope(i);
+            return _currToken;
         }
 
         // Nope: do we then expect a comma?
@@ -596,6 +591,14 @@
                 _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
             }
             i = _skipWS();
+
+            // Was that a trailing comma?
+            if (Feature.ALLOW_TRAILING_COMMA.enabledIn(_features)) {
+                if (i == INT_RBRACKET || i == INT_RCURLY) {
+                    _closeScope(i);
+                    return _currToken;
+                }
+            }
         }
 
         /* And should we now have a name? Always true for
@@ -2199,6 +2202,45 @@
         }
     }
 
+    /**
+     * Alternative to {@link #_skipWS} that handles possible {@link EOFException}
+     * caused by trying to read past the end of {@link InputData}.
+     *
+     * @since 2.9
+     */
+    private final int _skipWSOrEnd() throws IOException
+    {
+        int i = _nextByte;
+        if (i < 0) {
+            try {
+                i = _inputData.readUnsignedByte();
+            } catch (EOFException e) {
+                return _eofAsNextChar();
+            }
+        } else {
+            _nextByte = -1;
+        }
+        while (true) {
+            if (i > INT_SPACE) {
+                if (i == INT_SLASH || i == INT_HASH) {
+                    return _skipWSComment(i);
+                }
+                return i;
+            } else {
+                // 06-May-2016, tatu: Could verify validity of WS, but for now why bother.
+                //   ... but line number is useful thingy
+                if (i == INT_CR || i == INT_LF) {
+                    ++_currInputRow;
+                }
+            }
+            try {
+                i = _inputData.readUnsignedByte();
+            } catch (EOFException e) {
+                return _eofAsNextChar();
+            }
+        }
+    }
+    
     private final int _skipWSComment(int i) throws IOException
     {
         while (true) {
@@ -2788,6 +2830,23 @@
     /**********************************************************
      */
 
+    private void _closeScope(int i) throws JsonParseException {
+        if (i == INT_RBRACKET) {
+            if (!_parsingContext.inArray()) {
+                _reportMismatchedEndMarker(i, '}');
+            }
+            _parsingContext = _parsingContext.clearAndGetParent();
+            _currToken = JsonToken.END_ARRAY;
+        }
+        if (i == INT_RCURLY) {
+            if (!_parsingContext.inObject()) {
+                _reportMismatchedEndMarker(i, ']');
+            }
+            _parsingContext = _parsingContext.clearAndGetParent();
+            _currToken = JsonToken.END_OBJECT;
+        }
+    }
+
     /**
      * Helper method needed to fix [Issue#148], masking of 0x00 character
      */
diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
index 5a0dcda..1533f4a 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
@@ -28,6 +28,8 @@
     // pre-processing task, to simplify first pass, keep it fast.
     protected final static int[] _icLatin1 = CharTypes.getInputCodeLatin1();
 
+    protected final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask();
+
     /*
     /**********************************************************
     /* Configuration
@@ -118,7 +120,7 @@
      * buffer.
      */
     protected boolean _bufferRecyclable;
-    
+
     /*
     /**********************************************************
     /* Life-cycle
@@ -152,7 +154,7 @@
     public void setCodec(ObjectCodec c) {
         _objectCodec = c;
     }
-    
+
     /*
     /**********************************************************
     /* Overrides for life-cycle
@@ -176,7 +178,7 @@
     public Object getInputSource() {
         return _inputStream;
     }
-    
+
     /*
     /**********************************************************
     /* Overrides, low-level reading
@@ -259,14 +261,12 @@
         }
         return true;
     }
-    
+
     @Override
     protected void _closeInput() throws IOException
     {
-        /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
-         *   on the underlying InputStream, unless we "own" it, or auto-closing
-         *   feature is enabled.
-         */
+        // We are not to call close() on the underlying InputStream
+        // unless we "own" it, or auto-closing feature is enabled.
         if (_inputStream != null) {
             if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) {
                 _inputStream.close();
@@ -739,19 +739,11 @@
 
         // Closing scope?
         if (i == INT_RBRACKET) {
-            _updateLocation();
-            if (!_parsingContext.inArray()) {
-                _reportMismatchedEndMarker(i, '}');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
+            _closeArrayScope();
             return (_currToken = JsonToken.END_ARRAY);
         }
         if (i == INT_RCURLY) {
-            _updateLocation();
-            if (!_parsingContext.inObject()) {
-                _reportMismatchedEndMarker(i, ']');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
+            _closeObjectScope();
             return (_currToken = JsonToken.END_OBJECT);
         }
 
@@ -761,11 +753,16 @@
                 _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
             }
             i = _skipWS();
+            // Was that a trailing comma?
+            if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
+                if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
+                    return _closeScope(i);
+                }
+            }
         }
 
-        /* And should we now have a name? Always true for
-         * Object contexts, since the intermediate 'expect-value'
-         * state is never retained.
+        /* And should we now have a name? Always true for Object contexts
+         * since the intermediate 'expect-value' state is never retained.
          */
         if (!_parsingContext.inObject()) {
             _updateLocation();
@@ -931,20 +928,12 @@
 
         // Closing scope?
         if (i == INT_RBRACKET) {
-            _updateLocation();
-            if (!_parsingContext.inArray()) {
-                _reportMismatchedEndMarker(i, '}');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
+            _closeArrayScope();
             _currToken = JsonToken.END_ARRAY;
             return false;
         }
         if (i == INT_RCURLY) {
-            _updateLocation();
-            if (!_parsingContext.inObject()) {
-                _reportMismatchedEndMarker(i, ']');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
+            _closeObjectScope();
             _currToken = JsonToken.END_OBJECT;
             return false;
         }
@@ -955,8 +944,15 @@
                 _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
             }
             i = _skipWS();
-        }
 
+            // Was that a trailing comma?
+            if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
+                if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
+                    _closeScope(i);
+                    return false;
+                }
+            }
+        }
         if (!_parsingContext.inObject()) {
             _updateLocation();
             _nextTokenNotInObject(i);
@@ -1018,20 +1014,12 @@
         _binaryValue = null;
 
         if (i == INT_RBRACKET) {
-            _updateLocation();
-            if (!_parsingContext.inArray()) {
-                _reportMismatchedEndMarker(i, '}');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
+            _closeArrayScope();
             _currToken = JsonToken.END_ARRAY;
             return null;
         }
         if (i == INT_RCURLY) {
-            _updateLocation();
-            if (!_parsingContext.inObject()) {
-                _reportMismatchedEndMarker(i, ']');
-            }
-            _parsingContext = _parsingContext.clearAndGetParent();
+            _closeObjectScope();
             _currToken = JsonToken.END_OBJECT;
             return null;
         }
@@ -1042,7 +1030,15 @@
                 _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
             }
             i = _skipWS();
+            // Was that a trailing comma?
+            if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
+                if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
+                    _closeScope(i);
+                    return null;
+                }
+            }
         }
+
         if (!_parsingContext.inObject()) {
             _updateLocation();
             _nextTokenNotInObject(i);
@@ -3497,33 +3493,32 @@
     /**********************************************************
      */
 
-    protected void _reportInvalidToken(String matchedPart) throws IOException
-     {
-         _reportInvalidToken(matchedPart, "'null', 'true', 'false' or NaN");
-     }
+    protected void _reportInvalidToken(String matchedPart) throws IOException {
+        _reportInvalidToken(matchedPart, "'null', 'true', 'false' or NaN");
+    }
 
     protected void _reportInvalidToken(String matchedPart, String msg) throws IOException
-     {
-         StringBuilder sb = new StringBuilder(matchedPart);
+    {
+        StringBuilder sb = new StringBuilder(matchedPart);
 
-         /* Let's just try to find what appears to be the token, using
-          * regular Java identifier character rules. It's just a heuristic,
-          * nothing fancy here (nor fast).
-          */
-         while (true) {
-             if (_inputPtr >= _inputEnd && !_loadMore()) {
-                 break;
-             }
-             int i = (int) _inputBuffer[_inputPtr++];
-             char c = (char) _decodeCharForError(i);
-             if (!Character.isJavaIdentifierPart(c)) {
-                 break;
-             }
-             sb.append(c);
-         }
-         _reportError("Unrecognized token '"+sb.toString()+"': was expecting "+msg);
-     }
-        
+        /* Let's just try to find what appears to be the token, using
+         * regular Java identifier character rules. It's just a heuristic,
+         * nothing fancy here (nor fast).
+         */
+        while (true) {
+            if (_inputPtr >= _inputEnd && !_loadMore()) {
+                break;
+            }
+            int i = (int) _inputBuffer[_inputPtr++];
+            char c = (char) _decodeCharForError(i);
+            if (!Character.isJavaIdentifierPart(c)) {
+                break;
+            }
+            sb.append(c);
+        }
+        _reportError("Unrecognized token '"+sb.toString()+"': was expecting "+msg);
+    }
+
     protected void _reportInvalidChar(int c)
         throws JsonParseException
     {
@@ -3733,6 +3728,31 @@
     /**********************************************************
      */
 
+    private final JsonToken _closeScope(int i) throws JsonParseException {
+        if (i == INT_RCURLY) {
+            _closeObjectScope();
+            return (_currToken = JsonToken.END_OBJECT);
+        }
+        _closeArrayScope();
+        return (_currToken = JsonToken.END_ARRAY);
+    }
+
+    private final void _closeArrayScope() throws JsonParseException {
+        _updateLocation();
+        if (!_parsingContext.inArray()) {
+            _reportMismatchedEndMarker(']', '}');
+        }
+        _parsingContext = _parsingContext.clearAndGetParent();
+    }
+
+    private final void _closeObjectScope() throws JsonParseException {
+        _updateLocation();
+        if (!_parsingContext.inObject()) {
+            _reportMismatchedEndMarker('}', ']');
+        }
+        _parsingContext = _parsingContext.clearAndGetParent();
+    }
+
     /**
      * Helper method needed to fix [Issue#148], masking of 0x00 character
      */
diff --git a/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java b/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
index 6641151..f5ee928 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
@@ -364,17 +364,17 @@
      */
     
     @Override
-    public void writeObject(Object pojo) throws IOException,JsonProcessingException {
+    public void writeObject(Object pojo) throws IOException {
         if (delegateCopyMethods) {
             delegate.writeObject(pojo);
             return;
         }
-        // NOTE: copied from 
         if (pojo == null) {
             writeNull();
         } else {
-            if (getCodec() != null) {
-                getCodec().writeValue(this, pojo);
+            ObjectCodec c = getCodec();
+            if (c != null) {
+                c.writeValue(this, pojo);
                 return;
             }
             _writeSimpleObject(pojo);
@@ -382,19 +382,20 @@
     }
     
     @Override
-    public void writeTree(TreeNode rootNode) throws IOException {
+    public void writeTree(TreeNode tree) throws IOException {
         if (delegateCopyMethods) {
-            delegate.writeTree(rootNode);
+            delegate.writeTree(tree);
             return;
         }
         // As with 'writeObject()', we are not check if write would work
-        if (rootNode == null) {
+        if (tree == null) {
             writeNull();
         } else {
-            if (getCodec() == null) {
+            ObjectCodec c = getCodec();
+            if (c == null) {
                 throw new IllegalStateException("No ObjectCodec defined");
             }
-            getCodec().writeValue(this, rootNode);
+            c.writeTree(this, tree);
         }
     }
 
@@ -413,15 +414,15 @@
      */
 
     @Override
-    public void copyCurrentEvent(JsonParser jp) throws IOException {
-        if (delegateCopyMethods) delegate.copyCurrentEvent(jp);
-        else super.copyCurrentEvent(jp);
+    public void copyCurrentEvent(JsonParser p) throws IOException {
+        if (delegateCopyMethods) delegate.copyCurrentEvent(p);
+        else super.copyCurrentEvent(p);
     }
 
     @Override
-    public void copyCurrentStructure(JsonParser jp) throws IOException {
-        if (delegateCopyMethods) delegate.copyCurrentStructure(jp);
-        else super.copyCurrentStructure(jp);
+    public void copyCurrentStructure(JsonParser p) throws IOException {
+        if (delegateCopyMethods) delegate.copyCurrentStructure(p);
+        else super.copyCurrentStructure(p);
     }
 
     /*
diff --git a/src/main/java/com/fasterxml/jackson/core/util/VersionUtil.java b/src/main/java/com/fasterxml/jackson/core/util/VersionUtil.java
index 3896001..5bdc1b4 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/VersionUtil.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/VersionUtil.java
@@ -27,33 +27,17 @@
 {
     private final static Pattern V_SEP = Pattern.compile("[-_./;:]");
 
-    private final Version _v;
-
     /*
     /**********************************************************
     /* Instance life-cycle
     /**********************************************************
      */
-    
-    protected VersionUtil()
-    {
-        Version v = null;
-        try {
-            /* Class we pass only matters for resource-loading: can't use this Class
-             * (as it's just being loaded at this point), nor anything that depends on it.
-             */
-            v = VersionUtil.versionFor(getClass());
-        } catch (Exception e) { // not good to dump to stderr; but that's all we have at this low level
-            System.err.println("ERROR: Failed to load Version information from "+getClass());
-        }
-        if (v == null) {
-            v = Version.unknownVersion();
-        }
-        _v = v;
-    }
 
-    public Version version() { return _v; }
-    
+    protected VersionUtil() { }
+
+    @Deprecated // since 2.9
+    public Version version() { return Version.unknownVersion(); }
+
     /*
     /**********************************************************
     /* Static load methods
diff --git a/src/test/java/com/fasterxml/jackson/core/BaseTest.java b/src/test/java/com/fasterxml/jackson/core/BaseTest.java
index ca8ce4f..053869a 100644
--- a/src/test/java/com/fasterxml/jackson/core/BaseTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/BaseTest.java
@@ -422,6 +422,7 @@
     {
         StringWriter sw = new StringWriter(100);
         JsonGenerator g = f.createGenerator(sw);
+        g.disable(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT);
         try {
             while (p.nextToken() != null) {
                 g.copyCurrentEvent(p);
diff --git a/src/test/java/com/fasterxml/jackson/core/TestExceptions.java b/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
index 0301b19..fbbb74f 100644
--- a/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
+++ b/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
@@ -16,6 +16,20 @@
         String orig = exc.getOriginalMessage();
         assertEquals("Foobar", orig);
         assertTrue(msg.length() > orig.length());
+
+        // and another
+        JsonProcessingException exc2 = new JsonProcessingException("Second",
+                JsonLocation.NA, exc);
+        assertSame(exc, exc2.getCause());
+        exc2.clearLocation();
+        assertNull(exc2.getLocation());
+
+        // and yet with null
+        JsonProcessingException exc3 = new JsonProcessingException(exc);
+        assertNull(exc3.getOriginalMessage());
+        assertEquals("N/A", exc3.getMessage());
+
+        assertEquals("com.fasterxml.jackson.core.JsonProcessingException: N/A", exc3.toString());
     }
 
     // [core#198]
diff --git a/src/test/java/com/fasterxml/jackson/core/TestLocation.java b/src/test/java/com/fasterxml/jackson/core/TestLocation.java
new file mode 100644
index 0000000..d993129
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/TestLocation.java
@@ -0,0 +1,21 @@
+package com.fasterxml.jackson.core;
+
+public class TestLocation extends BaseTest
+{
+    public void testBasics()
+    {
+        JsonLocation loc1 = new JsonLocation("src", 10L, 10L, 1, 2);
+        JsonLocation loc2 = new JsonLocation(null, 10L, 10L, 3, 2);
+        assertEquals(loc1, loc1);
+        assertFalse(loc1.equals(null));
+        assertFalse(loc1.equals(loc2));
+        assertFalse(loc2.equals(loc1));
+
+        // don't care about what it is; should not compute to 0 with data above
+        assertTrue(loc1.hashCode() != 0);
+        assertTrue(loc2.hashCode() != 0);
+
+        assertEquals("[Source: src; line: 1, column: 2]", loc1.toString());
+        assertEquals("[Source: UNKNOWN; line: 3, column: 2]", loc2.toString());
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/TestVersions.java b/src/test/java/com/fasterxml/jackson/core/TestVersions.java
index c7b6feb..865be6f 100644
--- a/src/test/java/com/fasterxml/jackson/core/TestVersions.java
+++ b/src/test/java/com/fasterxml/jackson/core/TestVersions.java
@@ -6,7 +6,7 @@
 import com.fasterxml.jackson.core.util.BufferRecycler;
 
 /**
- * Tests to verify [JACKSON-278]
+ * Tests to verify functioning of {@link Version} class.
  */
 public class TestVersions extends com.fasterxml.jackson.core.BaseTest
 {
@@ -22,6 +22,18 @@
         jgen.close();
     }
 
+    public void testMisc() {
+        Version unk = Version.unknownVersion();
+        assertEquals("0.0.0", unk.toString());
+        assertEquals("//0.0.0", unk.toFullString());
+        assertTrue(unk.equals(unk));
+
+        Version other = new Version(2, 8, 4, "",
+                "groupId", "artifactId");
+        assertEquals("2.8.4", other.toString());
+        assertEquals("groupId/artifactId/2.8.4", other.toFullString());
+    }
+    
     /*
     /**********************************************************
     /* Helper methods
diff --git a/src/test/java/com/fasterxml/jackson/core/base64/Base64BinaryParsingTest.java b/src/test/java/com/fasterxml/jackson/core/base64/Base64BinaryParsingTest.java
index 8693bb9..24b53ea 100644
--- a/src/test/java/com/fasterxml/jackson/core/base64/Base64BinaryParsingTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/base64/Base64BinaryParsingTest.java
@@ -49,6 +49,63 @@
         }
     }
 
+    public void testInvalidTokenForBase64() throws IOException
+    {
+        for (int mode : ALL_MODES) {
+
+            // First: illegal padding
+            JsonParser p = createParser(mode, "[ ]");
+            assertToken(JsonToken.START_ARRAY, p.nextToken());
+            try {
+                p.getBinaryValue();
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "current token");
+                verifyException(e, "can not access as binary");
+            }
+            p.close();
+        }
+    }
+
+    public void testInvalidChar() throws IOException
+    {
+        for (int mode : ALL_MODES) {
+
+            // First: illegal padding
+            JsonParser p = createParser(mode, quote("a==="));
+            assertToken(JsonToken.VALUE_STRING, p.nextToken());
+            try {
+                p.getBinaryValue(Base64Variants.MIME);
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "padding only legal");
+            }
+            p.close();
+
+            // second: invalid space within
+            p = createParser(mode, quote("ab de"));
+            assertToken(JsonToken.VALUE_STRING, p.nextToken());
+            try {
+                p.getBinaryValue(Base64Variants.MIME);
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "illegal white space");
+            }
+            p.close();
+
+            // third: something else
+            p = createParser(mode, quote("ab#?"));
+            assertToken(JsonToken.VALUE_STRING, p.nextToken());
+            try {
+                p.getBinaryValue(Base64Variants.MIME);
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "illegal character '#'");
+            }
+            p.close();
+        }
+    }
+    
     /*
     /**********************************************************
     /* Test helper methods
diff --git a/src/test/java/com/fasterxml/jackson/core/base64/Base64CodecTest.java b/src/test/java/com/fasterxml/jackson/core/base64/Base64CodecTest.java
new file mode 100644
index 0000000..6b895ed
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/base64/Base64CodecTest.java
@@ -0,0 +1,113 @@
+package com.fasterxml.jackson.core.base64;
+
+import org.junit.Assert;
+
+import com.fasterxml.jackson.core.*;
+
+public class Base64CodecTest
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    public void testVariantAccess()
+    {
+        for (Base64Variant var : new Base64Variant[] {
+                Base64Variants.MIME,
+                Base64Variants.MIME_NO_LINEFEEDS,
+                Base64Variants.MODIFIED_FOR_URL,
+                Base64Variants.PEM
+        }) {
+            assertSame(var, Base64Variants.valueOf(var.getName()));
+        }
+
+        try {
+            Base64Variants.valueOf("foobar");
+            fail("Should not pass");
+        } catch (IllegalArgumentException e) {
+            verifyException(e, "No Base64Variant with name 'foobar'");
+        }
+    }
+
+    public void testProps()
+    {
+        Base64Variant std = Base64Variants.MIME;
+        // let's verify basic props of std cocec
+        assertEquals("MIME", std.getName());
+        assertEquals("MIME", std.toString());
+        assertTrue(std.usesPadding());
+        assertFalse(std.usesPaddingChar('X'));
+        assertEquals('=', std.getPaddingChar());
+        assertTrue(std.usesPaddingChar('='));
+        assertEquals((byte) '=', std.getPaddingByte());
+        assertEquals(76, std.getMaxLineLength());
+    }
+
+    public void testCharEncoding() throws Exception
+    {
+        Base64Variant std = Base64Variants.MIME;
+        assertEquals(Base64Variant.BASE64_VALUE_INVALID, std.decodeBase64Char('?'));
+        assertEquals(Base64Variant.BASE64_VALUE_INVALID, std.decodeBase64Char((int) '?'));
+        assertEquals(Base64Variant.BASE64_VALUE_INVALID, std.decodeBase64Char((char) 0xA0));
+        assertEquals(Base64Variant.BASE64_VALUE_INVALID, std.decodeBase64Char(0xA0));
+
+        assertEquals(Base64Variant.BASE64_VALUE_INVALID, std.decodeBase64Byte((byte) '?'));
+        assertEquals(Base64Variant.BASE64_VALUE_INVALID, std.decodeBase64Byte((byte) 0xA0));
+        
+        assertEquals(0, std.decodeBase64Char('A'));
+        assertEquals(1, std.decodeBase64Char((int) 'B'));
+        assertEquals(2, std.decodeBase64Char((byte)'C'));
+
+        assertEquals(0, std.decodeBase64Byte((byte) 'A'));
+        assertEquals(1, std.decodeBase64Byte((byte) 'B'));
+        assertEquals(2, std.decodeBase64Byte((byte)'C'));
+        
+        assertEquals('/', std.encodeBase64BitsAsChar(63));
+        assertEquals((byte) 'b', std.encodeBase64BitsAsByte(27));
+
+        String EXP_STR = "HwdJ";
+        int TRIPLET = 0x1F0749;
+        StringBuilder sb = new StringBuilder();
+        std.encodeBase64Chunk(sb, TRIPLET);
+        assertEquals(EXP_STR, sb.toString());
+
+        byte[] exp = EXP_STR.getBytes("UTF-8");
+        byte[] act = new byte[exp.length];
+        std.encodeBase64Chunk(TRIPLET, act, 0);
+        Assert.assertArrayEquals(exp, act);
+    }
+
+    public void testConvenienceMethods() throws Exception
+    {
+        Base64Variant std = Base64Variants.MIME;
+
+        byte[] input = new byte[] { 1, 2, 34, 127, -1 };
+        String encoded = std.encode(input, false);
+        byte[] decoded = std.decode(encoded);    
+        Assert.assertArrayEquals(input, decoded);
+
+        assertEquals(quote(encoded), std.encode(input, true));
+    }
+
+    @SuppressWarnings("unused")
+    public void testErrors() throws Exception
+    {
+        try {
+            Base64Variant b = new Base64Variant("foobar", "xyz", false, '!', 24);
+            fail("Should not pass");
+        } catch (IllegalArgumentException iae) {
+            verifyException(iae, "length must be exactly");
+        }
+        try {
+            Base64Variants.MIME.decode("!@##@%$#%&*^(&)(*");
+        } catch (IllegalArgumentException iae) {
+            verifyException(iae, "Illegal character");
+        }
+
+        // also, for [jackson-core#335]
+        final String BASE64_HELLO = "aGVsbG8=!";
+        try {
+            Base64Variants.MIME.decode(BASE64_HELLO);
+            fail("Should not pass");
+        } catch (IllegalArgumentException iae) {
+            verifyException(iae, "Illegal character");
+        }
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/base64/TestBase64Codec.java b/src/test/java/com/fasterxml/jackson/core/base64/TestBase64Codec.java
deleted file mode 100644
index dabcc39..0000000
--- a/src/test/java/com/fasterxml/jackson/core/base64/TestBase64Codec.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.fasterxml.jackson.core.base64;
-
-import org.junit.Assert;
-
-import com.fasterxml.jackson.core.*;
-
-public class TestBase64Codec
-    extends com.fasterxml.jackson.core.BaseTest
-{
-    public void testProps()
-    {
-        Base64Variant std = Base64Variants.MIME;
-        // let's verify basic props of std cocec
-        assertEquals("MIME", std.getName());
-        assertEquals("MIME", std.toString());
-        assertTrue(std.usesPadding());
-        assertFalse(std.usesPaddingChar('X'));
-        assertEquals('=', std.getPaddingChar());
-        assertTrue(std.usesPaddingChar('='));
-        assertEquals((byte) '=', std.getPaddingByte());
-        assertEquals(76, std.getMaxLineLength());
-    }
-
-    public void testCharEncoding() throws Exception
-    {
-        Base64Variant std = Base64Variants.MIME;
-        assertEquals(Base64Variant.BASE64_VALUE_INVALID, std.decodeBase64Char('?'));
-        assertEquals(Base64Variant.BASE64_VALUE_INVALID, std.decodeBase64Char((int) '?'));
-        assertEquals(Base64Variant.BASE64_VALUE_INVALID, std.decodeBase64Char((byte) '?'));
-
-        assertEquals(0, std.decodeBase64Char('A'));
-        assertEquals(1, std.decodeBase64Char((int) 'B'));
-        assertEquals(2, std.decodeBase64Char((byte)'C'));
-
-        assertEquals('/', std.encodeBase64BitsAsChar(63));
-        assertEquals((byte) 'b', std.encodeBase64BitsAsByte(27));
-
-        String EXP_STR = "HwdJ";
-        int TRIPLET = 0x1F0749;
-        StringBuilder sb = new StringBuilder();
-        std.encodeBase64Chunk(sb, TRIPLET);
-        assertEquals(EXP_STR, sb.toString());
-
-        byte[] exp = EXP_STR.getBytes("UTF-8");
-        byte[] act = new byte[exp.length];
-        std.encodeBase64Chunk(TRIPLET, act, 0);
-        Assert.assertArrayEquals(exp, act);
-    }
-
-    @SuppressWarnings("unused")
-    public void testErrors() throws Exception
-    {
-        try {
-            Base64Variant b = new Base64Variant("foobar", "xyz", false, '!', 24);
-        } catch (IllegalArgumentException iae) {
-            verifyException(iae, "length must be exactly");
-        }
-
-        // also, for [jackson-core#335]
-        final String BASE64_HELLO = "aGVsbG8=!";
-        try {
-            Base64Variants.MIME.decode(BASE64_HELLO);
-            fail("Should not pass");
-        } catch (IllegalArgumentException iae) {
-            verifyException(iae, "Illegal character");
-        }
-    }
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/filter/BasicParserFilteringTest.java b/src/test/java/com/fasterxml/jackson/core/filter/BasicParserFilteringTest.java
index f7de6b5..7c061ec 100644
--- a/src/test/java/com/fasterxml/jackson/core/filter/BasicParserFilteringTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/filter/BasicParserFilteringTest.java
@@ -91,20 +91,6 @@
     }
 
     @SuppressWarnings("resource")
-    public void testSingleMatchFilteringWithPath() throws Exception
-    {
-        JsonParser p0 = JSON_F.createParser(SIMPLE);
-        JsonParser p = new FilteringParserDelegate(p0,
-               new NameMatchFilter("value"),
-                   true, // includePath
-                   false // multipleMatches
-                );
-        String result = readAndWrite(JSON_F, p);
-        assertEquals(aposToQuotes("{'ob':{'value':3}}"), result);
-    }
-
-    
-    @SuppressWarnings("resource")
     public void testNotAllowMultipleMatches() throws Exception
     {
     	String jsonString = aposToQuotes("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'value':4,'b':true}");
diff --git a/src/test/java/com/fasterxml/jackson/core/io/UTF8WriterTest.java b/src/test/java/com/fasterxml/jackson/core/io/UTF8WriterTest.java
index 32d1c39..ddefff6 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/UTF8WriterTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/UTF8WriterTest.java
@@ -2,6 +2,8 @@
 
 import java.io.*;
 
+import org.junit.Assert;
+
 import com.fasterxml.jackson.core.io.IOContext;
 import com.fasterxml.jackson.core.io.UTF8Writer;
 import com.fasterxml.jackson.core.util.BufferRecycler;
@@ -51,6 +53,7 @@
         char[] ch = str.toCharArray();
 
         w.write(ch, 0, ch.length);
+        w.flush(); // trigger different code path for close
         w.close();
 
         byte[] data = out.toByteArray();
@@ -68,9 +71,11 @@
         UTF8Writer w = new UTF8Writer(ctxt, out);
         
         w.write('X');
+        char[] ch = { 'Y' };
+        w.write(ch);
         
         w.close();
-        assertEquals(1, out.size());
+        assertEquals(2, out.size());
 
         // and this ought to be fine...
         w.flush();
@@ -78,4 +83,80 @@
         w.close();
         w.flush();
     }
+
+    public void testSurrogatesOk() throws Exception
+    {
+        BufferRecycler rec = new BufferRecycler();
+        IOContext ctxt = new IOContext(rec, null, false);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        UTF8Writer w = new UTF8Writer(ctxt, out);
+
+        // First, valid case, char by char
+        w.write(0xD83D);
+        w.write(0xDE03);
+        w.close();
+        assertEquals(4, out.size());
+        final byte[] EXP_SURROGATES = new byte[] { (byte) 0xF0, (byte) 0x9F,
+               (byte) 0x98, (byte) 0x83 };
+        Assert.assertArrayEquals(EXP_SURROGATES, out.toByteArray());
+
+        // and then as String
+        ctxt = new IOContext(rec, null, false);
+        out = new ByteArrayOutputStream();
+        w = new UTF8Writer(ctxt, out);
+        w.write("\uD83D\uDE03");
+        w.close();
+        assertEquals(4, out.size());
+        Assert.assertArrayEquals(EXP_SURROGATES, out.toByteArray());
+    }
+
+    @SuppressWarnings("resource")
+    public void testSurrogatesFail() throws Exception
+    {
+        BufferRecycler rec = new BufferRecycler();
+        IOContext ctxt;
+        ByteArrayOutputStream out;
+        UTF8Writer w;
+
+        ctxt = new IOContext(rec, null, false);
+        out = new ByteArrayOutputStream();
+        w = new UTF8Writer(ctxt, out);
+        try {
+            w.write(0xDE03);
+            fail("should not pass");
+        } catch (IOException e) {
+            verifyException(e, "Unmatched second part");
+        }
+
+        ctxt = new IOContext(rec, null, false);
+        out = new ByteArrayOutputStream();
+        w = new UTF8Writer(ctxt, out);
+        w.write(0xD83D);
+        try {
+            w.write('a');
+            fail("should not pass");
+        } catch (IOException e) {
+            verifyException(e, "Broken surrogate pair");
+        }
+
+        ctxt = new IOContext(rec, null, false);
+        out = new ByteArrayOutputStream();
+        w = new UTF8Writer(ctxt, out);
+        try {
+            w.write("\uDE03");
+            fail("should not pass");
+        } catch (IOException e) {
+            verifyException(e, "Unmatched second part");
+        }
+        
+        ctxt = new IOContext(rec, null, false);
+        out = new ByteArrayOutputStream();
+        w = new UTF8Writer(ctxt, out);
+        try {
+            w.write("\uD83Da");
+            fail("should not pass");
+        } catch (IOException e) {
+            verifyException(e, "Broken surrogate pair");
+        }
+    }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java b/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java
index 85363f4..955d3d5 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java
@@ -46,6 +46,31 @@
         seq.close();
     }
 
+    public void testMultiLevel() throws Exception
+    {
+        JsonParser p1 = JSON_FACTORY.createParser("[ 1 ] ");
+        JsonParser p2 = JSON_FACTORY.createParser(" 5");
+        JsonParser p3 = JSON_FACTORY.createParser(" { } ");
+        JsonParserSequence seq1 = JsonParserSequence.createFlattened(true, p1, p2);
+        JsonParserSequence seq = JsonParserSequence.createFlattened(false, seq1, p3);
+        assertEquals(3, seq.containedParsersCount());
+
+        assertToken(JsonToken.START_ARRAY, seq.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, seq.nextToken());
+        assertToken(JsonToken.END_ARRAY, seq.nextToken());
+
+        assertToken(JsonToken.VALUE_NUMBER_INT, seq.nextToken());
+        
+        assertToken(JsonToken.START_OBJECT, seq.nextToken());
+        assertToken(JsonToken.END_OBJECT, seq.nextToken());
+
+        assertNull(seq.nextToken());
+        assertTrue(p1.isClosed());
+        assertTrue(p2.isClosed());
+        assertTrue(p3.isClosed());
+        assertTrue(seq.isClosed());
+    }
+    
     // for [jackson-core#296]
     public void testInitializationDisabled() throws Exception
     {
diff --git a/src/test/java/com/fasterxml/jackson/core/read/DataInputTest.java b/src/test/java/com/fasterxml/jackson/core/read/DataInputTest.java
new file mode 100644
index 0000000..4b90862
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/DataInputTest.java
@@ -0,0 +1,42 @@
+package com.fasterxml.jackson.core.read;
+
+import com.fasterxml.jackson.core.*;
+
+/* Additional testing for {@link java.io.DataInput} specific
+ * challenges for parsing.
+ */
+public class DataInputTest
+    extends com.fasterxml.jackson.core.BaseTest
+{
+    private final JsonFactory JSON_F = new JsonFactory();
+
+    public void testEOFAfterArray() throws Exception
+    {
+        JsonParser p = createParser(JSON_F, MODE_DATA_INPUT, "[ 1 ]  ");
+        assertToken(JsonToken.START_ARRAY, p.nextToken());
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertToken(JsonToken.END_ARRAY, p.nextToken());
+        assertNull(p.nextToken());
+        p.close();
+    }
+
+    public void testEOFAfterObject() throws Exception
+    {
+        JsonParser p = createParser(JSON_F, MODE_DATA_INPUT, "{ \"value\" : true }");
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        assertNull(p.nextToken());
+        p.close();
+    }
+
+    public void testEOFAfterScalar() throws Exception
+    {
+        JsonParser p = createParser(JSON_F, MODE_DATA_INPUT, "\"foobar\" ");
+        assertToken(JsonToken.VALUE_STRING, p.nextToken());
+        assertEquals("foobar", p.getText());
+        assertNull(p.nextToken());
+        p.close();
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/read/NumberCoercionTest.java b/src/test/java/com/fasterxml/jackson/core/read/NumberCoercionTest.java
new file mode 100644
index 0000000..8b83f09
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/NumberCoercionTest.java
@@ -0,0 +1,284 @@
+package com.fasterxml.jackson.core.read;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.BaseTest;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonParser.NumberType;
+import com.fasterxml.jackson.core.JsonToken;
+
+public class NumberCoercionTest extends BaseTest
+{
+    /*
+    /**********************************************************
+    /* Numeric coercions, integral
+    /**********************************************************
+     */
+
+    public void testToIntCoercion() throws Exception
+    {
+        for (int mode : ALL_STREAMING_MODES) {
+            JsonParser p;
+
+            // long->int
+            p = createParser(mode, "1");
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(1L, p.getLongValue());
+            assertEquals(1, p.getIntValue());
+            p.close();
+
+            // BigInteger->int
+            p = createParser(mode, "10");
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(BigInteger.TEN, p.getBigIntegerValue());
+            assertEquals(10, p.getIntValue());
+            p.close();
+
+            // double->int
+            p = createParser(mode, "2");
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(2.0, p.getDoubleValue());
+            assertEquals(2, p.getIntValue());
+            p.close();
+
+            // BigDecimal->int
+            p = createParser(mode, "10");
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(BigDecimal.TEN, p.getDecimalValue());
+            assertEquals(10, p.getIntValue());
+            p.close();
+        }
+    }
+
+    @SuppressWarnings("resource")
+    public void testToIntFailing() throws Exception
+    {
+        for (int mode : ALL_STREAMING_MODES) {
+            JsonParser p;
+
+            // long -> error
+            long big = 1L + Integer.MAX_VALUE;
+            p = createParser(mode, String.valueOf(big));
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(big, p.getLongValue());
+            try {
+                p.getIntValue();
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "out of range of int");
+            }
+            long small = -1L + Integer.MIN_VALUE;
+            p = createParser(mode, String.valueOf(small));
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(Long.valueOf(small), p.getNumberValue());
+            assertEquals(small, p.getLongValue());
+            try {
+                p.getIntValue();
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "out of range of int");
+            }
+
+            // double -> error
+            p = createParser(mode, String.valueOf(big)+".0");
+            assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+            assertEquals((double) big, p.getDoubleValue());
+            try {
+                p.getIntValue();
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "out of range of int");
+            }
+            p = createParser(mode, String.valueOf(small)+".0");
+            assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+            assertEquals((double) small, p.getDoubleValue());
+            try {
+                p.getIntValue();
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "out of range of int");
+            }
+
+            // BigInteger -> error
+            p = createParser(mode, String.valueOf(big));
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(BigInteger.valueOf(big), p.getBigIntegerValue());
+            try {
+                p.getIntValue();
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "out of range of int");
+            }
+            p = createParser(mode, String.valueOf(small));
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(BigInteger.valueOf(small), p.getBigIntegerValue());
+            try {
+                p.getIntValue();
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "out of range of int");
+            }
+        }
+    }
+
+    public void testToLongCoercion() throws Exception
+    {
+        for (int mode : ALL_STREAMING_MODES) {
+            JsonParser p;
+
+            // int->long
+            p = createParser(mode, "1");
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(1, p.getIntValue());
+            assertEquals(1L, p.getLongValue());
+            p.close();
+
+            // BigInteger->long
+            long biggish = 12345678901L;
+            p = createParser(mode, String.valueOf(biggish));
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(BigInteger.valueOf(biggish), p.getBigIntegerValue());
+            assertEquals(biggish, p.getLongValue());
+            p.close();
+
+            // double->long
+            p = createParser(mode, "2");
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(2.0, p.getDoubleValue());
+            assertEquals(2L, p.getLongValue());
+            p.close();
+
+            // BigDecimal->long
+            p = createParser(mode, "10");
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(BigDecimal.TEN, p.getDecimalValue());
+            assertEquals(10, p.getLongValue());
+            p.close();
+        }
+    }
+
+    @SuppressWarnings("resource")
+    public void testToLongFailing() throws Exception
+    {
+        for (int mode : ALL_STREAMING_MODES) {
+            JsonParser p;
+
+            // BigInteger -> error
+            BigInteger big = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.TEN);
+            p = createParser(mode, String.valueOf(big));
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(NumberType.BIG_INTEGER, p.getNumberType());
+            assertEquals(big, p.getBigIntegerValue());
+            assertEquals(big, p.getNumberValue());
+            try {
+                p.getLongValue();
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "out of range of long");
+            }
+            BigInteger small = BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.TEN);
+            p = createParser(mode, String.valueOf(small));
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(small, p.getBigIntegerValue());
+            try {
+                p.getLongValue();
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "out of range of long");
+            }
+        }
+    }
+    
+    public void testToBigIntegerCoercion() throws Exception
+    {
+        for (int mode : ALL_STREAMING_MODES) {
+            JsonParser p;
+
+            p = createParser(mode, "1");
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            // int to BigInteger
+            assertEquals(1, p.getIntValue());
+            assertEquals(BigInteger.ONE, p.getBigIntegerValue());
+            p.close();
+
+            p = createParser(mode, "2.0");
+            assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+            // double to BigInteger
+            assertEquals(2.0, p.getDoubleValue());
+            assertEquals(BigInteger.valueOf(2L), p.getBigIntegerValue());
+            p.close();
+            
+            p = createParser(mode, String.valueOf(Long.MAX_VALUE));
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            // long to BigInteger
+            assertEquals(Long.MAX_VALUE, p.getLongValue());
+            assertEquals(BigInteger.valueOf(Long.MAX_VALUE), p.getBigIntegerValue());
+            p.close();
+
+            p = createParser(mode, " 200.0");
+            assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+            // BigDecimal to BigInteger 
+            assertEquals(new BigDecimal("200.0"), p.getDecimalValue());
+            assertEquals(BigInteger.valueOf(200L), p.getBigIntegerValue());
+            p.close();
+        }
+    }
+    
+    /*
+    /**********************************************************
+    /* Numeric coercions, floating point
+    /**********************************************************
+     */
+    
+    public void testToDoubleCoercion() throws Exception
+    {
+        for (int mode : ALL_STREAMING_MODES) {
+            JsonParser p;
+
+            // BigDecimal->double
+            p = createParser(mode, "100.5");
+            assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
+            assertEquals(new BigDecimal("100.5"), p.getDecimalValue());
+            assertEquals(100.5, p.getDoubleValue());
+            p.close();
+
+            p = createParser(mode, "10");
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            assertEquals(BigInteger.TEN, p.getBigIntegerValue());
+            assertEquals(10.0, p.getDoubleValue());
+            p.close();
+        }
+    }
+    
+    public void testToBigDecimalCoercion() throws Exception
+    {
+        for (int mode : ALL_STREAMING_MODES) {
+            JsonParser p;
+
+            p = createParser(mode, "1");
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            // int to BigDecimal
+            assertEquals(1, p.getIntValue());
+            assertEquals(BigDecimal.ONE, p.getDecimalValue());
+            p.close();
+
+            p = createParser(mode, String.valueOf(Long.MAX_VALUE));
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            // long to BigDecimal
+            assertEquals(Long.MAX_VALUE, p.getLongValue());
+            assertEquals(BigDecimal.valueOf(Long.MAX_VALUE), p.getDecimalValue());
+            p.close();
+
+            BigInteger biggie = BigInteger.valueOf(Long.MAX_VALUE).multiply(BigInteger.TEN);
+            p = createParser(mode, String.valueOf(biggie));
+            assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+            // BigInteger to BigDecimal
+            assertEquals(biggie, p.getBigIntegerValue());
+            assertEquals(new BigDecimal(biggie), p.getDecimalValue());
+            p.close();
+
+        }
+    }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/read/NumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/NumberParsingTest.java
index 6c8da43..dab984b 100644
--- a/src/test/java/com/fasterxml/jackson/core/read/NumberParsingTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/read/NumberParsingTest.java
@@ -496,6 +496,7 @@
         }
     }
 
+
     /*
     /**********************************************************
     /* Tests for invalid access
@@ -594,6 +595,19 @@
         assertNull(p.nextToken());
     }
 
+    public void testInvalidNumber() throws Exception {
+        for (int mode : ALL_MODES) {
+            JsonParser p = createParser(mode, " -foo ");
+            try {
+                p.nextToken();
+                fail("Should not pass");
+            } catch (JsonParseException e) {
+                verifyException(e, "Unexpected character ('f'");
+            }
+            p.close();
+        }
+    }
+
     /*
     /**********************************************************
     /* Helper methods
diff --git a/src/test/java/com/fasterxml/jackson/core/read/ParserScopeMatchingTest.java b/src/test/java/com/fasterxml/jackson/core/read/ParserScopeMatchingTest.java
index 55c261c..fbe42fc 100644
--- a/src/test/java/com/fasterxml/jackson/core/read/ParserScopeMatchingTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/read/ParserScopeMatchingTest.java
@@ -25,20 +25,14 @@
         assertToken(JsonToken.START_ARRAY, p.nextToken());
         assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
         assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(2, p.getIntValue());
 
         try {
             p.nextToken();
+            fail("Expected an exception for unclosed ARRAY (mode: "+mode+")");
         } catch (JsonParseException pe) {
             verifyException(pe, "expected close marker for ARRAY");
-            return;
-        } catch (IOException ie) {
-            // DataInput behaves bit differently
-            if (mode == MODE_DATA_INPUT) {
-                verifyException(ie, "end-of-input");
-                return;
-            }
         }
-        fail("Expected an exception for unclosed ARRAY");
     }
 
     public void testUnclosedObject() throws Exception
@@ -57,15 +51,9 @@
 
         try {
             p.nextToken();
-            fail("Expected an exception for unclosed OBJECT");
+            fail("Expected an exception for unclosed OBJECT (mode: "+mode+")");
         } catch (JsonParseException pe) {
             verifyException(pe, "expected close marker for OBJECT");
-        } catch (IOException ie) {
-            // DataInput behaves bit differently
-            if (mode == MODE_DATA_INPUT) {
-                verifyException(ie, "end-of-input");
-                return;
-            }
         }
     }
 
diff --git a/src/test/java/com/fasterxml/jackson/core/read/TrailingCommasTest.java b/src/test/java/com/fasterxml/jackson/core/read/TrailingCommasTest.java
new file mode 100644
index 0000000..5ca9eb3
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/read/TrailingCommasTest.java
@@ -0,0 +1,328 @@
+package com.fasterxml.jackson.core.read;
+
+import com.fasterxml.jackson.core.BaseTest;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonParser.Feature;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.core.json.UTF8DataInputJsonParser;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+public class TrailingCommasTest extends BaseTest {
+
+  private final JsonFactory factory;
+  private final HashSet<JsonParser.Feature> features;
+  private final int mode;
+
+  public TrailingCommasTest(int mode, List<Feature> features) {
+    this.factory = new JsonFactory();
+    this.features = new HashSet<JsonParser.Feature>(features);
+
+    for (JsonParser.Feature feature : features) {
+      factory.enable(feature);
+    }
+
+    this.mode = mode;
+  }
+
+  @Parameterized.Parameters(name = "Mode {0}, Features {1}")
+  public static Collection<Object[]> getTestCases() {
+    ArrayList<Object[]> cases = new ArrayList<Object[]>();
+
+    for (int mode : ALL_MODES) {
+      cases.add(new Object[]{mode, Collections.emptyList()});
+      cases.add(new Object[]{mode, Arrays.asList(Feature.ALLOW_MISSING_VALUES)});
+      cases.add(new Object[]{mode, Arrays.asList(Feature.ALLOW_TRAILING_COMMA)});
+      cases.add(new Object[]{mode, Arrays.asList(Feature.ALLOW_MISSING_VALUES, Feature.ALLOW_TRAILING_COMMA)});
+    }
+
+    return cases;
+  }
+
+  @SuppressWarnings("resource")
+  @Test
+  public void testArrayBasic() throws Exception {
+    String json = "[\"a\", \"b\"]";
+
+    JsonParser p = createParser(factory, mode, json);
+
+    assertEquals(JsonToken.START_ARRAY, p.nextToken());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("a", p.getText());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("b", p.getText());
+
+    assertEquals(JsonToken.END_ARRAY, p.nextToken());
+    assertEnd(p);
+  }
+
+  @SuppressWarnings("resource")
+  @Test
+  public void testArrayInnerComma() throws Exception {
+    String json = "[\"a\",, \"b\"]";
+
+    JsonParser p = createParser(factory, mode, json);
+
+    assertEquals(JsonToken.START_ARRAY, p.nextToken());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("a", p.getText());
+
+    if (!features.contains(Feature.ALLOW_MISSING_VALUES)) {
+      assertUnexpected(p, ',');
+      return;
+    }
+
+    assertToken(JsonToken.VALUE_NULL, p.nextToken());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("b", p.getText());
+
+    assertEquals(JsonToken.END_ARRAY, p.nextToken());
+    assertEnd(p);
+  }
+
+  @SuppressWarnings("resource")
+  @Test
+  public void testArrayLeadingComma() throws Exception {
+    String json = "[,\"a\", \"b\"]";
+
+    JsonParser p = createParser(factory, mode, json);
+
+    assertEquals(JsonToken.START_ARRAY, p.nextToken());
+
+    if (!features.contains(Feature.ALLOW_MISSING_VALUES)) {
+      assertUnexpected(p, ',');
+      return;
+    }
+
+    assertToken(JsonToken.VALUE_NULL, p.nextToken());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("a", p.getText());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("b", p.getText());
+
+    assertEquals(JsonToken.END_ARRAY, p.nextToken());
+    assertEnd(p);
+    p.close();
+  }
+
+  @Test
+  public void testArrayTrailingComma() throws Exception {
+    String json = "[\"a\", \"b\",]";
+
+    JsonParser p = createParser(factory, mode, json);
+
+    assertEquals(JsonToken.START_ARRAY, p.nextToken());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("a", p.getText());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("b", p.getText());
+
+    // ALLOW_TRAILING_COMMA takes priority over ALLOW_MISSING_VALUES
+    if (features.contains(Feature.ALLOW_TRAILING_COMMA)) {
+      assertToken(JsonToken.END_ARRAY, p.nextToken());
+      assertEnd(p);
+    } else if (features.contains(Feature.ALLOW_MISSING_VALUES)) {
+      assertToken(JsonToken.VALUE_NULL, p.nextToken());
+      assertToken(JsonToken.END_ARRAY, p.nextToken());
+      assertEnd(p);
+    } else {
+      assertUnexpected(p, ']');
+    }
+    p.close();
+  }
+
+  @Test
+  public void testArrayTrailingCommas() throws Exception {
+    String json = "[\"a\", \"b\",,]";
+
+    JsonParser p = createParser(factory, mode, json);
+
+    assertEquals(JsonToken.START_ARRAY, p.nextToken());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("a", p.getText());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("b", p.getText());
+
+    // ALLOW_TRAILING_COMMA takes priority over ALLOW_MISSING_VALUES
+    if (features.contains(Feature.ALLOW_MISSING_VALUES) &&
+        features.contains(Feature.ALLOW_TRAILING_COMMA)) {
+      assertToken(JsonToken.VALUE_NULL, p.nextToken());
+      assertToken(JsonToken.END_ARRAY, p.nextToken());
+      assertEnd(p);
+    } else if (features.contains(Feature.ALLOW_MISSING_VALUES)) {
+      assertToken(JsonToken.VALUE_NULL, p.nextToken());
+      assertToken(JsonToken.VALUE_NULL, p.nextToken());
+      assertToken(JsonToken.END_ARRAY, p.nextToken());
+      assertEnd(p);
+    } else {
+      assertUnexpected(p, ',');
+    }
+    p.close();
+  }
+
+  @Test
+  public void testArrayTrailingCommasTriple() throws Exception {
+    String json = "[\"a\", \"b\",,,]";
+
+    JsonParser p = createParser(factory, mode, json);
+
+    assertEquals(JsonToken.START_ARRAY, p.nextToken());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("a", p.getText());
+
+    assertToken(JsonToken.VALUE_STRING, p.nextToken());
+    assertEquals("b", p.getText());
+
+    // ALLOW_TRAILING_COMMA takes priority over ALLOW_MISSING_VALUES
+    if (features.contains(Feature.ALLOW_MISSING_VALUES) &&
+        features.contains(Feature.ALLOW_TRAILING_COMMA)) {
+      assertToken(JsonToken.VALUE_NULL, p.nextToken());
+      assertToken(JsonToken.VALUE_NULL, p.nextToken());
+      assertToken(JsonToken.END_ARRAY, p.nextToken());
+      assertEnd(p);
+    } else if (features.contains(Feature.ALLOW_MISSING_VALUES)) {
+      assertToken(JsonToken.VALUE_NULL, p.nextToken());
+      assertToken(JsonToken.VALUE_NULL, p.nextToken());
+      assertToken(JsonToken.VALUE_NULL, p.nextToken());
+      assertToken(JsonToken.END_ARRAY, p.nextToken());
+      assertEnd(p);
+    } else {
+      assertUnexpected(p, ',');
+    }
+    p.close();
+  }
+
+  @Test
+  public void testObjectBasic() throws Exception {
+    String json = "{\"a\": true, \"b\": false}";
+
+    JsonParser p = createParser(factory, mode, json);
+
+    assertEquals(JsonToken.START_OBJECT, p.nextToken());
+
+    assertToken(JsonToken.FIELD_NAME, p.nextToken());
+    assertEquals("a", p.getText());
+    assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+
+    assertToken(JsonToken.FIELD_NAME, p.nextToken());
+    assertEquals("b", p.getText());
+    assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+
+    assertEquals(JsonToken.END_OBJECT, p.nextToken());
+    assertEnd(p);
+    p.close();
+  }
+
+  @Test
+  public void testObjectInnerComma() throws Exception {
+    String json = "{\"a\": true,, \"b\": false}";
+
+    JsonParser p = createParser(factory, mode, json);
+
+    assertEquals(JsonToken.START_OBJECT, p.nextToken());
+
+    assertToken(JsonToken.FIELD_NAME, p.nextToken());
+    assertEquals("a", p.getText());
+    assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+
+    assertUnexpected(p, ',');
+    p.close();
+  }
+
+  @Test
+  public void testObjectLeadingComma() throws Exception {
+    String json = "{,\"a\": true, \"b\": false}";
+
+    JsonParser p = createParser(factory, mode, json);
+
+    assertEquals(JsonToken.START_OBJECT, p.nextToken());
+
+    assertUnexpected(p, ',');
+    p.close();
+  }
+
+  @Test
+  public void testObjectTrailingComma() throws Exception {
+    String json = "{\"a\": true, \"b\": false,}";
+
+    JsonParser p = createParser(factory, mode, json);
+
+    assertEquals(JsonToken.START_OBJECT, p.nextToken());
+
+    assertToken(JsonToken.FIELD_NAME, p.nextToken());
+    assertEquals("a", p.getText());
+    assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+
+    assertToken(JsonToken.FIELD_NAME, p.nextToken());
+    assertEquals("b", p.getText());
+    assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+
+    if (features.contains(Feature.ALLOW_TRAILING_COMMA)) {
+      assertToken(JsonToken.END_OBJECT, p.nextToken());
+      assertEnd(p);
+    } else {
+      assertUnexpected(p, '}');
+    }
+    p.close();
+  }
+
+  @Test
+  public void testObjectTrailingCommas() throws Exception {
+    String json = "{\"a\": true, \"b\": false,,}";
+
+    JsonParser p = createParser(factory, mode, json);
+
+    assertEquals(JsonToken.START_OBJECT, p.nextToken());
+
+    assertToken(JsonToken.FIELD_NAME, p.nextToken());
+    assertEquals("a", p.getText());
+    assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+
+    assertToken(JsonToken.FIELD_NAME, p.nextToken());
+    assertEquals("b", p.getText());
+    assertToken(JsonToken.VALUE_FALSE, p.nextToken());
+
+    assertUnexpected(p, ',');
+    p.close();
+  }
+
+  private void assertEnd(JsonParser p) throws IOException {
+    // Issue #325
+    if (!(p instanceof UTF8DataInputJsonParser)) {
+      JsonToken next = p.nextToken();
+      assertNull("expected end of stream but found " + next, next);
+    }
+  }
+
+  private void assertUnexpected(JsonParser p, char c) throws IOException {
+    try {
+      p.nextToken();
+      fail("No exception thrown");
+    } catch (Exception e) {
+      verifyException(e, String.format("Unexpected character ('%s' (code %d))", c, (int) c));
+    }
+  }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/testsupport/MockDataInput.java b/src/test/java/com/fasterxml/jackson/core/testsupport/MockDataInput.java
index bdd71b2..11e8f31 100644
--- a/src/test/java/com/fasterxml/jackson/core/testsupport/MockDataInput.java
+++ b/src/test/java/com/fasterxml/jackson/core/testsupport/MockDataInput.java
@@ -42,7 +42,7 @@
     public byte readByte() throws IOException {
         int ch = _input.read();
         if (ch < 0) {
-            throw new IOException("End-of-input for readByte()");
+            throw new EOFException("End-of-input for readByte()");
         }
         return (byte) ch;
     }
diff --git a/src/test/java/com/fasterxml/jackson/core/type/TypeReferenceTest.java b/src/test/java/com/fasterxml/jackson/core/type/TypeReferenceTest.java
index 1bf326b..4dd70d0 100644
--- a/src/test/java/com/fasterxml/jackson/core/type/TypeReferenceTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/type/TypeReferenceTest.java
@@ -7,6 +7,122 @@
 // Not much to test, but exercise to prevent code coverage tool from showing all red for package
 public class TypeReferenceTest extends BaseTest
 {
+    static class BogusResolvedType extends ResolvedType {
+        private final boolean _refType;
+
+        public BogusResolvedType(boolean isRefType) {
+            _refType = isRefType;
+        }
+
+        @Override
+        public Class<?> getRawClass() {
+            return null;
+        }
+
+        @Override
+        public boolean hasRawClass(Class<?> clz) {
+            return false;
+        }
+
+        @Override
+        public boolean isAbstract() {
+            return false;
+        }
+
+        @Override
+        public boolean isConcrete() {
+            return false;
+        }
+
+        @Override
+        public boolean isThrowable() {
+            return false;
+        }
+
+        @Override
+        public boolean isArrayType() {
+            return false;
+        }
+
+        @Override
+        public boolean isEnumType() {
+            return false;
+        }
+
+        @Override
+        public boolean isInterface() {
+            return false;
+        }
+
+        @Override
+        public boolean isPrimitive() {
+            return false;
+        }
+
+        @Override
+        public boolean isFinal() {
+            return false;
+        }
+
+        @Override
+        public boolean isContainerType() {
+            return false;
+        }
+
+        @Override
+        public boolean isCollectionLikeType() {
+            return false;
+        }
+
+        @Override
+        public boolean isMapLikeType() {
+            return false;
+        }
+
+        @Override
+        public boolean hasGenericTypes() {
+            return false;
+        }
+
+        @Override
+        public ResolvedType getKeyType() {
+            return null;
+        }
+
+        @Override
+        public ResolvedType getContentType() {
+            return null;
+        }
+
+        @Override
+        public ResolvedType getReferencedType() {
+            if (_refType) {
+                return this;
+            }
+            return null;
+        }
+
+        @Override
+        public int containedTypeCount() {
+            return 0;
+        }
+
+        @Override
+        public ResolvedType containedType(int index) {
+            return null;
+        }
+
+        @Override
+        public String containedTypeName(int index) {
+            return null;
+        }
+
+        @Override
+        public String toCanonical() {
+            return null;
+        }
+    }
+    
     public void testSimple()
     {
         TypeReference<?> ref = new TypeReference<List<String>>() { };
@@ -24,4 +140,11 @@
             verifyException(e, "without actual type information");
         }
     }
+
+    public void testResolvedType() {
+        ResolvedType type1 = new BogusResolvedType(false);
+        assertFalse(type1.isReferenceType());
+        ResolvedType type2 = new BogusResolvedType(true);
+        assertTrue(type2.isReferenceType());
+    }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java b/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java
index 8fe7db3..e74d715 100644
--- a/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java
+++ b/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java
@@ -1,13 +1,177 @@
 package com.fasterxml.jackson.core.util;
 
 import java.io.*;
+import java.util.Iterator;
 
 import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.JsonParser.NumberType;
+import com.fasterxml.jackson.core.type.ResolvedType;
+import com.fasterxml.jackson.core.type.TypeReference;
 
 public class TestDelegates extends com.fasterxml.jackson.core.BaseTest
 {
+    static class POJO {
+        public int x = 3;
+    }
+
+    static class BogusCodec extends ObjectCodec
+    {
+        public Object pojoWritten;
+        public TreeNode treeWritten;
+
+        @Override
+        public Version version() {
+            return Version.unknownVersion();
+        }
+
+        @Override
+        public <T> T readValue(JsonParser p, Class<T> valueType) {
+            return null;
+        }
+        @Override
+        public <T> T readValue(JsonParser p, TypeReference<?> valueTypeRef) {
+            return null;
+        }
+        @Override
+        public <T> T readValue(JsonParser p, ResolvedType valueType) {
+            return null;
+        }
+        @Override
+        public <T> Iterator<T> readValues(JsonParser p, Class<T> valueType) {
+            return null;
+        }
+        @Override
+        public <T> Iterator<T> readValues(JsonParser p,
+                TypeReference<?> valueTypeRef) throws IOException {
+            return null;
+        }
+        @Override
+        public <T> Iterator<T> readValues(JsonParser p, ResolvedType valueType) {
+            return null;
+        }
+        @Override
+        public void writeValue(JsonGenerator gen, Object value) throws IOException {
+            gen.writeString("pojo");
+            pojoWritten = value;
+        }
+
+        @Override
+        public <T extends TreeNode> T readTree(JsonParser p) {
+            return null;
+        }
+        @Override
+        public void writeTree(JsonGenerator gen, TreeNode tree) throws IOException {
+            gen.writeString("tree");
+            treeWritten = tree;
+        }
+
+        @Override
+        public TreeNode createObjectNode() {
+            return null;
+        }
+        @Override
+        public TreeNode createArrayNode() {
+            return null;
+        }
+        @Override
+        public JsonParser treeAsTokens(TreeNode n) {
+            return null;
+        }
+        @Override
+        public <T> T treeToValue(TreeNode n, Class<T> valueType) {
+            return null;
+        } 
+    }
+
+    static class BogusTree implements TreeNode {
+        @Override
+        public JsonToken asToken() {
+            return null;
+        }
+
+        @Override
+        public NumberType numberType() {
+            return null;
+        }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public boolean isValueNode() {
+            return false;
+        }
+
+        @Override
+        public boolean isContainerNode() {
+            return false;
+        }
+
+        @Override
+        public boolean isMissingNode() {
+            return false;
+        }
+
+        @Override
+        public boolean isArray() {
+            return false;
+        }
+
+        @Override
+        public boolean isObject() {
+            return false;
+        }
+
+        @Override
+        public TreeNode get(String fieldName) {
+            return null;
+        }
+
+        @Override
+        public TreeNode get(int index) {
+            return null;
+        }
+
+        @Override
+        public TreeNode path(String fieldName) {
+            return null;
+        }
+
+        @Override
+        public TreeNode path(int index) {
+            return null;
+        }
+
+        @Override
+        public Iterator<String> fieldNames() {
+            return null;
+        }
+
+        @Override
+        public TreeNode at(JsonPointer ptr) {
+            return null;
+        }
+
+        @Override
+        public TreeNode at(String jsonPointerExpression) {
+            return null;
+        }
+
+        @Override
+        public JsonParser traverse() {
+            return null;
+        }
+
+        @Override
+        public JsonParser traverse(ObjectCodec codec) {
+            return null;
+        }
+    }
+
     private final JsonFactory JSON_F = new JsonFactory();
-    
+
     /**
      * Test default, non-overridden parser delegate.
      */
@@ -94,7 +258,7 @@
         StringWriter sw = new StringWriter();
         JsonGenerator jg = new JsonGeneratorDelegate(JSON_F.createGenerator(sw), false) {
             @Override
-            public void writeFieldName(String name) throws IOException, JsonGenerationException {
+            public void writeFieldName(String name) throws IOException {
                 super.writeFieldName(name+"-test");
                 super.writeBoolean(true);
                 super.writeFieldName(name);
@@ -107,4 +271,26 @@
         jp.close();
         jg.close();
     }
+
+    @SuppressWarnings("resource")
+    public void testGeneratorWithCodec() throws IOException
+    {
+        BogusCodec codec = new BogusCodec();
+        StringWriter sw = new StringWriter();
+        JsonGenerator g0 = JSON_F.createGenerator(sw);
+        g0.setCodec(codec);
+        JsonGeneratorDelegate del = new JsonGeneratorDelegate(g0, false);
+        del.writeStartArray();
+        POJO pojo = new POJO();
+        del.writeObject(pojo);
+        TreeNode tree = new BogusTree();
+        del.writeTree(tree);
+        del.writeEndArray();
+        del.close();
+
+        assertEquals("[\"pojo\",\"tree\"]", sw.toString());
+
+        assertSame(tree, codec.treeWritten);
+        assertSame(pojo, codec.pojoWritten);
+    }
 }
diff --git a/src/test/java/com/fasterxml/jackson/core/util/TestTextBuffer.java b/src/test/java/com/fasterxml/jackson/core/util/TestTextBuffer.java
index ab1d23a..997a7cb 100644
--- a/src/test/java/com/fasterxml/jackson/core/util/TestTextBuffer.java
+++ b/src/test/java/com/fasterxml/jackson/core/util/TestTextBuffer.java
@@ -13,6 +13,9 @@
         tb.append('a');
         tb.append(new char[] { 'X', 'b' }, 1, 1);
         tb.append("c", 0, 1);
+        // all fits within one buffer so it is efficient...
+        assertTrue(tb.hasTextAsCharacters());
+
         assertEquals(3, tb.contentsAsArray().length);
         assertEquals("abc", tb.toString());
 
@@ -21,7 +24,7 @@
 
     public void testLonger()
     {
-        TextBuffer tb = new TextBuffer(new BufferRecycler());
+        TextBuffer tb = new TextBuffer(null);
         for (int i = 0; i < 2000; ++i) {
             tb.append("abc", 0, 3);
         }
@@ -31,51 +34,54 @@
 
         tb.resetWithShared(new char[] { 'a' }, 0, 1);
         assertEquals(1, tb.toString().length());
+        assertTrue(tb.hasTextAsCharacters());
     }
 
-      public void testLongAppend()
-      {
-          final int len = TextBuffer.MAX_SEGMENT_LEN * 3 / 2;
-          StringBuilder sb = new StringBuilder(len);
-          for (int i = 0; i < len; ++i) {
-              sb.append('x');
-          }
-         final String STR = sb.toString();
-         final String EXP = "a" + STR + "c";
+    public void testLongAppend()
+    {
+        final int len = TextBuffer.MAX_SEGMENT_LEN * 3 / 2;
+        StringBuilder sb = new StringBuilder(len);
+        for (int i = 0; i < len; ++i) {
+            sb.append('x');
+        }
+        final String STR = sb.toString();
+        final String EXP = "a" + STR + "c";
  
-         // ok: first test with String:
-         TextBuffer tb = new TextBuffer(new BufferRecycler());
-         tb.append('a');
-         tb.append(STR, 0, len);
-         tb.append('c');
-         assertEquals(len+2, tb.size());
-         assertEquals(EXP, tb.contentsAsString());
+        // ok: first test with String:
+        TextBuffer tb = new TextBuffer(new BufferRecycler());
+        tb.append('a');
+        tb.append(STR, 0, len);
+        tb.append('c');
+        assertEquals(len+2, tb.size());
+        assertEquals(EXP, tb.contentsAsString());
  
-         // then char[]
-         tb = new TextBuffer(new BufferRecycler());
-         tb.append('a');
-         tb.append(STR.toCharArray(), 0, len);
-         tb.append('c');
-         assertEquals(len+2, tb.size());
-         assertEquals(EXP, tb.contentsAsString());
-      }
+        // then char[]
+        tb = new TextBuffer(new BufferRecycler());
+        tb.append('a');
+        tb.append(STR.toCharArray(), 0, len);
+        tb.append('c');
+        assertEquals(len+2, tb.size());
+        assertEquals(EXP, tb.contentsAsString());
+    }
 
-      // [Core#152]
-      public void testExpand()
-      {
-          TextBuffer tb = new TextBuffer(new BufferRecycler());
-          char[] buf = tb.getCurrentSegment();
+    // [core#152]
+    public void testExpand()
+    {
+        TextBuffer tb = new TextBuffer(new BufferRecycler());
+        char[] buf = tb.getCurrentSegment();
 
-          while (buf.length < 500 * 1000) {
-              char[] old = buf;
-              buf = tb.expandCurrentSegment();
-              if (old.length >= buf.length) {
-                  fail("Expected buffer of "+old.length+" to expand, did not, length now "+buf.length);
-              }
-          }
-      }
+        while (buf.length < 500 * 1000) {
+            char[] old = buf;
+            buf = tb.expandCurrentSegment();
+            if (old.length >= buf.length) {
+                fail("Expected buffer of "+old.length+" to expand, did not, length now "+buf.length);
+            }
+        }
+        tb.resetWithString("Foobar");
+        assertEquals("Foobar", tb.contentsAsString());
+    }
 
-    // [Core#182]
+    // [core#182]
     public void testEmpty() {
         TextBuffer tb = new TextBuffer(new BufferRecycler());
         tb.resetWithEmpty();
diff --git a/src/test/java/com/fasterxml/jackson/failing/TokenVerifyingParserFiltering330Test.java b/src/test/java/com/fasterxml/jackson/failing/TokenVerifyingParserFiltering330Test.java
new file mode 100644
index 0000000..88cf4de
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/failing/TokenVerifyingParserFiltering330Test.java
@@ -0,0 +1,137 @@
+package com.fasterxml.jackson.failing;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.JsonParser.NumberType;
+import com.fasterxml.jackson.core.filter.FilteringParserDelegate;
+import com.fasterxml.jackson.core.filter.TokenFilter;
+
+// Tests for [core#330]
+public class TokenVerifyingParserFiltering330Test extends BaseTest
+{
+    static class NameMatchFilter extends TokenFilter
+    {
+        private final Set<String> _names;
+        
+        public NameMatchFilter(String... names) {
+            _names = new HashSet<String>(Arrays.asList(names));
+        }
+
+        @Override
+        public TokenFilter includeElement(int index) {
+            return this;
+        }
+
+        @Override
+        public TokenFilter includeProperty(String name) {
+            if (_names.contains(name)) {
+                return TokenFilter.INCLUDE_ALL;
+            }
+            return this;
+        }
+
+        @Override
+        protected boolean _includeScalar() { return false; }
+    }
+
+    /*
+    /**********************************************************
+    /* Test methods
+    /**********************************************************
+     */
+
+    private final JsonFactory JSON_F = new JsonFactory();
+
+    private final String SIMPLE = aposToQuotes("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}");
+    
+    @SuppressWarnings("resource")
+    public void testBasicSingleMatchFilteringWithPath() throws Exception
+    {
+        JsonParser p0 = JSON_F.createParser(SIMPLE);
+        JsonParser p = new FilteringParserDelegate(p0,
+               new NameMatchFilter("value"),
+                   true, // includePath
+                   false // multipleMatches
+                );
+
+// {'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}
+        String result = readAndWrite(JSON_F, p);
+        assertEquals(aposToQuotes("{'ob':{'value':3}}"), result);
+    }
+    
+    @SuppressWarnings("resource")
+    public void testTokensSingleMatchWithPath() throws Exception
+    {
+        JsonParser p0 = JSON_F.createParser(SIMPLE);
+        JsonParser p = new FilteringParserDelegate(p0,
+               new NameMatchFilter("value"),
+                   true, // includePath
+                   false // multipleMatches
+                );
+
+        assertFalse(p.hasCurrentToken());
+        assertNull(p.getCurrentToken());
+        assertEquals(JsonTokenId.ID_NO_TOKEN, p.getCurrentTokenId());
+        assertFalse(p.isExpectedStartObjectToken());
+        assertFalse(p.isExpectedStartArrayToken());
+        
+// {'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}
+//      String result = readAndWrite(JSON_F, p);
+//      assertEquals(aposToQuotes("{'ob':{'value':3}}"), result);
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertEquals(JsonToken.START_OBJECT, p.getCurrentToken());
+        assertTrue(p.isExpectedStartObjectToken());
+        assertFalse(p.isExpectedStartArrayToken());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals(JsonToken.FIELD_NAME, p.getCurrentToken());
+        assertEquals("ob", p.getCurrentName());
+//        assertEquals("ob", p.getText());
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        assertEquals("ob", p.getCurrentName());
+
+        assertToken(JsonToken.FIELD_NAME, p.nextToken());
+        assertEquals("value", p.getCurrentName());
+        assertEquals("value", p.getText());
+
+        assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+        assertEquals(JsonToken.VALUE_NUMBER_INT, p.getCurrentToken());
+        assertEquals(NumberType.INT, p.getNumberType());
+        assertEquals(3, p.getIntValue());
+        assertEquals("value", p.getCurrentName());
+
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        assertEquals(JsonToken.END_OBJECT, p.getCurrentToken());
+
+        assertToken(JsonToken.END_OBJECT, p.nextToken());
+        assertEquals(JsonToken.END_OBJECT, p.getCurrentToken());
+
+        p.clearCurrentToken();
+        assertNull(p.getCurrentToken());
+        
+        p.close();
+    }
+
+    @SuppressWarnings("resource")
+    public void testSkippingForSingleWithPath() throws Exception
+    {
+        JsonParser p0 = JSON_F.createParser(SIMPLE);
+        JsonParser p = new FilteringParserDelegate(p0,
+               new NameMatchFilter("value"),
+                   true, // includePath
+                   false // multipleMatches
+                );
+
+//        assertEquals(aposToQuotes("{'ob':{'value':3}}"), result);
+
+        assertToken(JsonToken.START_OBJECT, p.nextToken());
+        p.skipChildren();
+        assertEquals(JsonToken.END_OBJECT, p.getCurrentToken());
+        assertNull(p.nextToken());
+    }
+}