Index: trunk/src/org/glassfish/json/BufferPoolImpl.java
===================================================================
--- trunk/src/org/glassfish/json/BufferPoolImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/BufferPoolImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -82,6 +82,6 @@
 
         // overwrite the queue
-        ConcurrentLinkedQueue<char[]> d = new ConcurrentLinkedQueue<char[]>();
-        queue = new WeakReference<ConcurrentLinkedQueue<char[]>>(d);
+        ConcurrentLinkedQueue<char[]> d = new ConcurrentLinkedQueue<>();
+        queue = new WeakReference<>(d);
 
         return d;
Index: trunk/src/org/glassfish/json/JsonArrayBuilderImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonArrayBuilderImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonArrayBuilderImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -49,12 +49,16 @@
 import java.util.AbstractList;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 /**
- * JsonArrayBuilder impl
+ * JsonArrayBuilder implementation
  *
  * @author Jitendra Kotamraju
+ * @author Kin-man Chung
  */
+
 class JsonArrayBuilderImpl implements JsonArrayBuilder {
     private ArrayList<JsonValue> valueList;
@@ -65,4 +69,17 @@
     }
 
+    JsonArrayBuilderImpl(JsonArray array, BufferPool bufferPool) {
+        this.bufferPool = bufferPool;
+        valueList = new ArrayList<>();
+        valueList.addAll(array);
+    }
+
+    JsonArrayBuilderImpl(Collection<?> collection, BufferPool bufferPool) {
+        this.bufferPool = bufferPool;
+        valueList = new ArrayList<>();
+        populate(collection);
+    }
+
+    @Override
     public JsonArrayBuilder add(JsonValue value) {
         validateValue(value);
@@ -71,4 +88,5 @@
     }
 
+    @Override
     public JsonArrayBuilder add(String value) {
         validateValue(value);
@@ -77,4 +95,5 @@
     }
 
+    @Override
     public JsonArrayBuilder add(BigDecimal value) {
         validateValue(value);
@@ -83,4 +102,5 @@
     }
 
+    @Override
     public JsonArrayBuilder add(BigInteger value) {
         validateValue(value);
@@ -89,4 +109,5 @@
     }
 
+    @Override
     public JsonArrayBuilder add(int value) {
         addValueList(JsonNumberImpl.getJsonNumber(value));
@@ -94,4 +115,5 @@
     }
 
+    @Override
     public JsonArrayBuilder add(long value) {
         addValueList(JsonNumberImpl.getJsonNumber(value));
@@ -99,4 +121,5 @@
     }
 
+    @Override
     public JsonArrayBuilder add(double value) {
         addValueList(JsonNumberImpl.getJsonNumber(value));
@@ -104,4 +127,5 @@
     }
 
+    @Override
     public JsonArrayBuilder add(boolean value) {
         addValueList(value ? JsonValue.TRUE : JsonValue.FALSE);
@@ -109,4 +133,5 @@
     }
 
+    @Override
     public JsonArrayBuilder addNull() {
         addValueList(JsonValue.NULL);
@@ -114,4 +139,5 @@
     }
 
+    @Override
     public JsonArrayBuilder add(JsonObjectBuilder builder) {
         if (builder == null) {
@@ -122,4 +148,5 @@
     }
 
+    @Override
     public JsonArrayBuilder add(JsonArrayBuilder builder) {
         if (builder == null) {
@@ -130,4 +157,178 @@
     }
 
+    @Override
+    public JsonArrayBuilder addAll(JsonArrayBuilder builder) {
+        if (builder == null) {
+            throw new NullPointerException(JsonMessages.ARRBUILDER_ARRAY_BUILDER_NULL());
+        }
+        if (valueList == null) {
+            valueList = new ArrayList<>();
+        }
+        valueList.addAll(builder.build());
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(int index, JsonValue value) {
+        validateValue(value);
+        addValueList(index, value);
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(int index, String value) {
+        validateValue(value);
+        addValueList(index, new JsonStringImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(int index, BigDecimal value) {
+        validateValue(value);
+        addValueList(index, JsonNumberImpl.getJsonNumber(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(int index, BigInteger value) {
+        validateValue(value);
+        addValueList(index, JsonNumberImpl.getJsonNumber(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(int index, int value) {
+        addValueList(index, JsonNumberImpl.getJsonNumber(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(int index, long value) {
+        addValueList(index, JsonNumberImpl.getJsonNumber(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(int index, double value) {
+        addValueList(index, JsonNumberImpl.getJsonNumber(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(int index, boolean value) {
+        addValueList(index, value ? JsonValue.TRUE : JsonValue.FALSE);
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder addNull(int index) {
+        addValueList(index, JsonValue.NULL);
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(int index, JsonObjectBuilder builder) {
+        if (builder == null) {
+            throw new NullPointerException(JsonMessages.ARRBUILDER_OBJECT_BUILDER_NULL());
+        }
+        addValueList(index, builder.build());
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(int index, JsonArrayBuilder builder) {
+        if (builder == null) {
+            throw new NullPointerException(JsonMessages.ARRBUILDER_OBJECT_BUILDER_NULL());
+        }
+        addValueList(index, builder.build());
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder set(int index, JsonValue value) {
+        validateValue(value);
+        setValueList(index, value);
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder set(int index, String value) {
+        validateValue(value);
+        setValueList(index, new JsonStringImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder set(int index, BigDecimal value) {
+        validateValue(value);
+        setValueList(index, JsonNumberImpl.getJsonNumber(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder set(int index, BigInteger value) {
+        validateValue(value);
+        setValueList(index, JsonNumberImpl.getJsonNumber(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder set(int index, int value) {
+        setValueList(index, JsonNumberImpl.getJsonNumber(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder set(int index, long value) {
+        setValueList(index, JsonNumberImpl.getJsonNumber(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder set(int index, double value) {
+        setValueList(index, JsonNumberImpl.getJsonNumber(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder set(int index, boolean value) {
+        setValueList(index, value ? JsonValue.TRUE : JsonValue.FALSE);
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder setNull(int index) {
+        setValueList(index, JsonValue.NULL);
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder set(int index, JsonObjectBuilder builder) {
+        if (builder == null) {
+            throw new NullPointerException(JsonMessages.ARRBUILDER_OBJECT_BUILDER_NULL());
+        }
+        setValueList(index, builder.build());
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder set(int index, JsonArrayBuilder builder) {
+        if (builder == null) {
+            throw new NullPointerException(JsonMessages.ARRBUILDER_OBJECT_BUILDER_NULL());
+        }
+        setValueList(index, builder.build());
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder remove(int index) {
+        if (valueList == null) {
+            throw new IndexOutOfBoundsException(JsonMessages.ARRBUILDER_VALUELIST_NULL(index, 0));
+        }
+        valueList.remove(index);
+        return this;
+    }
+
+    @Override
     public JsonArray build() {
         List<JsonValue> snapshot;
@@ -143,9 +344,34 @@
     }
 
+    private void populate(Collection<?> collection) {
+        for (Object value : collection) {
+            if (value != null && value instanceof Optional) {
+                ((Optional<?>) value).ifPresent(v ->
+                        this.valueList.add(MapUtil.handle(v, bufferPool)));
+            } else {
+                this.valueList.add(MapUtil.handle(value, bufferPool));
+            }
+        }
+    }
+
     private void addValueList(JsonValue value) {
         if (valueList == null) {
-            valueList = new ArrayList<JsonValue>();
+            valueList = new ArrayList<>();
         }
         valueList.add(value);
+    }
+
+    private void addValueList(int index, JsonValue value) {
+        if (valueList == null) {
+            valueList = new ArrayList<>();
+        }
+        valueList.add(index, value);
+    }
+
+    private void setValueList(int index, JsonValue value) {
+        if (valueList == null) {
+            throw new IndexOutOfBoundsException(JsonMessages.ARRBUILDER_VALUELIST_NULL(index, 0));
+        }
+        valueList.set(index, value);
     }
 
@@ -263,13 +489,15 @@
         public String toString() {
             StringWriter sw = new StringWriter();
-            JsonWriter jw = new JsonWriterImpl(sw, bufferPool);
-            jw.write(this);
-            jw.close();
+            try (JsonWriter jw = new JsonWriterImpl(sw, bufferPool)) {
+                jw.write(this);
+            }
             return sw.toString();
         }
-    }
-
+
+        @Override
+        public JsonArray asJsonArray() {
+            return this;
+        }
+    }
 }
 
-
-
Index: trunk/src/org/glassfish/json/JsonBuilderFactoryImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonBuilderFactoryImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonBuilderFactoryImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -41,6 +41,9 @@
 package org.glassfish.json;
 
+import java.util.Collection;
 import org.glassfish.json.api.BufferPool;
 
+import javax.json.JsonObject;
+import javax.json.JsonArray;
 import javax.json.JsonArrayBuilder;
 import javax.json.JsonBuilderFactory;
@@ -65,4 +68,14 @@
         return new JsonObjectBuilderImpl(bufferPool);
     }
+ 
+    @Override
+    public JsonObjectBuilder createObjectBuilder(JsonObject object) {
+        return new JsonObjectBuilderImpl(object, bufferPool);
+    }
+
+    @Override
+    public JsonObjectBuilder createObjectBuilder(Map<String, Object> object) {
+        return new JsonObjectBuilderImpl(object, bufferPool);
+    }
 
     @Override
@@ -72,4 +85,14 @@
 
     @Override
+    public JsonArrayBuilder createArrayBuilder(JsonArray array) {
+        return new JsonArrayBuilderImpl(array, bufferPool);
+    }
+
+    @Override
+    public JsonArrayBuilder createArrayBuilder(Collection<?> collection) {
+        return new JsonArrayBuilderImpl(collection, bufferPool);
+    }
+
+    @Override
     public Map<String, ?> getConfigInUse() {
         return config;
Index: trunk/src/org/glassfish/json/JsonGeneratorFactoryImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonGeneratorFactoryImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonGeneratorFactoryImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
Index: trunk/src/org/glassfish/json/JsonGeneratorImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonGeneratorImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonGeneratorImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -50,4 +50,5 @@
 import java.math.BigInteger;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayDeque;
 import java.util.Deque;
@@ -58,5 +59,4 @@
  */
 class JsonGeneratorImpl implements JsonGenerator {
-    private static final Charset UTF_8 = Charset.forName("UTF-8");
 
     private static final char[] INT_MIN_VALUE_CHARS = "-2147483648".toCharArray();
@@ -101,4 +101,5 @@
         IN_NONE,
         IN_OBJECT,
+        IN_FIELD,
         IN_ARRAY
     }
@@ -107,5 +108,5 @@
     private final Writer writer;
     private Context currentContext = new Context(Scope.IN_NONE);
-    private final Deque<Context> stack = new ArrayDeque<Context>();
+    private final Deque<Context> stack = new ArrayDeque<>();
 
     // Using own buffering mechanism as JDK's BufferedWriter uses synchronized
@@ -122,5 +123,5 @@
 
     JsonGeneratorImpl(OutputStream out, BufferPool bufferPool) {
-        this(out, UTF_8, bufferPool);
+        this(out, StandardCharsets.UTF_8, bufferPool);
     }
 
@@ -170,5 +171,5 @@
         writeComma();
         writeEscapedString(name);
-        writeChar(':');
+        writeColon();
         return this;
     }
@@ -267,8 +268,6 @@
     @Override
     public JsonGenerator write(JsonValue value) {
-        if (currentContext.scope != Scope.IN_ARRAY) {
-            throw new JsonGenerationException(
-                    JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
-        }
+        checkContextForValue();
+
         switch (value.getValueType()) {
             case ARRAY:
@@ -295,4 +294,5 @@
                 JsonNumber number = (JsonNumber)value;
                 writeValue(number.toString());
+                popFieldContext();
                 break;
             case TRUE:
@@ -382,22 +382,20 @@
     }
 
+    @Override
     public JsonGenerator write(String value) {
-        if (currentContext.scope != Scope.IN_ARRAY) {
-            throw new JsonGenerationException(
-                    JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
-        }
+        checkContextForValue();
         writeComma();
         writeEscapedString(value);
-        return this;
-    }
-
-
+        popFieldContext();
+        return this;
+    }
+
+
+    @Override
     public JsonGenerator write(int value) {
-        if (currentContext.scope != Scope.IN_ARRAY) {
-            throw new JsonGenerationException(
-                    JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
-        }
+        checkContextForValue();
         writeComma();
         writeInt(value);
+        popFieldContext();
         return this;
     }
@@ -405,9 +403,7 @@
     @Override
     public JsonGenerator write(long value) {
-        if (currentContext.scope != Scope.IN_ARRAY) {
-            throw new JsonGenerationException(
-                    JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
-        }
+        checkContextForValue();
         writeValue(String.valueOf(value));
+        popFieldContext();
         return this;
     }
@@ -415,12 +411,10 @@
     @Override
     public JsonGenerator write(double value) {
-        if (currentContext.scope != Scope.IN_ARRAY) {
-            throw new JsonGenerationException(
-                    JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
-        }
+        checkContextForValue();
         if (Double.isInfinite(value) || Double.isNaN(value)) {
             throw new NumberFormatException(JsonMessages.GENERATOR_DOUBLE_INFINITE_NAN());
         }
         writeValue(String.valueOf(value));
+        popFieldContext();
         return this;
     }
@@ -428,39 +422,48 @@
     @Override
     public JsonGenerator write(BigInteger value) {
-        if (currentContext.scope != Scope.IN_ARRAY) {
-            throw new JsonGenerationException(
-                    JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
-        }
+        checkContextForValue();
         writeValue(value.toString());
-        return this;
+        popFieldContext();
+        return this;
+    }
+
+    private void checkContextForValue() {
+        if ((!currentContext.first && currentContext.scope != Scope.IN_ARRAY && currentContext.scope != Scope.IN_FIELD)
+                || (currentContext.first && currentContext.scope == Scope.IN_OBJECT)) {
+            throw new JsonGenerationException(
+                    JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
+        }
     }
 
     @Override
     public JsonGenerator write(BigDecimal value) {
-        if (currentContext.scope != Scope.IN_ARRAY) {
-            throw new JsonGenerationException(
-                    JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
-        }
+        checkContextForValue();
         writeValue(value.toString());
-        return this;
-    }
-
+        popFieldContext();
+
+        return this;
+    }
+
+    private void popFieldContext() {
+        if (currentContext.scope == Scope.IN_FIELD) {
+            currentContext = stack.pop();
+        }
+    }
+
+    @Override
     public JsonGenerator write(boolean value) {
-        if (currentContext.scope != Scope.IN_ARRAY) {
-            throw new JsonGenerationException(
-                    JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
-        }
+        checkContextForValue();
         writeComma();
         writeString(value ? "true" : "false");
-        return this;
-    }
-
+        popFieldContext();
+        return this;
+    }
+
+    @Override
     public JsonGenerator writeNull() {
-        if (currentContext.scope != Scope.IN_ARRAY) {
-            throw new JsonGenerationException(
-                    JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
-        }
+        checkContextForValue();
         writeComma();
         writeString("null");
+        popFieldContext();
         return this;
     }
@@ -474,6 +477,19 @@
         writeComma();
         writeEscapedString(name);
-        writeChar(':');
+        writeColon();
         writeString(value);
+    }
+
+    @Override
+    public JsonGenerator writeKey(String name) {
+        if (currentContext.scope != Scope.IN_OBJECT) {
+            throw new JsonGenerationException(
+                    JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
+        }
+        writeName(name);
+        stack.push(currentContext);
+        currentContext = new Context(Scope.IN_FIELD);
+        currentContext.first = false;
+        return this;
     }
 
@@ -485,12 +501,17 @@
         writeChar(currentContext.scope == Scope.IN_ARRAY ? ']' : '}');
         currentContext = stack.pop();
+        popFieldContext();
         return this;
     }
 
     protected void writeComma() {
-        if (!currentContext.first) {
+        if (!currentContext.first && currentContext.scope != Scope.IN_FIELD) {
             writeChar(',');
         }
         currentContext.first = false;
+    }
+
+    protected void writeColon() {
+        writeChar(':');
     }
 
@@ -505,4 +526,5 @@
     }
 
+    @Override
     public void close() {
         if (currentContext.scope != Scope.IN_NONE || currentContext.first) {
Index: trunk/src/org/glassfish/json/JsonLocationImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonLocationImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonLocationImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -74,4 +74,5 @@
     }
 
+    @Override
     public String toString() {
         return "(line no="+lineNo+", column no="+columnNo+", offset="+ offset +")";
Index: trunk/src/org/glassfish/json/JsonMergePatchImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonMergePatchImpl.java	(revision 13231)
+++ trunk/src/org/glassfish/json/JsonMergePatchImpl.java	(revision 13231)
@@ -0,0 +1,142 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2015-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package org.glassfish.json;
+
+import javax.json.Json;
+import javax.json.JsonMergePatch;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonValue;
+
+/**
+ * This class is an implementation of a JSON Merge Patch as specified in
+ * <a href="http://tools.ietf.org/html/rfc7396">RFC 7396</a>.
+ *
+ * @since 1.1
+ */
+
+public final class JsonMergePatchImpl implements JsonMergePatch {
+
+    private JsonValue patch;
+
+    public JsonMergePatchImpl(JsonValue patch) {
+        this.patch = patch;
+    }
+
+    @Override
+    public JsonValue apply(JsonValue target) {
+        return mergePatch(target, patch);
+    }
+
+    @Override
+    public JsonValue toJsonValue() {
+        return patch;
+    }
+    /**
+     * Applies the specified patch to the specified target.
+     * The target is not modified by the patch.
+     *
+     * @param target the {@code JsonValue} to apply the patch operations
+     * @param patch the patch
+     * @return the {@code JsonValue} as the result of applying the patch
+     *    operations on the target.
+     */
+    private static JsonValue mergePatch(JsonValue target, JsonValue patch) {
+
+        if (patch.getValueType() != JsonValue.ValueType.OBJECT) {
+            return patch;
+        }
+        if (target.getValueType() != JsonValue.ValueType.OBJECT) {
+            target = JsonValue.EMPTY_JSON_OBJECT;
+        }
+        JsonObject targetJsonObject = target.asJsonObject();
+        JsonObjectBuilder builder =
+            Json.createObjectBuilder(targetJsonObject);
+        patch.asJsonObject().forEach((key, value) -> {
+            if (value == JsonValue.NULL) {
+                if (targetJsonObject.containsKey(key)) {
+                    builder.remove(key);
+                }
+            } else if (targetJsonObject.containsKey(key)) {
+                builder.add(key, mergePatch(targetJsonObject.get(key), value));
+            } else {
+                builder.add(key, mergePatch(JsonValue.EMPTY_JSON_OBJECT, value));
+            }
+        });
+        return builder.build();
+    }
+
+    /**
+     * Generate a JSON Merge Patch from the source and target {@code JsonValue}.
+     * @param source the source
+     * @param target the target
+     * @return a JSON Patch which when applied to the source, yields the target
+     */
+    static JsonValue diff(JsonValue source, JsonValue target) {
+        if (source.getValueType() != JsonValue.ValueType.OBJECT ||
+                target.getValueType() != JsonValue.ValueType.OBJECT) {
+            return target;
+        }
+        JsonObject s = (JsonObject) source;
+        JsonObject t = (JsonObject) target;
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        // First find members to be replaced or removed
+        s.forEach((key, value) -> {
+            if (t.containsKey(key)) {
+                // key present in both.
+                if (! value.equals(t.get(key))) {
+                    // If the values are equal, nop, else get diff for the values
+                    builder.add(key, diff(value, t.get(key)));
+                }
+            } else {
+                builder.addNull(key);
+            }
+        });
+        // Then find members to be added
+        t.forEach((key, value) -> {
+            if (! s.containsKey(key))
+                builder.add(key, value);
+        });
+        return builder.build();
+    }
+
+}
+
Index: trunk/src/org/glassfish/json/JsonMessages.java
===================================================================
--- trunk/src/org/glassfish/json/JsonMessages.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonMessages.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -46,4 +46,6 @@
 import java.text.MessageFormat;
 import java.util.ResourceBundle;
+import javax.json.JsonObject;
+import javax.json.JsonValue;
 
 /**
@@ -56,4 +58,9 @@
             ResourceBundle.getBundle("org.glassfish.json.messages");
 
+    // global/shared messages
+    static String INTERNAL_ERROR() {
+        return localize("internal.error");
+    }
+
     // tokenizer messages
     static String TOKENIZER_UNEXPECTED_CHAR(int unexpected, JsonLocation location) {
@@ -91,4 +98,20 @@
     }
 
+    static String PARSER_GETARRAY_ERR(JsonParser.Event event) {
+        return localize("parser.getArray.err", event);
+    }
+
+    static String PARSER_GETOBJECT_ERR(JsonParser.Event event) {
+        return localize("parser.getObject.err", event);
+    }
+
+    static String PARSER_GETVALUE_ERR(JsonParser.Event event) {
+        return localize("parser.getValue.err", event);
+    }
+
+    static String PARSER_GETVALUESTREAM_ERR() {
+        return localize("parser.getValueStream.err");
+    }
+
     static String PARSER_EXPECTED_EOF(JsonTokenizer.JsonToken token) {
         return localize("parser.expected.eof", token);
@@ -103,4 +126,19 @@
     }
 
+    static String PARSER_STATE_ERR(JsonValue.ValueType type) {
+        return localize("parser.state.err", type);
+    }
+
+    static String PARSER_SCOPE_ERR(JsonValue value) {
+        return localize("parser.scope.err", value);
+    }
+
+    static String PARSER_INPUT_ENC_DETECT_FAILED() {
+        return localize("parser.input.enc.detect.failed");
+    }
+
+    static String PARSER_INPUT_ENC_DETECT_IOERR() {
+        return localize("parser.input.enc.detect.ioerr");
+    }
 
     // generator messages
@@ -140,5 +178,4 @@
     }
 
-
     // reader messages
     static String READER_READ_ALREADY_CALLED() {
@@ -146,12 +183,4 @@
     }
 
-    static String READER_EXPECTED_ARRAY_GOT_OBJECT() {
-        return localize("reader.expected.array.got.object");
-    }
-
-    static String READER_EXPECTED_OBJECT_GOT_ARRAY() {
-        return localize("reader.expected.object.got.array");
-    }
-
 
     // obj builder messages
@@ -184,4 +213,71 @@
     static String ARRBUILDER_ARRAY_BUILDER_NULL() {
         return localize("arrbuilder.array.builder.null");
+    }
+
+    static String ARRBUILDER_VALUELIST_NULL(int index, int size) {
+        return localize("arrbuilder.valuelist.null", index, size);
+    }
+
+    // json pointer messages
+    static String POINTER_FORMAT_INVALID() {
+        return localize("pointer.format.invalid");
+    }
+
+    static String POINTER_MAPPING_MISSING(JsonObject object, String key) {
+        return localize("pointer.mapping.missing", object, key);
+    }
+
+    static String POINTER_REFERENCE_INVALID(JsonValue.ValueType type) {
+        return localize("pointer.reference.invalid", type.name());
+    }
+
+    static String POINTER_ARRAY_INDEX_ERR(String token) {
+        return localize("pointer.array.index.err", token);
+    }
+
+    static String POINTER_ARRAY_INDEX_ILLEGAL(String token) {
+        return localize("pointer.array.index.illegal", token);
+    }
+
+    // nodereference messages
+    static String NODEREF_VALUE_ADD_ERR() {
+        return localize("noderef.value.add.err");
+    }
+
+    static String NODEREF_VALUE_CANNOT_REMOVE() {
+        return localize("noderef.value.cannot.remove");
+    }
+
+    static String NODEREF_OBJECT_MISSING(String key) {
+        return localize("noderef.object.missing", key);
+    }
+
+    static String NODEREF_ARRAY_INDEX_ERR(int index, int size) {
+        return localize("noderef.array.index.err", index, size);
+    }
+
+    // json patch messages
+    static String PATCH_MUST_BE_ARRAY() {
+        return localize("patch.must.be.array");
+    }
+
+    static String PATCH_MOVE_PROPER_PREFIX(String from, String path) {
+        return localize("patch.move.proper.prefix", from, path);
+    }
+
+    static String PATCH_MOVE_TARGET_NULL(String from) {
+        return localize("patch.move.target.null", from);
+    }
+
+    static String PATCH_TEST_FAILED(String path, String value) {
+        return localize("patch.test.failed", path, value);
+    }
+
+    static String PATCH_ILLEGAL_OPERATION(String operation) {
+        return localize("patch.illegal.operation", operation);
+    }
+
+    static String PATCH_MEMBER_MISSING(String operation, String member) {
+        return localize("patch.member.missing", operation, member);
     }
 
Index: trunk/src/org/glassfish/json/JsonNumberImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonNumberImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonNumberImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -126,4 +126,9 @@
 
         @Override
+        public Number numberValue() {
+            return num;
+        }
+
+        @Override
         public String toString() {
             return Integer.toString(num);
@@ -143,4 +148,14 @@
         public boolean isIntegral() {
             return true;
+        }
+
+        @Override
+        public int intValue() {
+            return (int) num;
+        }
+
+        @Override
+        public int intValueExact() {
+            return Math.toIntExact(num);
         }
 
@@ -172,4 +187,9 @@
 
         @Override
+        public Number numberValue() {
+            return num;
+        }
+
+        @Override
         public String toString() {
             return Long.toString(num);
@@ -191,4 +211,9 @@
         }
 
+        @Override
+        public Number numberValue() {
+            return bigDecimalValue();
+        }
+
     }
 
@@ -245,4 +270,7 @@
     @Override
     public boolean equals(Object obj) {
+        if (this == obj){
+            return true;
+        }
         if (!(obj instanceof JsonNumber)) {
             return false;
Index: trunk/src/org/glassfish/json/JsonObjectBuilderImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonObjectBuilderImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonObjectBuilderImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -51,9 +51,11 @@
 
 /**
- * JsonObjectBuilder impl
+ * JsonObjectBuilder implementation
  *
  * @author Jitendra Kotamraju
+ * @author Kin-man Chung
  */
 class JsonObjectBuilderImpl implements JsonObjectBuilder {
+
     private Map<String, JsonValue> valueMap;
     private final BufferPool bufferPool;
@@ -63,4 +65,17 @@
     }
 
+    JsonObjectBuilderImpl(JsonObject object, BufferPool bufferPool) {
+        this.bufferPool = bufferPool;
+        valueMap = new LinkedHashMap<>();
+        valueMap.putAll(object);
+    }
+
+    JsonObjectBuilderImpl(Map<String, Object> map, BufferPool bufferPool) {
+        this.bufferPool = bufferPool;
+        valueMap = new LinkedHashMap<>();
+        populate(map);
+    }
+
+    @Override
     public JsonObjectBuilder add(String name, JsonValue value) {
         validateName(name);
@@ -70,4 +85,5 @@
     }
 
+    @Override
     public JsonObjectBuilder add(String name, String value) {
         validateName(name);
@@ -77,4 +93,5 @@
     }
 
+    @Override
     public JsonObjectBuilder add(String name, BigInteger value) {
         validateName(name);
@@ -84,4 +101,5 @@
     }
 
+    @Override
     public JsonObjectBuilder add(String name, BigDecimal value) {
         validateName(name);
@@ -91,4 +109,5 @@
     }
 
+    @Override
     public JsonObjectBuilder add(String name, int value) {
         validateName(name);
@@ -97,4 +116,5 @@
     }
 
+    @Override
     public JsonObjectBuilder add(String name, long value) {
         validateName(name);
@@ -103,4 +123,5 @@
     }
 
+    @Override
     public JsonObjectBuilder add(String name, double value) {
         validateName(name);
@@ -109,4 +130,5 @@
     }
 
+    @Override
     public JsonObjectBuilder add(String name, boolean value) {
         validateName(name);
@@ -115,4 +137,5 @@
     }
 
+    @Override
     public JsonObjectBuilder addNull(String name) {
         validateName(name);
@@ -121,4 +144,5 @@
     }
 
+    @Override
     public JsonObjectBuilder add(String name, JsonObjectBuilder builder) {
         validateName(name);
@@ -130,4 +154,5 @@
     }
 
+    @Override
     public JsonObjectBuilder add(String name, JsonArrayBuilder builder) {
         validateName(name);
@@ -139,4 +164,24 @@
     }
 
+    @Override
+    public JsonObjectBuilder addAll(JsonObjectBuilder builder) {
+        if (builder == null) {
+            throw new NullPointerException(JsonMessages.OBJBUILDER_OBJECT_BUILDER_NULL());
+        }
+        if (valueMap == null) {
+            this.valueMap = new LinkedHashMap<>();
+        }
+        this.valueMap.putAll(builder.build());
+        return this;
+    }
+
+    @Override
+    public JsonObjectBuilder remove(String name) {
+        validateName(name);
+        this.valueMap.remove(name);
+        return this;
+    }
+
+    @Override
     public JsonObject build() {
         Map<String, JsonValue> snapshot = (valueMap == null)
@@ -147,7 +192,20 @@
     }
 
+    private void populate(Map<String, Object> map) {
+        final Set<String> fields = map.keySet();
+        for (String field : fields) {
+            Object value = map.get(field);
+            if (value != null && value instanceof Optional) {
+                ((Optional<?>) value).ifPresent(v ->
+                        this.valueMap.put(field, MapUtil.handle(v, bufferPool)));
+            } else {
+                this.valueMap.put(field, MapUtil.handle(value, bufferPool));
+            }
+        }
+    }
+
     private void putValueMap(String name, JsonValue value) {
         if (valueMap == null) {
-            this.valueMap = new LinkedHashMap<String, JsonValue>();
+            this.valueMap = new LinkedHashMap<>();
         }
         valueMap.put(name, value);
@@ -264,9 +322,29 @@
         public String toString() {
             StringWriter sw = new StringWriter();
-            JsonWriter jw = new JsonWriterImpl(sw, bufferPool);
-            jw.write(this);
-            jw.close();
+            try (JsonWriter jw = new JsonWriterImpl(sw, bufferPool)) {
+                jw.write(this);
+            }
             return sw.toString();
         }
+
+        @Override
+        public JsonObject asJsonObject() {
+            return this;
+        }
+
+        @Override
+        public int size() {
+            return valueMap.size();
+        }
+
+        @Override
+        public JsonValue get(Object key) {
+            return valueMap.get(key);
+        }
+
+        @Override
+        public boolean containsKey(Object key) {
+            return valueMap.containsKey(key);
+        }
     }
 
Index: trunk/src/org/glassfish/json/JsonParserFactoryImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonParserFactoryImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonParserFactoryImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
Index: trunk/src/org/glassfish/json/JsonParserImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonParserImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonParserImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -41,12 +41,29 @@
 package org.glassfish.json;
 
-import javax.json.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.nio.charset.Charset;
+import java.util.AbstractMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonException;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonValue;
 import javax.json.stream.JsonLocation;
 import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParser.Event;
 import javax.json.stream.JsonParsingException;
-import java.io.*;
-import java.math.BigDecimal;
-import java.nio.charset.Charset;
-import java.util.*;
 
 import org.glassfish.json.JsonTokenizer.JsonToken;
@@ -58,30 +75,32 @@
  *
  * @author Jitendra Kotamraju
+ * @author Kin-man Chung
  */
 public class JsonParserImpl implements JsonParser {
 
+    private final BufferPool bufferPool;
     private Context currentContext = new NoneContext();
     private Event currentEvent;
 
     private final Stack stack = new Stack();
-    private final StateIterator stateIterator;
     private final JsonTokenizer tokenizer;
 
     public JsonParserImpl(Reader reader, BufferPool bufferPool) {
+        this.bufferPool = bufferPool;
         tokenizer = new JsonTokenizer(reader, bufferPool);
-        stateIterator = new StateIterator();
     }
 
     public JsonParserImpl(InputStream in, BufferPool bufferPool) {
+        this.bufferPool = bufferPool;
         UnicodeDetectingInputStream uin = new UnicodeDetectingInputStream(in);
         tokenizer = new JsonTokenizer(new InputStreamReader(uin, uin.getCharset()), bufferPool);
-        stateIterator = new StateIterator();
     }
 
     public JsonParserImpl(InputStream in, Charset encoding, BufferPool bufferPool) {
+        this.bufferPool = bufferPool;
         tokenizer = new JsonTokenizer(new InputStreamReader(in, encoding), bufferPool);
-        stateIterator = new StateIterator();
-    }
-
+    }
+
+    @Override
     public String getString() {
         if (currentEvent == Event.KEY_NAME || currentEvent == Event.VALUE_STRING
@@ -115,4 +134,8 @@
     }
 
+    boolean isDefinitelyLong() {
+    	return tokenizer.isDefinitelyLong();
+    }
+
     @Override
     public long getLong() {
@@ -121,5 +144,5 @@
                     JsonMessages.PARSER_GETLONG_ERR(currentEvent));
         }
-        return tokenizer.getBigDecimal().longValue();
+        return tokenizer.getLong();
     }
 
@@ -134,4 +157,190 @@
 
     @Override
+    public JsonArray getArray() {
+        if (currentEvent != Event.START_ARRAY) {
+            throw new IllegalStateException(
+                JsonMessages.PARSER_GETARRAY_ERR(currentEvent));
+        }
+        return getArray(new JsonArrayBuilderImpl(bufferPool));
+    }
+
+    @Override
+    public JsonObject getObject() {
+        if (currentEvent != Event.START_OBJECT) {
+            throw new IllegalStateException(
+                JsonMessages.PARSER_GETOBJECT_ERR(currentEvent));
+        }
+        return getObject(new JsonObjectBuilderImpl(bufferPool));
+    }
+
+    @Override
+    public JsonValue getValue() {
+        switch (currentEvent) {
+            case START_ARRAY:
+                return getArray(new JsonArrayBuilderImpl(bufferPool));
+            case START_OBJECT:
+                return getObject(new JsonObjectBuilderImpl(bufferPool));
+            case KEY_NAME:
+            case VALUE_STRING:
+                return new JsonStringImpl(getString());
+            case VALUE_NUMBER:
+                if (isDefinitelyInt()) {
+                    return JsonNumberImpl.getJsonNumber(getInt());
+                } else if (isDefinitelyLong()) {
+                    return JsonNumberImpl.getJsonNumber(getLong());
+                }
+                return JsonNumberImpl.getJsonNumber(getBigDecimal());
+            case VALUE_TRUE:
+                return JsonValue.TRUE;
+            case VALUE_FALSE:
+                return JsonValue.FALSE;
+            case VALUE_NULL:
+                return JsonValue.NULL;
+            case END_ARRAY:
+            case END_OBJECT:
+            default:
+            	throw new IllegalStateException(JsonMessages.PARSER_GETVALUE_ERR(currentEvent));
+        }
+    }
+
+    @Override
+    public Stream<JsonValue> getArrayStream() {
+        if (currentEvent != Event.START_ARRAY) {
+            throw new IllegalStateException(
+                JsonMessages.PARSER_GETARRAY_ERR(currentEvent));
+        }
+        Spliterator<JsonValue> spliterator =
+                new Spliterators.AbstractSpliterator<JsonValue>(Long.MAX_VALUE, Spliterator.ORDERED) {
+            @Override
+            public Spliterator<JsonValue> trySplit() {
+                return null;
+            }
+            @Override
+            public boolean tryAdvance(Consumer<? super JsonValue> action) {
+                if (action == null) {
+                    throw new NullPointerException();
+                }
+                if (! hasNext()) {
+                    return false;
+                }
+                if (next() == JsonParser.Event.END_ARRAY) {
+                    return false;
+                }
+                action.accept(getValue());
+                return true;
+            }
+        };
+        return StreamSupport.stream(spliterator, false);
+    }
+
+    @Override
+    public Stream<Map.Entry<String, JsonValue>> getObjectStream() {
+        if (currentEvent != Event.START_OBJECT) {
+            throw new IllegalStateException(
+                JsonMessages.PARSER_GETOBJECT_ERR(currentEvent));
+        }
+        Spliterator<Map.Entry<String, JsonValue>> spliterator =
+                new Spliterators.AbstractSpliterator<Map.Entry<String, JsonValue>>(Long.MAX_VALUE, Spliterator.ORDERED) {
+            @Override
+            public Spliterator<Map.Entry<String,JsonValue>> trySplit() {
+                return null;
+            }
+            @Override
+            public boolean tryAdvance(Consumer<? super Map.Entry<String, JsonValue>> action) {
+                if (action == null) {
+                    throw new NullPointerException();
+                }
+                if (! hasNext()) {
+                    return false;
+                }
+                JsonParser.Event e = next();
+                if (e == JsonParser.Event.END_OBJECT) {
+                    return false;
+                }
+                if (e != JsonParser.Event.KEY_NAME) {
+                    throw new JsonException(JsonMessages.INTERNAL_ERROR());
+                }
+                String key = getString();
+                if (! hasNext()) {
+                    throw new JsonException(JsonMessages.INTERNAL_ERROR());
+                }
+                next();
+                JsonValue value = getValue();
+                action.accept(new AbstractMap.SimpleImmutableEntry<>(key, value));
+                return true;
+            }
+        };
+        return StreamSupport.stream(spliterator, false);
+    }
+
+    @Override
+    public Stream<JsonValue> getValueStream() {
+        if (! (currentContext instanceof NoneContext)) {
+            throw new IllegalStateException(
+                JsonMessages.PARSER_GETVALUESTREAM_ERR());
+        }
+        Spliterator<JsonValue> spliterator =
+                new Spliterators.AbstractSpliterator<JsonValue>(Long.MAX_VALUE, Spliterator.ORDERED) {
+            @Override
+            public Spliterator<JsonValue> trySplit() {
+                return null;
+            }
+            @Override
+            public boolean tryAdvance(Consumer<? super JsonValue> action) {
+                if (action == null) {
+                    throw new NullPointerException();
+                }
+                if (! hasNext()) {
+                    return false;
+                }
+                next();
+                action.accept(getValue());
+                return true;
+            }
+        };
+        return StreamSupport.stream(spliterator, false);
+    }
+
+    @Override
+    public void skipArray() {
+        if (currentEvent == Event.START_ARRAY) {
+            currentContext.skip();
+            currentContext = stack.pop();
+        }
+    }
+
+    @Override
+    public void skipObject() {
+        if (currentEvent == Event.START_OBJECT) {
+            currentContext.skip();
+            currentContext = stack.pop();
+        }
+    }
+
+    private JsonArray getArray(JsonArrayBuilder builder) {
+        while(hasNext()) {
+            JsonParser.Event e = next();
+            if (e == JsonParser.Event.END_ARRAY) {
+                return builder.build();
+            }
+            builder.add(getValue());
+        }
+        throw parsingException(JsonToken.EOF, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL, SQUARECLOSE]");
+    }
+
+    private JsonObject getObject(JsonObjectBuilder builder) {
+        while(hasNext()) {
+            JsonParser.Event e = next();
+            if (e == JsonParser.Event.END_OBJECT) {
+                return builder.build();
+            }
+            String key = getString();
+            next();
+            builder.add(key, getValue());
+        }
+        throw parsingException(JsonToken.EOF, "[STRING, CURLYCLOSE]");
+    }
+
+    @Override
     public JsonLocation getLocation() {
         return tokenizer.getLocation();
@@ -142,41 +351,18 @@
     }
 
+    @Override
     public boolean hasNext() {
-        return stateIterator.hasNext();
-    }
-
+        return tokenizer.hasNextToken();
+    }
+
+    @Override
     public Event next() {
-        return stateIterator.next();
-    }
-
-    private class StateIterator implements  Iterator<JsonParser.Event> {
-
-        @Override
-        public boolean hasNext() {
-            if (stack.isEmpty() && (currentEvent == Event.END_ARRAY || currentEvent == Event.END_OBJECT)) {
-                JsonToken token = tokenizer.nextToken();
-                if (token != JsonToken.EOF) {
-                    throw new JsonParsingException(JsonMessages.PARSER_EXPECTED_EOF(token),
-                            getLastCharLocation());
-                }
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public JsonParser.Event next() {
-            if (!hasNext()) {
-                throw new NoSuchElementException();
-            }
-            return currentEvent = currentContext.getNextEvent();
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-    }
-
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        return currentEvent = currentContext.getNextEvent();
+    }
+
+    @Override
     public void close() {
         try {
@@ -206,4 +392,8 @@
         }
 
+        private Context peek() {
+            return head;
+        }
+
         private boolean isEmpty() {
             return head == null;
@@ -214,4 +404,5 @@
         Context next;
         abstract Event getNextEvent();
+        abstract void skip();
     }
 
@@ -219,5 +410,5 @@
         @Override
         public Event getNextEvent() {
-            // Handle 1. {     2. [
+            // Handle 1. {   2. [   3. value
             JsonToken token = tokenizer.nextToken();
             if (token == JsonToken.CURLYOPEN) {
@@ -229,6 +420,13 @@
                 currentContext = new ArrayContext();
                 return Event.START_ARRAY;
-            }
-            throw parsingException(token, "[CURLYOPEN, SQUAREOPEN]");
+            } else if (token.isValue()) {
+                return token.getEvent();
+            }
+            throw parsingException(token, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL]");
+        }
+
+        @Override
+        void skip() {
+            // no-op
         }
     }
@@ -293,4 +491,21 @@
         }
 
+        @Override
+        void skip() {
+            JsonToken token;
+            int depth = 1;
+            do {
+                token = tokenizer.nextToken();
+                switch (token) {
+                    case CURLYCLOSE:
+                        depth--;
+                        break;
+                    case CURLYOPEN:
+                        depth++;
+                        break;
+                }
+            } while (!(token == JsonToken.CURLYCLOSE && depth == 0));
+        }
+
     }
 
@@ -328,4 +543,20 @@
         }
 
+        @Override
+        void skip() {
+            JsonToken token;
+            int depth = 1;
+            do {
+                token = tokenizer.nextToken();
+                switch (token) {
+                    case SQUARECLOSE:
+                        depth--;
+                        break;
+                    case SQUAREOPEN:
+                        depth++;
+                        break;
+                }
+            } while (!(token == JsonToken.SQUARECLOSE && depth == 0));
+        }
     }
 
Index: trunk/src/org/glassfish/json/JsonPatchBuilderImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonPatchBuilderImpl.java	(revision 13231)
+++ trunk/src/org/glassfish/json/JsonPatchBuilderImpl.java	(revision 13231)
@@ -0,0 +1,362 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2015-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package org.glassfish.json;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonException;
+import javax.json.JsonPatch;
+import javax.json.JsonPatch.Operation;
+import javax.json.JsonPatchBuilder;
+import javax.json.JsonStructure;
+import javax.json.JsonValue;
+
+/**
+ * A builder for constructing a JSON Patch by adding
+ * JSON Patch operations incrementally.
+ * <p>
+ * The following illustrates the approach.
+ * <pre>
+ *   JsonPatchBuilder builder = Json.createPatchBuilder();
+ *   JsonPatch patch = builder.add("/John/phones/office", "1234-567")
+ *                            .remove("/Amy/age")
+ *                            .build();
+ * </pre>
+ * The result is equivalent to the following JSON Patch.
+ * <pre>
+ * [
+ *    {"op" = "add", "path" = "/John/phones/office", "value" = "1234-567"},
+ *    {"op" = "remove", "path" = "/Amy/age"}
+ * ] </pre>
+ *
+ * @since 1.1
+ */
+public final class JsonPatchBuilderImpl implements JsonPatchBuilder {
+
+    private final JsonArrayBuilder builder;
+
+    /**
+     * Creates a JsonPatchBuilderImpl, starting with the specified
+     * JSON Patch
+     * @param patch the JSON Patch
+     */
+    public JsonPatchBuilderImpl(JsonArray patch) {
+        builder = Json.createArrayBuilder(patch);
+    }
+
+    /**
+     * Creates JsonPatchBuilderImpl with empty JSON Patch
+     */
+    public JsonPatchBuilderImpl() {
+        builder = Json.createArrayBuilder();
+    }
+
+    /**
+     * A convenience method for {@code new JsonPatchImpl(build()).apply(target)}.
+     * The target is not modified by the patch.
+     *
+     * @param <T> the target type, must be a subtype of {@link JsonStructure}
+     * @param target the target to apply the patch operations
+     * @return the transformed target after the patch
+     * @throws JsonException if the supplied JSON Patch is malformed or if
+     *    it contains references to non-existing members
+     */
+    public <T extends JsonStructure> T apply(T target) {
+        return build().apply(target);
+    }
+
+    /**
+     * Adds an "add" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder add(String path, JsonValue value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.ADD.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                   );
+        return this;
+    }
+
+    /**
+     * Adds an "add" JSON Patch operation
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder add(String path, String value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.ADD.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                   );
+        return this;
+    }
+
+    /**
+     * Adds an "add" JSON Patch operation
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder add(String path, int value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.ADD.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                  );
+        return this;
+    }
+
+    /**
+     * Adds an "add" JSON Patch operation
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder add(String path, boolean value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.ADD.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                   );
+        return this;
+    }
+
+    /**
+     * Adds a "remove" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder remove(String path) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.REMOVE.operationName())
+                           .add("path", path)
+                    );
+        return this;
+    }
+
+    /**
+     * Adds a "replace" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder replace(String path, JsonValue value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.REPLACE.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                  );
+        return this;
+    }
+
+    /**
+     * Adds a "replace" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder replace(String path, String value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.REPLACE.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                  );
+        return this;
+    }
+
+    /**
+     * Adds a "replace" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder replace(String path, int value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.REPLACE.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                  );
+        return this;
+    }
+
+    /**
+     * Adds a "replace" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder replace(String path, boolean value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.REPLACE.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                  );
+        return this;
+    }
+
+    /**
+     * Adds a "move" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @param from the "from" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder move(String path, String from) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.MOVE.operationName())
+                           .add("path", path)
+                           .add("from", from)
+                  );
+        return this;
+    }
+
+    /**
+     * Adds a "copy" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @param from the "from" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder copy(String path, String from) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.COPY.operationName())
+                           .add("path", path)
+                           .add("from", from)
+                  );
+        return this;
+    }
+
+    /**
+     * Adds a "test" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder test(String path, JsonValue value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.TEST.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                  );
+        return this;
+    }
+
+    /**
+     * Adds a "test" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder test(String path, String value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.TEST.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                  );
+        return this;
+    }
+
+    /**
+     * Adds a "test" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder test(String path, int value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.TEST.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                  );
+        return this;
+    }
+
+    /**
+     * Adds a "test" JSON Patch operation.
+     * @param path the "path" member of the operation
+     * @param value the "value" member of the operation
+     * @return this JsonPatchBuilder
+     */
+    @Override
+    public JsonPatchBuilder test(String path, boolean value) {
+        builder.add(Json.createObjectBuilder()
+                           .add("op", Operation.TEST.operationName())
+                           .add("path", path)
+                           .add("value", value)
+                  );
+        return this;
+    }
+
+    /**
+     * Returns the patch operations in a JsonArray
+     * @return the patch operations in a JsonArray
+     */
+    public JsonArray buildAsJsonArray() {
+        return builder.build();
+    }
+
+    /**
+     * Returns the patch operation in a JsonPatch
+     * @return the patch operation in a JsonPatch
+     */
+    @Override
+    public JsonPatch build() {
+        return new JsonPatchImpl(buildAsJsonArray());
+    }
+}
+
Index: trunk/src/org/glassfish/json/JsonPatchImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonPatchImpl.java	(revision 13231)
+++ trunk/src/org/glassfish/json/JsonPatchImpl.java	(revision 13231)
@@ -0,0 +1,321 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2015-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package org.glassfish.json;
+
+import javax.json.*;
+import javax.json.JsonValue.ValueType;
+
+/**
+ * This class is an immutable representation of a JSON Patch as specified in
+ * <a href="http://tools.ietf.org/html/rfc6902">RFC 6902</a>.
+ * <p>A {@code JsonPatch} can be instantiated with {@link Json#createPatch(JsonArray)}
+ * by specifying the patch operations in a JSON Patch. Alternately, it
+ * can also be constructed with a {@link JsonPatchBuilder}.
+ * </p>
+ * The following illustrates both approaches.
+ * <p>1. Construct a JsonPatch with a JSON Patch.
+ * <pre>{@code
+ *   JsonArray contacts = ... // The target to be patched
+ *   JsonArray patch = ...  ; // JSON Patch
+ *   JsonPatch jsonpatch = Json.createPatch(patch);
+ *   JsonArray result = jsonpatch.apply(contacts);
+ * } </pre>
+ * 2. Construct a JsonPatch with JsonPatchBuilder.
+ * <pre>{@code
+ *   JsonPatchBuilder builder = Json.createPatchBuilder();
+ *   JsonArray result = builder.add("/John/phones/office", "1234-567")
+ *                             .remove("/Amy/age")
+ *                             .build()
+ *                             .apply(contacts);
+ * } </pre>
+ *
+ * @since 1.1
+ */
+public class JsonPatchImpl implements JsonPatch {
+
+    private final JsonArray patch;
+
+    /**
+     * Constructs a JsonPatchImpl
+     * @param patch the JSON Patch
+     */
+    public JsonPatchImpl(JsonArray patch) {
+        this.patch = patch;
+    }
+
+    /**
+     * Compares this {@code JsonPatchImpl} with another object.
+     * @param obj the object to compare this {@code JsonPatchImpl} against
+     * @return true if the given object is a {@code JsonPatchImpl} with the same
+     * reference tokens as this one, false otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null || obj.getClass() != JsonPatchImpl.class)
+            return false;
+        return patch.equals(((JsonPatchImpl)obj).patch);
+    }
+
+    /**
+     * Returns the hash code value for this {@code JsonPatchImpl}.
+     *
+     * @return the hash code value for this {@code JsonPatchImpl} object
+     */
+    @Override
+    public int hashCode() {
+        return patch.hashCode();
+    }
+
+    /**
+     * Returns the JSON Patch text
+     * @return the JSON Patch text
+     */
+    @Override
+    public String toString() {
+        return patch.toString();
+    }
+
+    /**
+     * Applies the patch operations to the specified {@code target}.
+     * The target is not modified by the patch.
+     *
+     * @param target the target to apply the patch operations
+     * @return the transformed target after the patch
+     * @throws JsonException if the supplied JSON Patch is malformed or if
+     *    it contains references to non-existing members
+     */
+    @Override
+    public JsonStructure apply(JsonStructure target) {
+
+        JsonStructure result = target;
+
+        for (JsonValue operation: patch) {
+            if (operation.getValueType() != ValueType.OBJECT) {
+                throw new JsonException(JsonMessages.PATCH_MUST_BE_ARRAY());
+            }
+            result = apply(result, (JsonObject) operation);
+        }
+        return result;
+    }
+
+    @Override
+    public JsonArray toJsonArray() {
+        return patch;
+    }
+
+    /**
+     * Generates a JSON Patch from the source and target {@code JsonStructure}.
+     * The generated JSON Patch need not be unique.
+     * @param source the source
+     * @param target the target, must be the same type as the source
+     * @return a JSON Patch which when applied to the source, yields the target
+     */
+    public static JsonArray diff(JsonStructure source, JsonStructure target) {
+        return (new DiffGenerator()).diff(source, target);
+    }
+
+    /**
+     * Applies a JSON Patch operation to the target.
+     * @param target the target to apply the operation
+     * @param operation the JSON Patch operation
+     * @return the target after the patch
+     */
+    private JsonStructure apply(JsonStructure target, JsonObject operation) {
+
+        JsonPointer pointer = getPointer(operation, "path");
+        JsonPointer from;
+        switch (Operation.fromOperationName(operation.getString("op"))) {
+            case ADD:
+                return pointer.add(target, getValue(operation));
+            case REPLACE:
+                return pointer.replace(target, getValue(operation));
+            case REMOVE:
+                return pointer.remove(target);
+            case COPY:
+                from = getPointer(operation, "from");
+                return pointer.add(target, from.getValue(target));
+            case MOVE:
+                // Check if from is a proper prefix of path
+                String dest = operation.getString("path");
+                String src = operation.getString("from");
+                if (dest.startsWith(src) && src.length() < dest.length()) {
+                    throw new JsonException(JsonMessages.PATCH_MOVE_PROPER_PREFIX(src, dest));
+                }
+                from = getPointer(operation, "from");
+                // Check if 'from' exists in target object
+                if (!from.containsValue(target)) {
+                    throw new JsonException(JsonMessages.PATCH_MOVE_TARGET_NULL(src));
+                }
+                if (pointer.equals(from)) {
+                    // nop
+                    return target;
+                }
+                return pointer.add(from.remove(target), from.getValue(target));
+            case TEST:
+                if (! getValue(operation).equals(pointer.getValue(target))) {
+                    throw new JsonException(JsonMessages.PATCH_TEST_FAILED(operation.getString("path"), getValue(operation).toString()));
+                }
+                return target;
+            default:
+                throw new JsonException(JsonMessages.PATCH_ILLEGAL_OPERATION(operation.getString("op")));
+        }
+    }
+
+    private JsonPointer getPointer(JsonObject operation, String member) {
+        JsonString pointerString = operation.getJsonString(member);
+        if (pointerString == null) {
+            missingMember(operation.getString("op"), member);
+        }
+        return Json.createPointer(pointerString.getString());
+    }
+
+    private JsonValue getValue(JsonObject operation) {
+        JsonValue value = operation.get("value");
+        if (value == null) {
+            missingMember(operation.getString("op"), "value");
+        }
+        return value;
+    }
+
+    private void missingMember(String op, String  member) {
+        throw new JsonException(JsonMessages.PATCH_MEMBER_MISSING(op, member));
+    }
+
+    static class DiffGenerator {
+        private JsonPatchBuilder builder;
+
+        JsonArray diff(JsonStructure source, JsonStructure target) {
+            builder = Json.createPatchBuilder();
+            diff("", source, target);
+            return builder.build().toJsonArray();
+        }
+
+        private void diff(String path, JsonValue source, JsonValue target) {
+            if (source.equals(target)) {
+                return;
+            }
+            ValueType s = source.getValueType();
+            ValueType t = target.getValueType();
+            if (s == ValueType.OBJECT && t == ValueType.OBJECT) {
+                diffObject(path, (JsonObject) source, (JsonObject) target);
+            } else if (s == ValueType.ARRAY && t == ValueType.ARRAY) {
+                diffArray(path, (JsonArray) source, (JsonArray) target);
+            } else {
+                builder.replace(path, target);
+            }
+        }
+
+        private void diffObject(String path, JsonObject source, JsonObject target) {
+            source.forEach((key, value) -> {
+                if (target.containsKey(key)) {
+                    diff(path + '/' + key, value, target.get(key));
+                } else {
+                    builder.remove(path + '/' + key);
+                }
+            });
+            target.forEach((key, value) -> {
+                if (! source.containsKey(key)) {
+                    builder.add(path + '/' + key, value);
+                }
+            });
+        }
+
+        /*
+         * For array element diff, find the longest common subsequence, per
+         * http://en.wikipedia.org/wiki/Longest_common_subsequence_problem .
+         * We modify the algorithm to generate a replace if possible.
+         */
+        private void diffArray(String path, JsonArray source, JsonArray target) {
+            /* The array c keeps track of length of the subsequence. To avoid
+             * computing the equality of array elements again, we
+             * left shift its value by 1, and use the low order bit to mark
+             * that two items are equal.
+             */
+            int m = source.size();
+            int n = target.size();
+            int [][] c = new int[m+1][n+1];
+            for (int i = 0; i < m+1; i++)
+                c[i][0] = 0;
+            for (int i = 0; i < n+1; i++)
+                c[0][i] = 0;
+            for (int i = 0; i < m; i++) {
+                for (int j = 0; j < n; j++) {
+                    if (source.get(i).equals(target.get(j))) {
+                        c[i+1][j+1] = ((c[i][j]) & ~1) + 3;
+                        // 3 = (1 << 1) | 1;
+                    } else {
+                        c[i+1][j+1] = Math.max(c[i+1][j], c[i][j+1]) & ~1;
+                    }
+                }
+            }
+
+            int i = m;
+            int j = n;
+            while (i > 0 || j > 0) {
+                if (i == 0) {
+                    j--;
+                    builder.add(path + '/' + j, target.get(j));
+                } else if (j == 0) {
+                    i--;
+                    builder.remove(path + '/' + i);
+                } else if ((c[i][j] & 1) == 1) {
+                    i--; j--;
+                } else {
+                    int f = c[i][j-1] >> 1;
+                    int g = c[i-1][j] >> 1;
+                    if (f > g) {
+                        j--;
+                        builder.add(path + '/' + j, target.get(j));
+                    } else if (f < g) {
+                        i--;
+                        builder.remove(path + '/' + i);
+                    } else { // f == g) {
+                       i--; j--;
+                       diff(path + '/' + i, source.get(i), target.get(j));
+                    }
+                }
+            }
+        }
+    }
+}
+
Index: trunk/src/org/glassfish/json/JsonPointerImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonPointerImpl.java	(revision 13231)
+++ trunk/src/org/glassfish/json/JsonPointerImpl.java	(revision 13231)
@@ -0,0 +1,316 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2015-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package org.glassfish.json;
+
+import javax.json.JsonArray;
+import javax.json.JsonException;
+import javax.json.JsonObject;
+import javax.json.JsonPointer;
+import javax.json.JsonStructure;
+import javax.json.JsonValue;
+import java.io.Serializable;
+import java.util.function.BiFunction;
+
+/**
+ * <p>This class is an immutable representation of a JSON Pointer as specified in
+ * <a href="http://tools.ietf.org/html/rfc6901">RFC 6901</a>.
+ * </p>
+ * <p> A JSON Pointer, when applied to a target {@link JsonValue},
+ * defines a reference location in the target.</p>
+ * <p> An empty JSON Pointer string defines a reference to the target itself.</p>
+ * <p> If the JSON Pointer string is non-empty, it must be a sequence
+ * of '/' prefixed tokens, and the target must either be a {@link JsonArray}
+ * or {@link JsonObject}. If the target is a {@code JsonArray}, the pointer
+ * defines a reference to an array element, and the last token specifies the index.
+ * If the target is a {@link JsonObject}, the pointer defines a reference to a
+ * name/value pair, and the last token specifies the name.
+ * </p>
+ * <p> The method {@link #getValue getValue()} returns the referenced value.
+ * The methods {@link #add add()}, {@link #replace replace()},
+ * and {@link #remove remove()} executes the operations specified in
+ * <a href="http://tools.ietf.org/html/rfc6902">RFC 6902</a>. </p>
+ *
+ * @since 1.1
+ */
+
+public final class JsonPointerImpl implements JsonPointer, Serializable {
+
+    private static final long serialVersionUID = -8123110179640843141L;
+    private final String[] tokens;
+    private final String jsonPointer;
+
+    /**
+     * Constructs and initializes a JsonPointerImpl.
+     * @param jsonPointer the JSON Pointer string
+     * @throws NullPointerException if {@code jsonPointer} is {@code null}
+     * @throws JsonException if {@code jsonPointer} is not a valid JSON Pointer
+     */
+    public JsonPointerImpl(String jsonPointer) {
+        this.jsonPointer = jsonPointer;
+        tokens = jsonPointer.split("/", -1);  // keep the trailing blanks
+        if (! "".equals(tokens[0])) {
+            throw new JsonException(JsonMessages.POINTER_FORMAT_INVALID());
+        }
+        for (int i = 1; i < tokens.length; i++) {
+            String token = tokens[i];
+            StringBuilder reftoken = new StringBuilder();
+            for (int j = 0; j < token.length(); j++) {
+                char ch = token.charAt(j);
+                if (ch == '~' && j < token.length() - 1) {
+                    char ch1 = token.charAt(j+1);
+                    if (ch1 == '0') {
+                        ch = '~'; j++;
+                    } else if (ch1 == '1') {
+                        ch = '/'; j++;
+                    }
+                }
+                reftoken.append(ch);
+            }
+            tokens[i] = reftoken.toString();
+        }
+    }
+
+    /**
+     * Compares this {@code JsonPointer} with another object.
+     * @param obj the object to compare this {@code JsonPointer} against
+     * @return true if the given object is a {@code JsonPointer} with the same
+     * reference tokens as this one, false otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null || obj.getClass() != JsonPointerImpl.class)
+            return false;
+        return jsonPointer.equals(((JsonPointerImpl)obj).jsonPointer);
+    }
+
+    /**
+     * Returns the hash code value for this {@code JsonPointer} object.
+     * The hash code of this object is defined by the hash codes of it's reference tokens.
+     *
+     * @return the hash code value for this {@code JsonPointer} object
+     */
+    @Override
+    public int hashCode() {
+        return jsonPointer.hashCode();
+    }
+
+    /**
+     * Returns {@code true} if there is a value at the referenced location in the specified {@code target}.
+     *
+     * @param target the target referenced by this {@code JsonPointer}
+     * @return {@code true} if this pointer points to a value in a specified {@code target}.
+     */
+    @Override
+    public boolean containsValue(JsonStructure target) {
+        NodeReference[] refs = getReferences(target);
+        return refs[0].contains();
+    }
+
+    /**
+     * Returns the value at the referenced location in the specified {@code target}
+     *
+     * @param target the target referenced by this {@code JsonPointer}
+     * @return the referenced value in the target.
+     * @throws NullPointerException if {@code target} is null
+     * @throws JsonException if the referenced value does not exist
+     */
+    @Override
+    public JsonValue getValue(JsonStructure target) {
+        NodeReference[] refs = getReferences(target);
+        return refs[0].get();
+    }
+
+    /**
+     * Adds or replaces a value at the referenced location in the specified
+     * {@code target} with the specified {@code value}.
+     * <ol>
+     * <li>If the reference is the target (empty JSON Pointer string),
+     * the specified {@code value}, which must be the same type as
+     * specified {@code target}, is returned.</li>
+     * <li>If the reference is an array element, the specified {@code value} is inserted
+     * into the array, at the referenced index. The value currently at that location, and
+     * any subsequent values, are shifted to the right (adds one to the indices).
+     * Index starts with 0. If the reference is specified with a "-", or if the
+     * index is equal to the size of the array, the value is appended to the array.</li>
+     * <li>If the reference is a name/value pair of a {@code JsonObject}, and the
+     * referenced value exists, the value is replaced by the specified {@code value}.
+     * If the value does not exist, a new name/value pair is added to the object.</li>
+     * </ol>
+     *
+     * @param target the target referenced by this {@code JsonPointer}
+     * @param value the value to be added
+     * @return the transformed {@code target} after the value is added.
+     * @throws NullPointerException if {@code target} is {@code null}
+     * @throws JsonException if the reference is an array element and
+     * the index is out of range ({@code index < 0 || index > array size}),
+     * or if the pointer contains references to non-existing objects or arrays.
+     */
+    @Override
+    public JsonStructure add(JsonStructure target, JsonValue value) {
+        return execute(NodeReference::add, target, value);
+    }
+
+    /**
+     * Replaces the value at the referenced location in the specified
+     * {@code target} with the specified {@code value}.
+     *
+     * @param target the target referenced by this {@code JsonPointer}
+     * @param value the value to be stored at the referenced location
+     * @return the transformed {@code target} after the value is replaced.
+     * @throws NullPointerException if {@code target} is {@code null}
+     * @throws JsonException if the referenced value does not exist,
+     *    or if the reference is the target.
+     */
+    @Override
+    public JsonStructure replace(JsonStructure target, JsonValue value) {
+        return execute(NodeReference::replace, target, value);
+    }
+
+    /**
+     * Removes the value at the reference location in the specified {@code target}
+     *
+     * @param target the target referenced by this {@code JsonPointer}
+     * @return the transformed {@code target} after the value is removed.
+     * @throws NullPointerException if {@code target} is {@code null}
+     * @throws JsonException if the referenced value does not exist,
+     *    or if the reference is the target.
+     */
+    @Override
+    public JsonStructure remove(JsonStructure target) {
+        return execute((r,v)->r.remove(), target, null);
+    }
+
+    /**
+     * Executes the operation
+     * @param op a {code BiFunction} used to specify the operation to execute on
+     *    the leaf node of the Json Pointer
+     * @param target the target JsonStructure for this JsonPointer
+     * @param value the JsonValue for add and replace, can be null for getvalue and remove
+     */
+    private JsonStructure execute(BiFunction<NodeReference, JsonValue, JsonStructure> op,
+            JsonStructure target, JsonValue value) {
+
+        NodeReference[] refs = getReferences(target);
+        JsonStructure result = op.apply(refs[0], value);
+        for (int i = 1; i < refs.length; i++) {
+            result = refs[i].replace(result);
+        }
+        return result;
+    }
+
+    /**
+     * Computes the {@code NodeReference}s for each node on the path of
+     * the JSON Pointer, in reverse order, starting from the leaf node
+     */
+    private NodeReference[] getReferences(JsonStructure target) {
+        NodeReference[] references;
+        // First check if this is a reference to a JSON value tree
+        if (tokens.length == 1) {
+            references = new NodeReference[1];
+            references[0] = NodeReference.of(target);
+            return references;
+        }
+
+        references = new NodeReference[tokens.length-1];
+        JsonValue value = target;
+        int s = tokens.length;
+        for (int i = 1; i < s; i++) {
+             // Start with index 1, skipping the "" token
+            switch (value.getValueType()) {
+                case OBJECT:
+                    JsonObject object = (JsonObject) value;
+                    references[s-i-1] = NodeReference.of(object, tokens[i]);
+                    if (i < s-1) {
+                        value = object.get(tokens[i]);
+                        if (value == null) {
+                            // Except for the last name, the mapping must exist
+                            throw new JsonException(JsonMessages.POINTER_MAPPING_MISSING(object, tokens[i]));
+                        }
+                    }
+                    break;
+                case ARRAY:
+                    int index = getIndex(tokens[i]);
+                    JsonArray array = (JsonArray) value;
+                    references[s-i-1] = NodeReference.of(array, index);
+                    if (i < s-1 && index != -1) {
+                        if (index >= array.size()) {
+                            throw new JsonException(JsonMessages.NODEREF_ARRAY_INDEX_ERR(index, array.size()));
+                        }
+                        // The last array index in the path can have index value of -1
+                        // ("-" in the JSON pointer)
+                        value = array.get(index);
+                    }
+                    break;
+                default:
+                    throw new JsonException(JsonMessages.POINTER_REFERENCE_INVALID(value.getValueType()));
+             }
+        }
+        return references;
+    }
+
+    /**
+     * Computes the array index
+     * @param token the input string token
+     * @return the array index. -1 if the token is "-"
+     * @throws JsonException if the string token is not in correct format
+     */
+    static private int getIndex(String token) {
+        if (token == null || token.length() == 0) {
+            throw new JsonException(JsonMessages.POINTER_ARRAY_INDEX_ERR(token));
+        }
+        if (token.equals("-")) {
+            return -1;
+        }
+        if (token.equals("0")) {
+            return 0;
+        }
+        if (token.charAt(0) == '+' || token.charAt(0) == '-') {
+            throw new JsonException(JsonMessages.POINTER_ARRAY_INDEX_ERR(token));
+        }
+        try {
+            return Integer.parseInt(token);
+        } catch (NumberFormatException ex) {
+            throw new JsonException(JsonMessages.POINTER_ARRAY_INDEX_ILLEGAL(token), ex);
+       }
+    }
+}
Index: trunk/src/org/glassfish/json/JsonPrettyGeneratorImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonPrettyGeneratorImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonPrettyGeneratorImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -117,4 +117,10 @@
     }
 
+    @Override
+    protected void writeColon() {
+        super.writeColon();
+        writeChar(' ');
+    }
+
     private void writeNewLine() {
         writeChar('\n');
Index: trunk/src/org/glassfish/json/JsonProviderImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonProviderImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonProviderImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -53,10 +53,15 @@
 import java.io.Reader;
 import java.io.Writer;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.math.BigDecimal;
+import java.math.BigInteger;
 
 /**
  * @author Jitendra Kotamraju
+ * @author Kin-man Chung
+ * @author Alex Soto
  */
 public class JsonProviderImpl extends JsonProvider {
@@ -106,5 +111,5 @@
             pool = bufferPool;
         } else {
-            providerConfig = new HashMap<String, Object>();
+            providerConfig = new HashMap<>();
             if (prettyPrinting=JsonProviderImpl.isPrettyPrintingEnabled(config)) {
                 providerConfig.put(JsonGenerator.PRETTY_PRINTING, true);
@@ -152,5 +157,5 @@
             pool = bufferPool;
         } else {
-            providerConfig = new HashMap<String, Object>();
+            providerConfig = new HashMap<>();
             if (prettyPrinting=JsonProviderImpl.isPrettyPrintingEnabled(config)) {
                 providerConfig.put(JsonGenerator.PRETTY_PRINTING, true);
@@ -185,6 +190,91 @@
 
     @Override
+    public JsonObjectBuilder createObjectBuilder(JsonObject object) {
+        return new JsonObjectBuilderImpl(object, bufferPool);
+    }
+
+    @Override
+    public JsonObjectBuilder createObjectBuilder(Map<String, Object> map) {
+        return new JsonObjectBuilderImpl(map, bufferPool);
+    }
+
+    @Override
     public JsonArrayBuilder createArrayBuilder() {
         return new JsonArrayBuilderImpl(bufferPool);
+    }
+
+    @Override
+    public JsonArrayBuilder createArrayBuilder(JsonArray array) {
+        return new JsonArrayBuilderImpl(array, bufferPool);
+    }
+
+    @Override
+    public JsonArrayBuilder createArrayBuilder(Collection<?> collection) {
+        return new JsonArrayBuilderImpl(collection, bufferPool);
+    }
+
+    @Override
+    public JsonPointer createPointer(String jsonPointer) {
+        return new JsonPointerImpl(jsonPointer);
+    }
+
+    @Override
+    public JsonPatchBuilder createPatchBuilder() {
+        return new JsonPatchBuilderImpl();
+    }
+
+    @Override
+    public JsonPatchBuilder createPatchBuilder(JsonArray array) {
+        return new JsonPatchBuilderImpl(array);
+    }
+
+    @Override
+    public JsonPatch createPatch(JsonArray array) {
+        return new JsonPatchImpl(array);
+    }
+
+    @Override
+    public JsonPatch createDiff(JsonStructure source, JsonStructure target) {
+        return new JsonPatchImpl(JsonPatchImpl.diff(source, target));
+    }
+
+    @Override
+    public JsonMergePatch createMergePatch(JsonValue patch) {
+        return new JsonMergePatchImpl(patch);
+    }
+
+    @Override
+    public JsonMergePatch createMergeDiff(JsonValue source, JsonValue target) {
+        return new JsonMergePatchImpl(JsonMergePatchImpl.diff(source, target));
+    }
+
+    @Override
+    public JsonString createValue(String value) {
+        return new JsonStringImpl(value);
+    }
+
+    @Override
+    public JsonNumber createValue(int value) {
+        return JsonNumberImpl.getJsonNumber(value);
+    }
+
+    @Override
+    public JsonNumber createValue(long value) {
+        return JsonNumberImpl.getJsonNumber(value);
+    }
+
+    @Override
+    public JsonNumber createValue(double value) {
+        return JsonNumberImpl.getJsonNumber(value);
+    }
+
+    @Override
+    public JsonNumber createValue(BigInteger value) {
+        return JsonNumberImpl.getJsonNumber(value);
+    }
+
+    @Override
+    public JsonNumber createValue(BigDecimal value) {
+        return JsonNumberImpl.getJsonNumber(value);
     }
 
Index: trunk/src/org/glassfish/json/JsonReaderFactoryImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonReaderFactoryImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonReaderFactoryImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
Index: trunk/src/org/glassfish/json/JsonReaderImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonReaderImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonReaderImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -43,10 +43,15 @@
 import org.glassfish.json.api.BufferPool;
 
-import javax.json.*;
-import javax.json.stream.JsonParser;
 import java.io.InputStream;
 import java.io.Reader;
-import java.math.BigDecimal;
 import java.nio.charset.Charset;
+import javax.json.JsonArray;
+import javax.json.JsonException;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonStructure;
+import javax.json.JsonValue;
+import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParsingException;
 
 /**
@@ -82,12 +87,16 @@
         readDone = true;
         if (parser.hasNext()) {
-            JsonParser.Event e = parser.next();
-            if (e == JsonParser.Event.START_ARRAY) {
-                return readArray(new JsonArrayBuilderImpl(bufferPool));
-            } else if (e == JsonParser.Event.START_OBJECT) {
-                return readObject(new JsonObjectBuilderImpl(bufferPool));
+            try {
+                JsonParser.Event e = parser.next();
+                if (e == JsonParser.Event.START_ARRAY) {
+                    return parser.getArray();
+                } else if (e == JsonParser.Event.START_OBJECT) {
+                    return parser.getObject();
+                }
+            } catch (IllegalStateException ise) {
+                throw new JsonParsingException(ise.getMessage(), ise, parser.getLastCharLocation());
             }
         }
-        throw new JsonException("Internal Error");
+        throw new JsonException(JsonMessages.INTERNAL_ERROR());
     }
 
@@ -99,12 +108,12 @@
         readDone = true;
         if (parser.hasNext()) {
-            JsonParser.Event e = parser.next();
-            if (e == JsonParser.Event.START_OBJECT) {
-                return readObject(new JsonObjectBuilderImpl(bufferPool));
-            } else if (e == JsonParser.Event.START_ARRAY) {
-                throw new JsonException(JsonMessages.READER_EXPECTED_OBJECT_GOT_ARRAY());
+            try {
+                parser.next();
+                return parser.getObject();
+            } catch (IllegalStateException ise) {
+                throw new JsonParsingException(ise.getMessage(), ise, parser.getLastCharLocation());
             }
         }
-        throw new JsonException("Internal Error");
+        throw new JsonException(JsonMessages.INTERNAL_ERROR());
     }
 
@@ -116,12 +125,29 @@
         readDone = true;
         if (parser.hasNext()) {
-            JsonParser.Event e = parser.next();
-            if (e == JsonParser.Event.START_ARRAY) {
-                return readArray(new JsonArrayBuilderImpl(bufferPool));
-            } else if (e == JsonParser.Event.START_OBJECT) {
-                throw new JsonException(JsonMessages.READER_EXPECTED_ARRAY_GOT_OBJECT());
+            try {
+                parser.next();
+                return parser.getArray();
+            } catch (IllegalStateException ise) {
+                throw new JsonParsingException(ise.getMessage(), ise, parser.getLastCharLocation());
             }
         }
-        throw new JsonException("Internal Error");
+        throw new JsonException(JsonMessages.INTERNAL_ERROR());
+    }
+
+    @Override
+    public JsonValue readValue() {
+        if (readDone) {
+            throw new IllegalStateException(JsonMessages.READER_READ_ALREADY_CALLED());
+        }
+        readDone = true;
+        if (parser.hasNext()) {
+            try {
+                parser.next();
+                return parser.getValue();
+            } catch (IllegalStateException ise) {
+                throw new JsonParsingException(ise.getMessage(), ise, parser.getLastCharLocation());
+            }
+        }
+        throw new JsonException(JsonMessages.INTERNAL_ERROR());
     }
 
@@ -131,88 +157,3 @@
         parser.close();
     }
-
-    private JsonArray readArray(JsonArrayBuilder builder) {
-        while(parser.hasNext()) {
-            JsonParser.Event e = parser.next();
-            switch (e) {
-                case START_ARRAY:
-                    JsonArray array = readArray(new JsonArrayBuilderImpl(bufferPool));
-                    builder.add(array);
-                    break;
-                case START_OBJECT:
-                    JsonObject object = readObject(new JsonObjectBuilderImpl(bufferPool));
-                    builder.add(object);
-                    break;
-                case VALUE_STRING:
-                    builder.add(parser.getString());
-                    break;
-                case VALUE_NUMBER:
-                    if (parser.isDefinitelyInt()) {
-                        builder.add(parser.getInt());
-                    } else {
-                        builder.add(parser.getBigDecimal());
-                    }
-                    break;
-                case VALUE_TRUE:
-                    builder.add(JsonValue.TRUE);
-                    break;
-                case VALUE_FALSE:
-                    builder.add(JsonValue.FALSE);
-                    break;
-                case VALUE_NULL:
-                    builder.addNull();
-                    break;
-                case END_ARRAY:
-                    return builder.build();
-                default:
-                    throw new JsonException("Internal Error");
-            }
-        }
-        throw new JsonException("Internal Error");
-    }
-
-    private JsonObject readObject(JsonObjectBuilder builder) {
-        String key = null;
-        while(parser.hasNext()) {
-            JsonParser.Event e = parser .next();
-            switch (e) {
-                case START_ARRAY:
-                    JsonArray array = readArray(new JsonArrayBuilderImpl(bufferPool));
-                    builder.add(key, array);
-                    break;
-                case START_OBJECT:
-                    JsonObject object = readObject(new JsonObjectBuilderImpl(bufferPool));
-                    builder.add(key, object);
-                    break;
-                case KEY_NAME:
-                    key = parser.getString();
-                    break;
-                case VALUE_STRING:
-                    builder.add(key, parser.getString());
-                    break;
-                case VALUE_NUMBER:
-                    if (parser.isDefinitelyInt()) {
-                        builder.add(key, parser.getInt());
-                    } else {
-                        builder.add(key, parser.getBigDecimal());
-                    }
-                    break;
-                case VALUE_TRUE:
-                    builder.add(key, JsonValue.TRUE);
-                    break;
-                case VALUE_FALSE:
-                    builder.add(key, JsonValue.FALSE);
-                    break;
-                case VALUE_NULL:
-                    builder.addNull(key);
-                    break;
-                case END_OBJECT:
-                    return builder.build();
-                default:
-                    throw new JsonException("Internal Error");
-            }
-        }
-        throw new JsonException("Internal Error");
-    }
-
 }
Index: trunk/src/org/glassfish/json/JsonStringImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonStringImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonStringImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -78,4 +78,7 @@
     @Override
     public boolean equals(Object obj) {
+        if (this == obj){
+            return true;
+        }
         if (!(obj instanceof JsonString)) {
             return false;
Index: trunk/src/org/glassfish/json/JsonStructureParser.java
===================================================================
--- trunk/src/org/glassfish/json/JsonStructureParser.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonStructureParser.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -45,5 +45,9 @@
 import javax.json.stream.JsonParser;
 import java.math.BigDecimal;
-import java.util.*;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
 
 /**
@@ -56,5 +60,5 @@
     private Scope current;
     private Event state;
-    private final Deque<Scope> scopeStack = new ArrayDeque<Scope>();
+    private final Deque<Scope> scopeStack = new ArrayDeque<>();
 
     JsonStructureParser(JsonArray array) {
@@ -68,10 +72,14 @@
     @Override
     public String getString() {
-        if (state == Event.KEY_NAME) {
-            return ((ObjectScope)current).key;
-        } else if (state == Event.VALUE_STRING) {
-            return ((JsonString)current.getJsonValue()).getString();
-        }
-        throw new IllegalStateException(JsonMessages.PARSER_GETSTRING_ERR(state));
+        switch (state) {
+            case KEY_NAME:
+                return ((ObjectScope)current).key;
+            case VALUE_STRING:
+                return ((JsonString)current.getJsonValue()).getString();
+            case VALUE_NUMBER:
+                return ((JsonNumber)current.getJsonValue()).toString();
+            default:
+                throw new IllegalStateException(JsonMessages.PARSER_GETSTRING_ERR(state));
+        }
     }
 
@@ -168,4 +176,60 @@
     public void close() {
         // no-op
+    }
+
+    @Override
+    public void skipObject() {
+        if (current instanceof ObjectScope) {
+            int depth = 1;
+            do {
+                if (state == Event.KEY_NAME) {
+                    state = getState(current.getJsonValue());
+                    switch (state) {
+                        case START_OBJECT:
+                            depth++;
+                            break;
+                        case END_OBJECT:
+                            depth--;
+                            break;
+                        default:
+                            //no-op
+                    }
+                } else {
+                    if (current.hasNext()) {
+                        current.next();
+                        state = Event.KEY_NAME;
+                    } else {
+                        state = Event.END_OBJECT;
+                        depth--;
+                    }
+                }
+            } while (state != Event.END_OBJECT && depth > 0);
+        }
+    }
+
+    @Override
+    public void skipArray() {
+        if (current instanceof ArrayScope) {
+            int depth = 1;
+            do {
+                if (current.hasNext()) {
+                    current.next();
+                    state = getState(current.getJsonValue());
+                    switch (state) {
+                        case START_ARRAY:
+                            depth++;
+                            break;
+                        case END_ARRAY:
+                            depth--;
+                            break;
+                        default:
+                            //no-op
+                    }
+                } else {
+                    state = Event.END_ARRAY;
+                    depth--;
+                }
+            } while (!(state == Event.END_ARRAY && depth == 0));
+        }
     }
 
@@ -187,5 +251,5 @@
                 return Event.VALUE_NULL;
             default:
-                throw new JsonException("Unknown value type="+value.getValueType());
+                throw new JsonException(JsonMessages.PARSER_STATE_ERR(value.getValueType()));
         }
     }
@@ -200,5 +264,5 @@
                 return new ObjectScope((JsonObject)value);
             }
-            throw new JsonException("Cannot be called for value="+value);
+            throw new JsonException(JsonMessages.PARSER_SCOPE_ERR(value));
         }
     }
Index: trunk/src/org/glassfish/json/JsonTokenizer.java
===================================================================
--- trunk/src/org/glassfish/json/JsonTokenizer.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonTokenizer.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -293,6 +293,9 @@
             }
         }
-        readBegin--;
-        storeEnd = readBegin;
+        if (ch != -1) {
+            // Only reset readBegin if eof has not been reached
+            readBegin--;
+            storeEnd = readBegin;
+        }
     }
 
@@ -417,4 +420,47 @@
     }
 
+    boolean hasNextToken() {
+        reset();
+        int ch = peek();
+
+        // whitespace
+        while (ch == 0x20 || ch == 0x09 || ch == 0x0a || ch == 0x0d) {
+            if (ch == '\r') {
+                ++lineNo;
+                ++readBegin;
+                ch = peek();
+                if (ch == '\n') {
+                    lastLineOffset = bufferOffset+readBegin+1;
+                } else {
+                    lastLineOffset = bufferOffset+readBegin;
+                    continue;
+                }
+            } else if (ch == '\n') {
+                ++lineNo;
+                lastLineOffset = bufferOffset+readBegin+1;
+            }
+            ++readBegin;
+            ch = peek();
+        }
+        return ch != -1;
+    }
+
+    private int peek() {
+        try {
+            if (readBegin == readEnd) {     // need to fill the buffer
+                int len = fillBuf();
+                if (len == -1) {
+                    return -1;
+                }
+                assert len != 0;
+                readBegin = storeEnd;
+                readEnd = readBegin+len;
+            }
+            return buf[readBegin];
+        } catch (IOException ioe) {
+            throw new JsonException(JsonMessages.TOKENIZER_IO_ERR(), ioe);
+        }
+    }
+
     // Gives the location of the last char. Used for
     // JsonParsingException.getLocation
@@ -499,5 +545,5 @@
         // no need to create BigDecimal for common integer values (1-9 digits)
         int storeLen = storeEnd-storeBegin;
-        if (!fracOrExp && (storeLen <= 9 || (minus && storeLen == 10))) {
+        if (!fracOrExp && (storeLen <= 9 || (minus && storeLen <= 10))) {
             int num = 0;
             int i = minus ? 1 : 0;
@@ -510,4 +556,19 @@
         }
     }
+    
+    long getLong() {
+        // no need to create BigDecimal for common integer values (1-18 digits)
+        int storeLen = storeEnd-storeBegin;
+        if (!fracOrExp && (storeLen <= 18 || (minus && storeLen <= 19))) {
+            long num = 0;
+            int i = minus ? 1 : 0;
+            for(; i < storeLen; i++) {
+                num = num * 10 + (buf[storeBegin+i] - '0');
+            }
+            return minus ? -num : num;
+        } else {
+            return getBigDecimal().longValue();
+        }
+    }
 
     // returns true for common integer values (1-9 digits).
@@ -515,5 +576,12 @@
     boolean isDefinitelyInt() {
         int storeLen = storeEnd-storeBegin;
-        return !fracOrExp && (storeLen <= 9 || (minus && storeLen == 10));
+        return !fracOrExp && (storeLen <= 9 || (minus && storeLen <= 10));
+    }
+    
+    // returns true for common long values (1-18 digits).
+    // So there are cases it will return false even though the number is long
+    boolean isDefinitelyLong() {
+    	int storeLen = storeEnd-storeBegin;
+    	return !fracOrExp && (storeLen <= 18 || (minus && storeLen <= 19));
     }
 
Index: trunk/src/org/glassfish/json/JsonUtil.java
===================================================================
--- trunk/src/org/glassfish/json/JsonUtil.java	(revision 13231)
+++ trunk/src/org/glassfish/json/JsonUtil.java	(revision 13231)
@@ -0,0 +1,99 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2015-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package org.glassfish.json;
+
+import java.io.StringReader;
+import javax.json.Json;
+import javax.json.JsonReader;
+import javax.json.JsonValue;
+import javax.json.stream.JsonParsingException;
+
+/**
+ * A utility class
+ * 
+ * @since 1.1
+ */
+public final class JsonUtil {
+
+    private JsonUtil() {
+    }
+
+    /**
+     * Reads the input JSON text and returns a JsonValue.
+     * <p>For convenience, single quotes as well as double quotes
+     * are allowed to delimit JSON strings. If single quotes are
+     * used, any quotes, single or double, in the JSON string must be
+     * escaped (prepend with a '\').
+     *
+     * @param jsonString the input JSON data
+     * @return the object model for {@code jsonString}
+     * @throws JsonParsingException if the input is not legal JSON text
+     */
+    public static JsonValue toJson(String jsonString) {
+        StringBuilder builder = new StringBuilder();
+        boolean single_context = false;
+        for (int i = 0; i < jsonString.length(); i++) {
+            char ch = jsonString.charAt(i);
+            if (ch == '\\') {
+                i = i + 1;
+                if (i < jsonString.length()) {
+                    ch = jsonString.charAt(i);
+                    if (!(single_context && ch == '\'')) {
+                        // unescape ' inside single quotes
+                        builder.append('\\');
+                    }
+                }
+            } else if (ch == '\'') {
+                // Turn ' into ", for proper JSON string
+                ch = '"';
+                single_context = ! single_context;
+            }
+            builder.append(ch);
+        }
+                   
+        JsonReader reader = Json.createReader(
+                                new StringReader(builder.toString()));
+        JsonValue value = reader.readValue();
+        reader.close();
+        return value;
+    }
+}
+
Index: trunk/src/org/glassfish/json/JsonWriterFactoryImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonWriterFactoryImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonWriterFactoryImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
Index: trunk/src/org/glassfish/json/JsonWriterImpl.java
===================================================================
--- trunk/src/org/glassfish/json/JsonWriterImpl.java	(revision 6756)
+++ trunk/src/org/glassfish/json/JsonWriterImpl.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -49,4 +49,5 @@
 import java.io.Writer;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
@@ -57,5 +58,4 @@
  */
 class JsonWriterImpl implements JsonWriter {
-    private static final Charset UTF_8 = Charset.forName("UTF-8");
 
     private final JsonGeneratorImpl generator;
@@ -75,9 +75,9 @@
 
     JsonWriterImpl(OutputStream out, BufferPool bufferPool) {
-        this(out, UTF_8, false, bufferPool);
+        this(out, StandardCharsets.UTF_8, false, bufferPool);
     }
 
     JsonWriterImpl(OutputStream out, boolean prettyPrinting, BufferPool bufferPool) {
-        this(out, UTF_8, prettyPrinting, bufferPool);
+        this(out, StandardCharsets.UTF_8, prettyPrinting, bufferPool);
     }
 
@@ -146,4 +146,26 @@
 
     @Override
+    public void write(JsonValue value) {
+        switch (value.getValueType()) {
+            case OBJECT:
+                writeObject((JsonObject) value);
+                return;
+            case ARRAY:
+                writeArray((JsonArray) value);
+                return;
+            default:
+                if (writeDone) {
+                    throw new IllegalStateException(JsonMessages.WRITER_WRITE_ALREADY_CALLED());
+                }
+                writeDone = true;
+                generator.write(value);
+                generator.flushBuffer();
+                if (os != null) {
+                    generator.flush();
+                }
+        }
+    }
+
+    @Override
     public void close() {
         writeDone = true;
Index: trunk/src/org/glassfish/json/MapUtil.java
===================================================================
--- trunk/src/org/glassfish/json/MapUtil.java	(revision 13231)
+++ trunk/src/org/glassfish/json/MapUtil.java	(revision 13231)
@@ -0,0 +1,115 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package org.glassfish.json;
+
+import org.glassfish.json.api.BufferPool;
+
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonValue;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Util for transforming a Map to a Json objects.
+ *
+ * @author asotobu
+ */
+public final class MapUtil {
+
+    private MapUtil() {
+        super();
+    }
+
+    static JsonValue handle(Object value, BufferPool bufferPool) {
+
+        if (value == null) {
+            return JsonValue.NULL;
+        }
+
+        if (value instanceof BigDecimal) {
+            return JsonNumberImpl.getJsonNumber((BigDecimal) value);
+        } else {
+            if (value instanceof BigInteger) {
+                return JsonNumberImpl.getJsonNumber((BigInteger) value);
+            } else {
+                if ( value instanceof Boolean) {
+                    Boolean b = (Boolean) value;
+                    return b ? JsonValue.TRUE : JsonValue.FALSE;
+                } else {
+                    if (value instanceof Double) {
+                        return JsonNumberImpl.getJsonNumber((Double) value);
+                    } else {
+                        if (value instanceof Integer) {
+                            return JsonNumberImpl.getJsonNumber((Integer) value);
+                        } else {
+                            if (value instanceof Long) {
+                                return JsonNumberImpl.getJsonNumber((Long) value);
+                            } else {
+                                if (value instanceof String) {
+                                    return new JsonStringImpl((String) value);
+                                } else {
+                                    if (value instanceof Collection) {
+                                        @SuppressWarnings("unchecked")
+                                        Collection<?> collection = (Collection<?>) value;
+                                        JsonArrayBuilder jsonArrayBuilder = new JsonArrayBuilderImpl(collection, bufferPool);
+                                        return jsonArrayBuilder.build();
+                                    } else {
+                                        if (value instanceof Map) {
+                                            @SuppressWarnings("unchecked")
+                                            JsonObjectBuilder object = new JsonObjectBuilderImpl((Map<String, Object>) value, bufferPool);
+                                            return object.build();
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        throw new IllegalArgumentException(String.format("Type %s is not supported.", value.getClass()));
+    }
+
+}
Index: trunk/src/org/glassfish/json/NodeReference.java
===================================================================
--- trunk/src/org/glassfish/json/NodeReference.java	(revision 13231)
+++ trunk/src/org/glassfish/json/NodeReference.java	(revision 13231)
@@ -0,0 +1,307 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2015-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package org.glassfish.json;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonException;
+import javax.json.JsonObject;
+import javax.json.JsonStructure;
+import javax.json.JsonValue;
+
+/**
+ * This class is a helper class for JsonPointer implementation,
+ * and is not part of the API.
+ *
+ * This class encapsulates a reference to a JSON node.
+ * There are three types of references.
+ * <ol><li>a reference to the root of a JSON tree.</li>
+ *     <li>a reference to a name/value (possibly non-existing) pair of a JSON object, identified by a name.</li>
+ *     <li>a reference to a member value of a JSON array, identified by an index.</li>
+ * </ol>
+ * Static factory methods are provided for creating these references.
+ *
+ * <p>A referenced value can be retrieved or replaced.
+ * The value of a JSON object or JSON array can be
+ * removed.  A new value can be added to a JSON object or
+ * inserted into a JSON array</p>
+ *
+ * <p>Since a {@code JsonObject} or {@code JsonArray} is immutable, these operations
+ * must not modify the referenced JSON object or array. The methods {@link #add},
+ * {@link #replace}, and {@link #remove} returns a new
+ * JSON object or array after the execution of the operation.</p>
+ */
+abstract class NodeReference {
+
+    /**
+     * Return {@code true} if a reference points to a valid value, {@code false} otherwise.
+     *
+     * @return {@code true} if a reference points to a value
+     */
+    abstract public boolean contains();
+
+    /**
+     * Get the value at the referenced location.
+     *
+     * @return the JSON value referenced
+     * @throws JsonException if the referenced value does not exist
+     */
+    abstract public JsonValue get();
+
+    /**
+     * Add or replace a value at the referenced location.
+     * If the reference is the root of a JSON tree, the added value must be
+     * a JSON object or array, which becomes the referenced JSON value.
+     * If the reference is an index of a JSON array, the value is inserted
+     * into the array at the index.  If the index is -1, the value is
+     * appended to the array.
+     * If the reference is a name of a JSON object, the name/value pair is added
+     * to the object, replacing any pair with the same name.
+     *
+     * @param value the value to be added
+     * @return the JsonStructure after the operation
+     * @throws JsonException if the index to the array is not -1 or is out of range
+     */
+    abstract public JsonStructure add(JsonValue value);
+
+    /**
+     * Remove the name/value pair from the JSON object, or the value in a JSON array, as specified by the reference
+     *
+     * @return the JsonStructure after the operation
+     * @throws JsonException if the name/value pair of the referenced JSON object
+     *    does not exist, or if the index of the referenced JSON array is
+     *    out of range, or if the reference is a root reference
+     */
+    abstract public JsonStructure remove();
+
+    /**
+     * Replace the referenced value with the specified value.
+     *
+     * @param value the JSON value to be stored at the referenced location
+     * @return the JsonStructure after the operation
+     * @throws JsonException if the name/value pair of the referenced JSON object
+     *    does not exist, or if the index of the referenced JSON array is
+     *    out of range, or if the reference is a root reference
+     */
+    abstract public JsonStructure replace(JsonValue value);
+
+    /**
+     * Returns a {@code NodeReference} for a {@code JsonStructure}.
+     *
+     * @param structure the {@code JsonStructure} referenced
+     * @return the {@code NodeReference}
+     */
+    public static NodeReference of(JsonStructure structure) {
+        return new RootReference(structure);
+    }
+
+    /**
+     * Returns a {@code NodeReference} for a name/value pair in a
+     * JSON object.
+     *
+     * @param object the referenced JSON object
+     * @param name the name of the name/pair
+     * @return the {@code NodeReference}
+     */
+    public static NodeReference of(JsonObject object, String name) {
+        return new ObjectReference(object, name);
+    }
+
+    /**
+     * Returns a {@code NodeReference} for a member value in a
+     * JSON array.
+     *
+     * @param array the referenced JSON array
+     * @param index the index of the member value in the JSON array
+     * @return the {@code NodeReference}
+     */
+    public static NodeReference of(JsonArray array, int index) {
+        return new ArrayReference(array, index);
+    }
+
+    static class RootReference extends NodeReference {
+
+        private JsonStructure root;
+
+        RootReference(JsonStructure root) {
+            this.root = root;
+        }
+
+        @Override
+        public boolean contains() {
+            return root != null;
+        }
+
+        @Override
+        public JsonValue get() {
+            return root;
+        }
+
+        @Override
+        public JsonStructure add(JsonValue value) {
+            switch (value.getValueType() ) {
+                case OBJECT:
+                case ARRAY:
+                    this.root = (JsonStructure) value;
+                    break;
+                default:
+                    throw new JsonException(JsonMessages.NODEREF_VALUE_ADD_ERR());
+            }
+            return root;
+        }
+
+        @Override
+        public JsonStructure remove() {
+            throw new JsonException(JsonMessages.NODEREF_VALUE_CANNOT_REMOVE());
+        }
+
+        @Override
+        public JsonStructure replace(JsonValue value) {
+            return add(value);
+        }
+    }
+
+    static class ObjectReference extends NodeReference {
+
+        private final JsonObject object;
+        private final String key;
+
+        ObjectReference(JsonObject object, String key) {
+            this.object = object;
+            this.key = key;
+        }
+
+        @Override
+        public boolean contains() {
+            return object != null && object.containsKey(key);
+        }
+
+        @Override
+        public JsonValue get() {
+            if (!contains()) {
+                throw new JsonException(JsonMessages.NODEREF_OBJECT_MISSING(key));
+            }
+            return object.get(key);
+        }
+
+        @Override
+        public JsonObject add(JsonValue value) {
+            return Json.createObjectBuilder(object).add(key, value).build();
+        }
+
+        @Override
+        public JsonObject remove() {
+            if (!contains()) {
+                throw new JsonException(JsonMessages.NODEREF_OBJECT_MISSING(key));
+            }
+            return Json.createObjectBuilder(object).remove(key).build();
+        }
+
+        @Override
+        public JsonObject replace(JsonValue value) {
+            if (!contains()) {
+                throw new JsonException(JsonMessages.NODEREF_OBJECT_MISSING(key));
+            }
+            return add(value);
+        }
+    }
+
+    static class ArrayReference extends NodeReference {
+
+        private final JsonArray array;
+        private final int index; // -1 means "-" in JSON Pointer
+
+        ArrayReference(JsonArray array, int index) {
+            this.array = array;
+            this.index = index;
+        }
+
+        @Override
+        public boolean contains() {
+            return array != null && index > -1 && index < array.size();
+        }
+
+        @Override
+        public JsonValue get() {
+            if (!contains()) {
+                throw new JsonException(JsonMessages.NODEREF_ARRAY_INDEX_ERR(index, array.size()));
+            }
+            return array.get(index);
+        }
+
+        @Override
+        public JsonArray add(JsonValue value) {
+            //TODO should we check for arrayoutofbounds?
+            // The spec seems to say index = array.size() is allowed. This is handled as append
+            JsonArrayBuilder builder = Json.createArrayBuilder(this.array);
+            if (index == -1 || index == array.size()) {
+                builder.add(value);
+            } else {
+                if(index < array.size()) {
+                    builder.add(index, value);
+                } else {
+                    throw new JsonException(JsonMessages.NODEREF_ARRAY_INDEX_ERR(index, array.size()));
+                }
+            }
+            return builder.build();
+        }
+
+        @Override
+        public JsonArray remove() {
+            if (!contains()) {
+                throw new JsonException(JsonMessages.NODEREF_ARRAY_INDEX_ERR(index, array.size()));
+            }
+            JsonArrayBuilder builder = Json.createArrayBuilder(this.array);
+            return builder.remove(index).build();
+        }
+
+        @Override
+        public JsonArray replace(JsonValue value) {
+            if (!contains()) {
+                throw new JsonException(JsonMessages.NODEREF_ARRAY_INDEX_ERR(index, array.size()));
+            }
+            JsonArrayBuilder builder = Json.createArrayBuilder(this.array);
+            return builder.set(index, value).build();
+        }
+    }
+}
+
Index: trunk/src/org/glassfish/json/UnicodeDetectingInputStream.java
===================================================================
--- trunk/src/org/glassfish/json/UnicodeDetectingInputStream.java	(revision 6756)
+++ trunk/src/org/glassfish/json/UnicodeDetectingInputStream.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -46,4 +46,5 @@
 import java.io.InputStream;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 
 /**
@@ -54,7 +55,5 @@
  */
 class UnicodeDetectingInputStream extends FilterInputStream {
-    private static final Charset UTF_8 = Charset.forName("UTF-8");
-    private static final Charset UTF_16BE = Charset.forName("UTF-16BE");
-    private static final Charset UTF_16LE = Charset.forName("UTF-16LE");
+
     private static final Charset UTF_32LE = Charset.forName("UTF-32LE");
     private static final Charset UTF_32BE = Charset.forName("UTF-32BE");
@@ -122,5 +121,5 @@
             buf[3] = (byte)b4;
         } catch (IOException ioe) {
-            throw new JsonException("I/O error while auto-detecting the encoding of stream", ioe);
+            throw new JsonException(JsonMessages.PARSER_INPUT_ENC_DETECT_IOERR(), ioe);
         }
     }
@@ -129,5 +128,5 @@
         fillBuf();
         if (bufLen < 2) {
-            throw new JsonException("Cannot auto-detect encoding, not enough chars");
+            throw new JsonException(JsonMessages.PARSER_INPUT_ENC_DETECT_FAILED());
         } else if (bufLen == 4) {
             // Use BOM to detect encoding
@@ -140,11 +139,11 @@
             } else if (buf[0] == FE && buf[1] == FF) {
                 curIndex = 2;
-                return UTF_16BE;
+                return StandardCharsets.UTF_16BE;
             } else if (buf[0] == FF && buf[1] == FE) {
                 curIndex = 2;
-                return UTF_16LE;
+                return StandardCharsets.UTF_16LE;
             } else if (buf[0] == EF && buf[1] == BB && buf[2] == BF) {
                 curIndex = 3;
-                return UTF_8;
+                return StandardCharsets.UTF_8;
             }
             // No BOM, just use JSON RFC's encoding algo to auto-detect
@@ -152,12 +151,12 @@
                 return UTF_32BE;
             } else if (buf[0] == NUL && buf[2] == NUL) {
-                return UTF_16BE;
+                return StandardCharsets.UTF_16BE;
             } else if (buf[1] == NUL && buf[2] == NUL && buf[3] == NUL) {
                 return UTF_32LE;
             } else if (buf[1] == NUL && buf[3] == NUL) {
-                return UTF_16LE;
+                return StandardCharsets.UTF_16LE;
             }
         }
-        return UTF_8;
+        return StandardCharsets.UTF_8;
     }
 
Index: trunk/src/org/glassfish/json/api/BufferPool.java
===================================================================
--- trunk/src/org/glassfish/json/api/BufferPool.java	(revision 6756)
+++ trunk/src/org/glassfish/json/api/BufferPool.java	(revision 13231)
@@ -2,5 +2,5 @@
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
@@ -9,10 +9,10 @@
  * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt.  See the License for the specific
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
+ * file and include the License file at LICENSE.txt.
  *
  * GPL Classpath Exception:
@@ -61,4 +61,6 @@
     /**
      * Returns an object back to the pool.
+     *
+     * @param buf object to return back to the pool
      */
     void recycle(char[] buf);
Index: trunk/src/org/glassfish/json/messages.properties
===================================================================
--- trunk/src/org/glassfish/json/messages.properties	(revision 13231)
+++ trunk/src/org/glassfish/json/messages.properties	(revision 13231)
@@ -0,0 +1,112 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright (c) 2013-2017 Oracle and/or its affiliates. All rights reserved.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common Development
+# and Distribution License("CDDL") (collectively, the "License").  You
+# may not use this file except in compliance with the License.  You can
+# obtain a copy of the License at
+# https://oss.oracle.com/licenses/CDDL+GPL-1.1
+# or LICENSE.txt.  See the License for the specific
+# language governing permissions and limitations under the License.
+#
+# When distributing the software, include this License Header Notice in each
+# file and include the License file at LICENSE.txt.
+#
+# GPL Classpath Exception:
+# Oracle designates this particular file as subject to the "Classpath"
+# exception as provided by Oracle in the GPL Version 2 section of the License
+# file that accompanied this code.
+#
+# Modifications:
+# If applicable, add the following below the License Header, with the fields
+# enclosed by brackets [] replaced by your own identifying information:
+# "Portions Copyright [year] [name of copyright owner]"
+#
+# Contributor(s):
+# If you wish your version of this file to be governed by only the CDDL or
+# only the GPL Version 2, indicate your decision by adding "[Contributor]
+# elects to include this software in this distribution under the [CDDL or GPL
+# Version 2] license."  If you don't indicate a single choice of license, a
+# recipient has the option to distribute your version of this file under
+# either the CDDL, the GPL Version 2 or to extend the choice of license to
+# its licensees as provided above.  However, if you add GPL Version 2 code
+# and therefore, elected the GPL Version 2 license, then the option applies
+# only if the new code is made subject to such option by the copyright
+# holder.
+#
+
+internal.error=Internal Error
+
+parser.getString.err=JsonParser#getString() is valid only for KEY_NAME, VALUE_STRING, VALUE_NUMBER parser states. \
+  But current parser state is {0}
+parser.isIntegralNumber.err=JsonParser#isIntegralNumber() is valid only for VALUE_NUMBER parser state. \
+  But current parser state is {0}
+parser.getInt.err=JsonParser#getInt() is valid only for VALUE_NUMBER parser state. \
+  But current parser state is {0}
+parser.getLong.err=JsonParser#getLong() is valid only for VALUE_NUMBER parser state. \
+  But current parser state is {0}
+parser.getBigDecimal.err=JsonParser#getBigDecimal() is valid only for VALUE_NUMBER parser state. \
+  But current parser state is {0}
+parser.getArray.err=JsonParser#getArray() or JsonParser#getArrayStream() is valid only for START_ARRAY parser state. \
+  But current parser state is {0}
+parser.getObject.err=JsonParser#getObject() or JsonParser#getObjectStream() is valid only for START_OBJECT parser state. \
+  But current parser state is {0}
+parser.getValue.err=JsonParser#getValue() is valid only for START_ARRAY, START_OBJECT, KEY_NAME, VALUE_STRING, VALUE_NUMBER, VALUE_NULL, VALUE_FALSE, VALUE_TRUE parser states. \
+  But current parser state is {0}
+parser.getValueStream.err=JsonParser#getValueStream() the parser must not be in an array or object. \
+  But current parser state is {0}
+parser.expected.eof=Expected EOF token, but got {0}
+parser.tokenizer.close.io=I/O error while closing JSON tokenizer
+parser.invalid.token=Invalid token={0} at {1}. Expected tokens are: {2}
+parser.state.err=Unknown value type {0}
+parser.scope.err=Cannot be called for value {0}
+parser.input.enc.detect.failed=Cannot auto-detect encoding, not enough chars
+parser.input.enc.detect.ioerr=I/O error while auto-detecting the encoding of stream
+
+generator.flush.io.err=I/O error while flushing generated JSON
+generator.close.io.err=I/O error while closing JsonGenerator
+generator.write.io.err=I/O error while writing in JsonGenerator
+generator.illegal.method=Illegal method during JSON generation, \
+  not valid in current context {0}
+generator.double.infinite.nan=double value cannot be Infinite or NaN
+generator.incomplete.json=Generating incomplete JSON
+generator.illegal.multiple.text=Cannot generate more than one JSON text
+
+writer.write.already.called=write/writeObject/writeArray/close method is already called
+
+reader.read.already.called=read/readObject/readArray/close method is already called
+
+objbuilder.name.null=Name in JsonObject's name/value pair cannot be null
+objbuilder.value.null=Value in JsonObject's name/value pair cannot be null
+objbuilder.object.builder.null=Object builder that is used to create a value in JsonObject's name/value pair cannot be null
+objbuilder.array.builder.null=Array builder that is used to create a value in JsonObject's name/value pair cannot be null
+
+arrbuilder.value.null=Cannot invoke add(null) while building JsonArray.
+arrbuilder.object.builder.null=Object builder that is used to add a value to JSON array cannot be null
+arrbuilder.array.builder.null=Array builder that is used to add a value to JSON array cannot be null
+arrbuilder.valuelist.null=Index: {0}, Size: {1}
+
+tokenizer.unexpected.char=Unexpected char {0} at {1}
+tokenizer.expected.char=Unexpected char {0} at {1}, expecting ''{2}''
+tokenizer.io.err=I/O error while parsing JSON
+
+pointer.format.invalid=A non-empty JSON Pointer must begin with a ''/''
+pointer.mapping.missing=The JSON Object ''{0}'' contains no mapping for the name ''{1}''
+pointer.reference.invalid=The reference value in a JSON Pointer must be a JSON Object or a JSON Array, was ''{0}''
+pointer.array.index.err=Array index format error, was ''{0}''
+pointer.array.index.illegal=Illegal integer format, was ''{0}''
+
+noderef.value.add.err=The root value only allows adding a JSON object or array
+noderef.value.cannot.remove=The JSON value at the root cannot be removed
+noderef.object.missing=Non-existing name/value pair in the object for key {0}
+noderef.array.index.err=An array item index is out of range. Index: {0}, Size: {1}
+
+patch.must.be.array=A JSON Patch must be an array of JSON Objects
+patch.move.proper.prefix=The ''{0}'' path of the patch operation ''move'' is a proper prefix of the ''{1}'' path
+patch.move.target.null=The ''{0}'' path of the patch operation ''move'' does not exist in target object
+patch.test.failed=The JSON Patch operation ''test'' failed for path ''{0}'' and value ''{1}''
+patch.illegal.operation=Illegal value for the op member of the JSON Patch operation: ''{0}''
+patch.member.missing=The JSON Patch operation ''{0}'' must contain a ''{1}'' member
