You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2018/05/19 14:08:18 UTC

[1/7] groovy git commit: GROOVY-8379: Rework groovy-json FastStringUtils (closes #667)

Repository: groovy
Updated Branches:
  refs/heads/GROOVY_2_5_X 3fbd0b6f6 -> 25e2a3866


http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/LazyMapTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/LazyMapTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/LazyMapTest.groovy
new file mode 100644
index 0000000..607ad73
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/LazyMapTest.groovy
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal
+
+class LazyMapTest extends GroovyTestCase {
+
+    // GROOVY-7302
+    void testSizeWhenNoBackingMapCreated() {
+        def map = new LazyMap()
+        map.someProperty = "1"
+        map.someProperty = "2"
+        map.someProperty = "3"
+        assert map.size() == 1
+        map.someProperty2 = "4"
+        assert map.size() == 2
+    }
+
+    void testSizeWhenLazyCreated() {
+        def map = new LazyMap()
+        map.someProperty1 = '1'
+        assert map.@map == null
+        map.someProperty2 = '2'
+        assert map.@map == null
+        map.someProperty3 = '3'
+        assert map.@map == null
+        map.someProperty4 = '4'
+        assert map.@map == null
+        map.someProperty5 = '5'
+        assert map.@map == null
+        map.someProperty6 = '6'
+        assert map.@map == null
+        map.someProperty7 = '7'
+        assert map.someProperty6 == '6'
+        assert map.@map?.size() == 7
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ReaderCharacterSourceTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ReaderCharacterSourceTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ReaderCharacterSourceTest.groovy
new file mode 100644
index 0000000..f45a0ef
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ReaderCharacterSourceTest.groovy
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal
+
+import org.apache.groovy.json.internal.Exceptions.JsonInternalException
+
+class ReaderCharacterSourceTest extends GroovyTestCase {
+
+    public static final int QUOTE_CHAR = (int)'"'.charAt(0)
+    public static final int BACKSLASH_CHAR = (int)'\\'.charAt(0)
+
+    void testFindNextChar() {
+        def testCases = [
+                [ input: '""', expected: '' ],
+                [ input: '"word"', expected: 'word' ],
+                [ input: '"\\u0026value"', expected: '\\u0026value' ],
+                [ input: '"value\\u0026"', expected: 'value\\u0026' ],
+                [ input: '"double\\"quote"', expected: 'double\\"quote' ],
+                [ input: '"\\"\\"\\"\\""', expected: '\\"\\"\\"\\"' ],
+                [ input: '"\\\\\\\\\\\\"', expected: '\\\\\\\\\\\\' ]
+        ]
+
+        testCases.each {
+            boolean containsEscape = it.input.contains('\\')
+            // Test all possible buffer sizes
+            for (int i = 1; i < it.input.length() + 1; i++) {
+                ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader(it.input), i)
+                rcs.nextChar() // Read the first double quote as if JSON parsing
+
+                String result = new String(rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR))
+
+                assertEquals("Buffer size ${i}", it.expected, result)
+                assertEquals("Expected escape character in ${it.input}, buffer size ${i}", containsEscape, rcs.hadEscape())
+            }
+        }
+    }
+
+    void testFindNextCharException() {
+        shouldFail(JsonInternalException) {
+            ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote'))
+            rcs.nextChar() // Read the first double quote as if JSON parsing
+            rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
+        }
+    }
+
+    void testFindNextCharExceptionWithEscapedEnding() {
+        shouldFail(JsonInternalException) {
+            ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote ending with escape \\'))
+            rcs.nextChar() // Read the first double quote as if JSON parsing
+            rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
+        }
+    }
+
+    void testFindNextCharExceptionWithEscapedQuote() {
+        shouldFail(JsonInternalException) {
+            ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote with escaped quote \\"'))
+            rcs.nextChar() // Read the first double quote as if JSON parsing
+            rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
+        }
+    }
+}


[7/7] groovy git commit: GROOVY-8379: Rework groovy-json FastStringUtils (closes #667)

Posted by pa...@apache.org.
GROOVY-8379: Rework groovy-json FastStringUtils (closes #667)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/25e2a386
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/25e2a386
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/25e2a386

Branch: refs/heads/GROOVY_2_5_X
Commit: 25e2a3866de4d11a3d9681863db3c19fef91fd22
Parents: 3fbd0b6
Author: paulk <pa...@asert.com.au>
Authored: Sun Feb 25 20:11:03 2018 +1000
Committer: Paul King <pa...@asert.com.au>
Committed: Sun May 20 00:08:03 2018 +1000

----------------------------------------------------------------------
 gradle/binarycompatibility.gradle               |   2 +-
 settings.gradle                                 |   1 +
 subprojects/groovy-json-direct/build.gradle     |  22 +
 .../jsondirect/DirectFastStringService.java     |  47 ++
 .../DirectFastStringServiceFactory.java         |  86 ++
 ....apache.groovy.json.FastStringServiceFactory |  19 +
 .../DirectFastStringServiceTest.groovy          |  39 +
 .../java/groovy/json/DefaultJsonGenerator.java  |   4 +-
 .../src/main/java/groovy/json/JsonOutput.java   |   4 +-
 .../src/main/java/groovy/json/JsonSlurper.java  |   8 +-
 .../java/groovy/json/internal/ArrayUtils.java   |  32 -
 .../groovy/json/internal/BaseJsonParser.java    | 228 -----
 .../java/groovy/json/internal/ByteScanner.java  |  70 --
 .../main/java/groovy/json/internal/Cache.java   |  40 -
 .../java/groovy/json/internal/CacheType.java    |  30 -
 .../main/java/groovy/json/internal/CharBuf.java | 842 -------------------
 .../java/groovy/json/internal/CharScanner.java  | 512 -----------
 .../groovy/json/internal/CharSequenceValue.java | 278 ------
 .../groovy/json/internal/CharacterSource.java   |  81 --
 .../src/main/java/groovy/json/internal/Chr.java | 213 -----
 .../main/java/groovy/json/internal/Dates.java   | 184 ----
 .../java/groovy/json/internal/Exceptions.java   | 178 ----
 .../groovy/json/internal/FastStringUtils.java   | 191 -----
 .../src/main/java/groovy/json/internal/IO.java  |  91 --
 .../groovy/json/internal/JsonFastParser.java    | 334 --------
 .../json/internal/JsonParserCharArray.java      | 386 ---------
 .../groovy/json/internal/JsonParserLax.java     | 677 ---------------
 .../JsonParserUsingCharacterSource.java         | 298 -------
 .../groovy/json/internal/JsonStringDecoder.java |  38 -
 .../main/java/groovy/json/internal/LazyMap.java | 205 -----
 .../java/groovy/json/internal/LazyValueMap.java | 247 ------
 .../java/groovy/json/internal/MapItemValue.java |  80 --
 .../java/groovy/json/internal/NumberValue.java  | 216 -----
 .../json/internal/ReaderCharacterSource.java    | 264 ------
 .../java/groovy/json/internal/SimpleCache.java  |  72 --
 .../src/main/java/groovy/json/internal/Sys.java |  84 --
 .../main/java/groovy/json/internal/Type.java    |  28 -
 .../main/java/groovy/json/internal/Value.java   |  63 --
 .../groovy/json/internal/ValueContainer.java    | 174 ----
 .../java/groovy/json/internal/ValueList.java    | 123 ---
 .../java/groovy/json/internal/ValueMap.java     |  46 -
 .../java/groovy/json/internal/ValueMapImpl.java | 147 ----
 .../groovy/json/DefaultFastStringService.java   |  36 +
 .../json/DefaultFastStringServiceFactory.java   |  26 +
 .../apache/groovy/json/FastStringService.java   |  33 +
 .../groovy/json/FastStringServiceFactory.java   |  28 +
 .../apache/groovy/json/internal/ArrayUtils.java |  32 +
 .../groovy/json/internal/BaseJsonParser.java    | 228 +++++
 .../groovy/json/internal/ByteScanner.java       |  70 ++
 .../org/apache/groovy/json/internal/Cache.java  |  40 +
 .../apache/groovy/json/internal/CacheType.java  |  30 +
 .../apache/groovy/json/internal/CharBuf.java    | 842 +++++++++++++++++++
 .../groovy/json/internal/CharScanner.java       | 512 +++++++++++
 .../groovy/json/internal/CharSequenceValue.java | 278 ++++++
 .../groovy/json/internal/CharacterSource.java   |  81 ++
 .../org/apache/groovy/json/internal/Chr.java    | 213 +++++
 .../org/apache/groovy/json/internal/Dates.java  | 184 ++++
 .../apache/groovy/json/internal/Exceptions.java | 178 ++++
 .../groovy/json/internal/FastStringUtils.java   |  85 ++
 .../org/apache/groovy/json/internal/IO.java     |  91 ++
 .../groovy/json/internal/JsonFastParser.java    | 334 ++++++++
 .../json/internal/JsonParserCharArray.java      | 386 +++++++++
 .../groovy/json/internal/JsonParserLax.java     | 677 +++++++++++++++
 .../JsonParserUsingCharacterSource.java         | 298 +++++++
 .../groovy/json/internal/JsonStringDecoder.java |  38 +
 .../apache/groovy/json/internal/LazyMap.java    | 205 +++++
 .../groovy/json/internal/LazyValueMap.java      | 247 ++++++
 .../groovy/json/internal/MapItemValue.java      |  80 ++
 .../groovy/json/internal/NumberValue.java       | 219 +++++
 .../json/internal/ReaderCharacterSource.java    | 264 ++++++
 .../groovy/json/internal/SimpleCache.java       |  72 ++
 .../org/apache/groovy/json/internal/Sys.java    |  84 ++
 .../org/apache/groovy/json/internal/Type.java   |  28 +
 .../org/apache/groovy/json/internal/Value.java  |  63 ++
 .../groovy/json/internal/ValueContainer.java    | 174 ++++
 .../apache/groovy/json/internal/ValueList.java  | 123 +++
 .../apache/groovy/json/internal/ValueMap.java   |  46 +
 .../groovy/json/internal/ValueMapImpl.java      | 147 ++++
 ....apache.groovy.json.FastStringServiceFactory |  19 +
 .../test/groovy/groovy/json/CharBufTest.groovy  |   2 +-
 .../groovy/json/CustomJsonGeneratorTest.groovy  |   2 +-
 .../src/test/groovy/groovy/json/IOTest.groovy   |   4 +-
 .../groovy/groovy/json/JsonSlurperTest.groovy   |   2 +-
 .../groovy/json/internal/ArrayUtilsTest.groovy  |  27 -
 .../groovy/json/internal/CharScannerTest.groovy | 288 -------
 .../groovy/groovy/json/internal/ChrTest.groovy  | 152 ----
 .../groovy/json/internal/DatesTest.groovy       |  48 --
 .../json/internal/FastStringUtilsTest.groovy    |  54 --
 .../FastStringUtilsUnsafeDisabledTest.groovy    |  60 --
 .../groovy/json/internal/LazyMapTest.groovy     |  52 --
 .../internal/ReaderCharacterSourceTest.groovy   |  77 --
 .../json/DefaultFastStringServiceTest.groovy    |  35 +
 .../groovy/json/internal/ArrayUtilsTest.groovy  |  27 +
 .../groovy/json/internal/CharScannerTest.groovy | 288 +++++++
 .../apache/groovy/json/internal/ChrTest.groovy  | 152 ++++
 .../groovy/json/internal/DatesTest.groovy       |  47 ++
 .../groovy/json/internal/LazyMapTest.groovy     |  52 ++
 .../internal/ReaderCharacterSourceTest.groovy   |  77 ++
 98 files changed, 7397 insertions(+), 7224 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/gradle/binarycompatibility.gradle
----------------------------------------------------------------------
diff --git a/gradle/binarycompatibility.gradle b/gradle/binarycompatibility.gradle
index 43713aa..274838b 100644
--- a/gradle/binarycompatibility.gradle
+++ b/gradle/binarycompatibility.gradle
@@ -35,7 +35,7 @@ task checkBinaryCompatibility {
 check.dependsOn(checkBinaryCompatibility)
 
 // for comparing between versions with different modules, set excludeModules to differing modules, e.g.
-def excludeModules = ['groovy-cli-picocli', 'groovy-cli-commons', 'groovy-dateutil', 'groovy-datetime', 'performance', 'groovy-macro', 'tests-vm8']
+def excludeModules = ['groovy-cli-picocli', 'groovy-cli-commons', 'groovy-dateutil', 'groovy-datetime', 'performance', 'groovy-macro', 'tests-vm8', 'groovy-json-direct']
 //def excludeModules = []
 
 Set projectsToCheck = allprojects.findAll{ !(it.name in excludeModules) }

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/settings.gradle
----------------------------------------------------------------------
diff --git a/settings.gradle b/settings.gradle
index 651936d..d9c4fa6 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -27,6 +27,7 @@ def subprojects = ['groovy-ant',
         'groovy-groovysh',
         'groovy-jmx',
         'groovy-json',
+        'groovy-json-direct',
         'groovy-jsr223',
         'groovy-nio',
         'groovy-servlet',

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json-direct/build.gradle
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json-direct/build.gradle b/subprojects/groovy-json-direct/build.gradle
new file mode 100644
index 0000000..68b6ed2
--- /dev/null
+++ b/subprojects/groovy-json-direct/build.gradle
@@ -0,0 +1,22 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+dependencies {
+    compile project(':groovy-json')
+    testCompile project(':groovy-test')
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringService.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringService.java b/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringService.java
new file mode 100644
index 0000000..0d7d4ad
--- /dev/null
+++ b/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringService.java
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.jsondirect;
+
+import org.apache.groovy.json.FastStringService;
+
+import static org.apache.groovy.jsondirect.DirectFastStringServiceFactory.STRING_VALUE_FIELD_OFFSET;
+import static org.apache.groovy.jsondirect.DirectFastStringServiceFactory.WRITE_TO_FINAL_FIELDS;
+import static org.apache.groovy.jsondirect.DirectFastStringServiceFactory.UNSAFE;
+
+/**
+ * Internal class for fast processing of Strings during JSON parsing - direct field writing version.
+ * Works for JDK 7 and 8 but uses the Unsafe mechanism of Java.
+ */
+public class DirectFastStringService implements FastStringService {
+    @Override
+    public char[] toCharArray(String string) {
+        return (char[]) UNSAFE.getObject(string, STRING_VALUE_FIELD_OFFSET);
+    }
+
+    @Override
+    public String noCopyStringFromChars(char[] chars) {
+        if (WRITE_TO_FINAL_FIELDS) {
+            String string = new String();
+            UNSAFE.putObject(string, STRING_VALUE_FIELD_OFFSET, chars);
+            return string;
+        } else {
+            return new String(chars);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringServiceFactory.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringServiceFactory.java b/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringServiceFactory.java
new file mode 100644
index 0000000..90f0626
--- /dev/null
+++ b/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringServiceFactory.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.jsondirect;
+
+import org.apache.groovy.json.FastStringService;
+import org.apache.groovy.json.FastStringServiceFactory;
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Field;
+
+public class DirectFastStringServiceFactory implements FastStringServiceFactory {
+    static final Unsafe UNSAFE;
+    static final long STRING_VALUE_FIELD_OFFSET;
+    private static final boolean ENABLED;
+
+    static final boolean WRITE_TO_FINAL_FIELDS = Boolean.parseBoolean(System.getProperty("groovy.json.faststringutils.write.to.final.fields", "false"));
+    private static final boolean DISABLE = Boolean.parseBoolean(System.getProperty("groovy.json.faststringutils.disable", "false"));
+
+    private static Unsafe loadUnsafe() {
+        try {
+            Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
+            unsafeField.setAccessible(true);
+            return (Unsafe) unsafeField.get(null);
+
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    static {
+        UNSAFE = DISABLE ? null : loadUnsafe();
+        ENABLED = UNSAFE != null;
+    }
+
+    private static long getFieldOffset(String fieldName) {
+        if (ENABLED) {
+            try {
+                return UNSAFE.objectFieldOffset(String.class.getDeclaredField(fieldName));
+            } catch (NoSuchFieldException e) {
+                // field undefined
+            }
+        }
+        return -1L;
+    }
+
+    static {
+        STRING_VALUE_FIELD_OFFSET = getFieldOffset("value");
+    }
+
+    @Override
+    public FastStringService getService() {
+        if (STRING_VALUE_FIELD_OFFSET != -1L && valueFieldIsCharArray()) {
+            return new DirectFastStringService();
+        }
+        // safe to return null here because then we'll get the default provider
+        return null;
+    }
+
+    /**
+     * JDK9 Compat Strings enhancement changed the internal representation of the value field from a char[]
+     * to a byte[] (see http://openjdk.java.net/jeps/254).
+     *
+     * @return true if internal String value field is a char[], otherwise false
+     */
+    private static boolean valueFieldIsCharArray() {
+        Object o = UNSAFE.getObject("", STRING_VALUE_FIELD_OFFSET);
+        return (o instanceof char[]);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json-direct/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json-direct/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory b/subprojects/groovy-json-direct/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
new file mode 100644
index 0000000..cbb3713
--- /dev/null
+++ b/subprojects/groovy-json-direct/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
@@ -0,0 +1,19 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+#
+org.apache.groovy.jsondirect.DirectFastStringServiceFactory

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json-direct/src/test/groovy/org/apache/groovy/jsondirect/DirectFastStringServiceTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json-direct/src/test/groovy/org/apache/groovy/jsondirect/DirectFastStringServiceTest.groovy b/subprojects/groovy-json-direct/src/test/groovy/org/apache/groovy/jsondirect/DirectFastStringServiceTest.groovy
new file mode 100644
index 0000000..fe05828
--- /dev/null
+++ b/subprojects/groovy-json-direct/src/test/groovy/org/apache/groovy/jsondirect/DirectFastStringServiceTest.groovy
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.jsondirect
+
+import org.apache.groovy.json.FastStringService
+
+class DirectFastStringServiceTest extends GroovyTestCase {
+
+    FastStringService service = new DirectFastStringServiceFactory().service
+
+    void testToCharArray() {
+        if (!service) return
+        def str = "some test"
+        assert service.toCharArray(str) == str.toCharArray()
+    }
+
+    void testNoCopyStringFromChars() {
+        if (!service) return
+        def source = "äöüliu"
+        def chars = source.toCharArray()
+        assert service.noCopyStringFromChars(chars) == source
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/DefaultJsonGenerator.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/DefaultJsonGenerator.java b/subprojects/groovy-json/src/main/java/groovy/json/DefaultJsonGenerator.java
index 6510d4d..1e530e2 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/DefaultJsonGenerator.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/DefaultJsonGenerator.java
@@ -18,8 +18,8 @@
  */
 package groovy.json;
 
-import groovy.json.internal.CharBuf;
-import groovy.json.internal.Chr;
+import org.apache.groovy.json.internal.CharBuf;
+import org.apache.groovy.json.internal.Chr;
 import groovy.lang.Closure;
 import groovy.util.Expando;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
index 63bbf1d..a650915 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
@@ -18,8 +18,8 @@
  */
 package groovy.json;
 
-import groovy.json.internal.CharBuf;
-import groovy.json.internal.Chr;
+import org.apache.groovy.json.internal.CharBuf;
+import org.apache.groovy.json.internal.Chr;
 import groovy.lang.Closure;
 import groovy.util.Expando;
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java
index 8808a05..dd931f0 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java
@@ -18,10 +18,10 @@
  */
 package groovy.json;
 
-import groovy.json.internal.JsonFastParser;
-import groovy.json.internal.JsonParserCharArray;
-import groovy.json.internal.JsonParserLax;
-import groovy.json.internal.JsonParserUsingCharacterSource;
+import org.apache.groovy.json.internal.JsonFastParser;
+import org.apache.groovy.json.internal.JsonParserCharArray;
+import org.apache.groovy.json.internal.JsonParserLax;
+import org.apache.groovy.json.internal.JsonParserUsingCharacterSource;
 import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport;
 import org.codehaus.groovy.runtime.ResourceGroovyMethods;
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ArrayUtils.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ArrayUtils.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ArrayUtils.java
deleted file mode 100644
index 7bd54a5..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ArrayUtils.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Richard Hightower
- */
-public class ArrayUtils {
-
-    public static char[] copyRange(char[] source, int startIndex, int endIndex) {
-        int len = endIndex - startIndex;
-        char[] copy = new char[len];
-        System.arraycopy(source, startIndex, copy, 0, Math.min(source.length - startIndex, len));
-        return copy;
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java
deleted file mode 100644
index 10facaf..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-import groovy.json.JsonParser;
-import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport;
-import org.codehaus.groovy.runtime.ResourceGroovyMethods;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Base JSON parser.
- * Scaled down version of Boon JsonParser with features
- * removed that are JDK 1.7 dependent or Groovy duplicated functionality.
- *
- * @author Rick Hightower
- */
-public abstract class BaseJsonParser implements JsonParser {
-
-    protected static final int COLON = ':';
-    protected static final int COMMA = ',';
-    protected static final int CLOSED_CURLY = '}';
-    protected static final int CLOSED_BRACKET = ']';
-
-    protected static final int LETTER_E = 'e';
-    protected static final int LETTER_BIG_E = 'E';
-
-    protected static final int MINUS = '-';
-    protected static final int PLUS = '+';
-
-    protected static final int DECIMAL_POINT = '.';
-
-    protected static final int ALPHA_0 = '0';
-    protected static final int ALPHA_1 = '1';
-    protected static final int ALPHA_2 = '2';
-    protected static final int ALPHA_3 = '3';
-    protected static final int ALPHA_4 = '4';
-    protected static final int ALPHA_5 = '5';
-    protected static final int ALPHA_6 = '6';
-    protected static final int ALPHA_7 = '7';
-    protected static final int ALPHA_8 = '8';
-    protected static final int ALPHA_9 = '9';
-
-    protected static final int DOUBLE_QUOTE = '"';
-
-    protected static final int ESCAPE = '\\';
-
-    protected static final boolean internKeys = Boolean.parseBoolean(System.getProperty("groovy.json.internKeys", "false"));
-    protected static ConcurrentHashMap<String, String> internedKeysCache;
-
-    private static final Charset UTF_8 = Charset.forName("UTF-8");
-
-    protected String charset = UTF_8.name();
-
-    private CharBuf fileInputBuf;
-
-    protected int bufSize = 256;
-
-    static {
-        if (internKeys) {
-            internedKeysCache = new ConcurrentHashMap<String, String>();
-        }
-    }
-
-    protected String charDescription(int c) {
-        String charString;
-        if (c == ' ') {
-            charString = "[SPACE]";
-        } else if (c == '\t') {
-            charString = "[TAB]";
-
-        } else if (c == '\n') {
-            charString = "[NEWLINE]";
-
-        } else {
-            charString = "'" + (char) c + "'";
-        }
-
-        charString = charString + " with an int value of " + ((int) c);
-        return charString;
-    }
-
-    public void setCharset(String charset) {
-        this.charset = charset;
-    }
-
-    public Object parse(String jsonString) {
-        return parse(FastStringUtils.toCharArray(jsonString));
-    }
-
-    public Object parse(byte[] bytes) {
-        return parse(bytes, charset);
-    }
-
-    public Object parse(byte[] bytes, String charset) {
-        try {
-            return parse(new String(bytes, charset));
-        } catch (UnsupportedEncodingException e) {
-            return Exceptions.handle(Object.class, e);
-        }
-    }
-
-    public Object parse(CharSequence charSequence) {
-        return parse(FastStringUtils.toCharArray(charSequence));
-    }
-
-    public Object parse(Reader reader) {
-        fileInputBuf = IO.read(reader, fileInputBuf, bufSize);
-        return parse(fileInputBuf.readForRecycle());
-    }
-
-    public Object parse(InputStream input) {
-        return parse(input, charset);
-    }
-
-    public Object parse(InputStream input, String charset) {
-        try {
-            return parse(new InputStreamReader(input, charset));
-        } catch (UnsupportedEncodingException e) {
-            return Exceptions.handle(Object.class, e);
-        }
-    }
-
-    public Object parse(File file, String charset) {
-        Reader reader = null;
-        try {
-            if (charset == null || charset.length() == 0) {
-                reader = ResourceGroovyMethods.newReader(file);
-            } else {
-                reader = ResourceGroovyMethods.newReader(file, charset);
-            }
-            return parse(reader);
-        } catch (IOException ioe) {
-            throw new JsonException("Unable to process file: " + file.getPath(), ioe);
-        } finally {
-            if (reader != null) {
-                DefaultGroovyMethodsSupport.closeWithWarning(reader);
-            }
-        }
-    }
-
-    protected static boolean isDecimalChar(int currentChar) {
-        switch (currentChar) {
-            case MINUS:
-            case PLUS:
-            case LETTER_E:
-            case LETTER_BIG_E:
-            case DECIMAL_POINT:
-                return true;
-        }
-        return false;
-    }
-
-    protected static boolean isDelimiter(int c) {
-        return c == COMMA || c == CLOSED_CURLY || c == CLOSED_BRACKET;
-    }
-
-    protected static final boolean isNumberDigit(int c) {
-        return c >= ALPHA_0 && c <= ALPHA_9;
-    }
-
-    protected static final boolean isDoubleQuote(int c) {
-        return c == DOUBLE_QUOTE;
-    }
-
-    protected static final boolean isEscape(int c) {
-        return c == ESCAPE;
-    }
-
-    protected static boolean hasEscapeChar(char[] array, int index, int[] indexHolder) {
-        char currentChar;
-        for (; index < array.length; index++) {
-            currentChar = array[index];
-            if (isDoubleQuote(currentChar)) {
-                indexHolder[0] = index;
-                return false;
-            } else if (isEscape(currentChar)) {
-                indexHolder[0] = index;
-                return true;
-            }
-        }
-
-        indexHolder[0] = index;
-        return false;
-    }
-
-    int[] indexHolder = new int[1];
-
-    protected static int findEndQuote(final char[] array, int index) {
-        char currentChar;
-        boolean escape = false;
-
-        for (; index < array.length; index++) {
-            currentChar = array[index];
-            if (isDoubleQuote(currentChar)) {
-                if (!escape) {
-                    break;
-                }
-            }
-            escape = isEscape(currentChar) && !escape;
-        }
-        return index;
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java
deleted file mode 100644
index 51219b2..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import static groovy.json.internal.Exceptions.die;
-
-/**
- * @author Richard Hightower
- */
-public class ByteScanner {
-
-    /**
-     * Turns a single nibble into an ascii HEX digit.
-     *
-     * @param nibble the nibble to serializeObject.
-     * @return the encoded nibble (1/2 byte).
-     */
-    protected static int encodeNibbleToHexAsciiCharByte(final int nibble) {
-        switch (nibble) {
-            case 0x00:
-            case 0x01:
-            case 0x02:
-            case 0x03:
-            case 0x04:
-            case 0x05:
-            case 0x06:
-            case 0x07:
-            case 0x08:
-            case 0x09:
-                return nibble + 0x30; // 0x30('0') - 0x39('9')
-            case 0x0A:
-            case 0x0B:
-            case 0x0C:
-            case 0x0D:
-            case 0x0E:
-            case 0x0F:
-                return nibble + 0x57; // 0x41('a') - 0x46('f')
-            default:
-                die("illegal nibble: " + nibble);
-                return -1;
-        }
-    }
-
-    /**
-     * Turn a single bytes into two hex character representation.
-     *
-     * @param decoded the byte to serializeObject.
-     * @param encoded the array to which each encoded nibbles are now ascii hex representations.
-     */
-    public static void encodeByteIntoTwoAsciiCharBytes(final int decoded, final byte[] encoded) {
-        encoded[0] = (byte) encodeNibbleToHexAsciiCharByte((decoded >> 4) & 0x0F);
-        encoded[1] = (byte) encodeNibbleToHexAsciiCharByte(decoded & 0x0F);
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java
deleted file mode 100644
index 9eff815..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-/**
- * Cache
- *
- * @param <KEY>   key
- * @param <VALUE> value
- * @author Rick Hightower
- */
-public interface Cache<KEY, VALUE> {
-
-    void put(KEY key, VALUE value);
-
-    VALUE get(KEY key);
-
-    VALUE getSilent(KEY key);
-
-    void remove(KEY key);
-
-    int size();
-}
-

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/CacheType.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CacheType.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CacheType.java
deleted file mode 100644
index 8ecf99b..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CacheType.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Rick Hightower
- */
-public enum CacheType {
-
-    LRU,
-    LFU,
-    FIFO
-}
-

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java
deleted file mode 100644
index f7e1b29..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-
-/**
- * @author Rick Hightower
- */
-public class CharBuf extends Writer implements CharSequence {
-
-    protected int capacity = 16;
-    protected int location = 0;
-
-    protected char[] buffer;
-
-    public CharBuf(char[] buffer) {
-        __init__(buffer);
-    }
-
-    private void __init__(char[] buffer) {
-        this.buffer = buffer;
-        this.capacity = buffer.length;
-    }
-
-    public CharBuf(byte[] bytes) {
-        this.buffer = null;
-        try {
-            String str = new String(bytes, "UTF-8");
-            __init__(FastStringUtils.toCharArray(str));
-        } catch (UnsupportedEncodingException e) {
-            Exceptions.handle(e);
-        }
-    }
-
-    public static CharBuf createExact(final int capacity) {
-        return new CharBuf(capacity) {
-            public CharBuf add(char[] chars) {
-                Chr._idx(buffer, location, chars);
-                location += chars.length;
-                return this;
-            }
-        };
-    }
-
-    public static CharBuf create(int capacity) {
-        return new CharBuf(capacity);
-    }
-
-    public static CharBuf create(char[] buffer) {
-        return new CharBuf(buffer);
-    }
-
-    protected CharBuf(int capacity) {
-        this.capacity = capacity;
-        init();
-    }
-
-    protected CharBuf() {
-        init();
-    }
-
-    public void write(char[] cbuf, int off, int len) {
-        if (off == 0 && cbuf.length == len) {
-            this.add(cbuf);
-        } else {
-            char[] buffer = ArrayUtils.copyRange(cbuf, off, off + len);
-            this.add(buffer);
-        }
-    }
-
-    public void flush() throws IOException {
-    }
-
-    public void close() throws IOException {
-    }
-
-    public void init() {
-        buffer = new char[capacity];
-    }
-
-    public final CharBuf add(String str) {
-        add(FastStringUtils.toCharArray(str));
-        return this;
-    }
-
-    public final CharBuf addString(String str) {
-        add(FastStringUtils.toCharArray(str));
-        return this;
-    }
-
-    public final CharBuf add(int i) {
-        add(Integer.toString(i));
-        return this;
-    }
-
-    private Cache<Integer, char[]> icache;
-
-    public final CharBuf addInt(int i) {
-        switch (i) {
-            case 0:
-                addChar('0');
-                return this;
-            case 1:
-                addChar('1');
-                return this;
-            case -1:
-                addChar('-');
-                addChar('1');
-                return this;
-        }
-
-        addInt(Integer.valueOf(i));
-        return this;
-    }
-
-    public final CharBuf addInt(Integer key) {
-        if (icache == null) {
-            icache = new SimpleCache<Integer, char[]>(20);
-        }
-        char[] chars = icache.get(key);
-
-        if (chars == null) {
-            String str = Integer.toString(key);
-            chars = FastStringUtils.toCharArray(str);
-            icache.put(key, chars);
-        }
-
-        addChars(chars);
-        return this;
-    }
-
-    final char[] trueChars = "true".toCharArray();
-    final char[] falseChars = "false".toCharArray();
-
-    public final CharBuf add(boolean b) {
-        addChars(b ? trueChars : falseChars);
-        return this;
-    }
-
-    public final CharBuf addBoolean(boolean b) {
-        add(Boolean.toString(b));
-        return this;
-    }
-
-    public final CharBuf add(byte i) {
-        add(Byte.toString(i));
-        return this;
-    }
-
-    public final CharBuf addByte(byte i) {
-        addInt(i);
-        return this;
-    }
-
-    public final CharBuf add(short i) {
-        add(Short.toString(i));
-        return this;
-    }
-
-    public final CharBuf addShort(short i) {
-        addInt(i);
-        return this;
-    }
-
-    public final CharBuf add(long l) {
-        add(Long.toString(l));
-        return this;
-    }
-
-    public final CharBuf add(double d) {
-        add(Double.toString(d));
-        return this;
-    }
-
-    private Cache<Double, char[]> dcache;
-
-    public final CharBuf addDouble(double d) {
-        addDouble(Double.valueOf(d));
-        return this;
-    }
-
-    public final CharBuf addDouble(Double key) {
-        if (dcache == null) {
-            dcache = new SimpleCache<Double, char[]>(20);
-        }
-        char[] chars = dcache.get(key);
-
-        if (chars == null) {
-            String str = Double.toString(key);
-            chars = FastStringUtils.toCharArray(str);
-            dcache.put(key, chars);
-        }
-
-        add(chars);
-        return this;
-    }
-
-    public final CharBuf add(float d) {
-        add(Float.toString(d));
-        return this;
-    }
-
-    private Cache<Float, char[]> fcache;
-
-    public final CharBuf addFloat(float d) {
-        addFloat(Float.valueOf(d));
-        return this;
-    }
-
-    public final CharBuf addFloat(Float key) {
-        if (fcache == null) {
-            fcache = new SimpleCache<Float, char[]>(20);
-        }
-        char[] chars = fcache.get(key);
-
-        if (chars == null) {
-            String str = Float.toString(key);
-            chars = FastStringUtils.toCharArray(str);
-            fcache.put(key, chars);
-        }
-
-        add(chars);
-
-        return this;
-    }
-
-    public final CharBuf addChar(byte i) {
-        add((char) i);
-        return this;
-    }
-
-    public final CharBuf addChar(int i) {
-        add((char) i);
-        return this;
-    }
-
-    public final CharBuf addChar(short i) {
-        add((char) i);
-        return this;
-    }
-
-    public final CharBuf addChar(final char ch) {
-        int _location = location;
-        char[] _buffer = buffer;
-        int _capacity = capacity;
-
-        if (1 + _location > _capacity) {
-            _buffer = Chr.grow(_buffer);
-            _capacity = _buffer.length;
-        }
-
-        _buffer[_location] = ch;
-        _location++;
-
-        location = _location;
-        buffer = _buffer;
-        capacity = _capacity;
-        return this;
-    }
-
-    public CharBuf addLine(String str) {
-        add(str.toCharArray());
-        add('\n');
-        return this;
-    }
-
-    public CharBuf addLine(CharSequence str) {
-        add(str.toString());
-        add('\n');
-        return this;
-    }
-
-    public CharBuf add(char[] chars) {
-        if (chars.length + location > capacity) {
-            buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
-            capacity = buffer.length;
-        }
-
-        Chr._idx(buffer, location, chars);
-        location += chars.length;
-        return this;
-    }
-
-    public final CharBuf addChars(char[] chars) {
-        if (chars.length + location > capacity) {
-            buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
-            capacity = buffer.length;
-        }
-
-        System.arraycopy(chars, 0, buffer, location, chars.length);
-        location += chars.length;
-        return this;
-    }
-
-    public final CharBuf addQuoted(char[] chars) {
-        int _location = location;
-        char[] _buffer = buffer;
-        int _capacity = capacity;
-
-        int sizeNeeded = chars.length + 2 + _location;
-        if (sizeNeeded > _capacity) {
-            _buffer = Chr.grow(_buffer, sizeNeeded * 2);
-            _capacity = _buffer.length;
-        }
-        _buffer[_location] = '"';
-        _location++;
-
-        System.arraycopy(chars, 0, _buffer, _location, chars.length);
-
-        _location += (chars.length);
-        _buffer[_location] = '"';
-        _location++;
-
-        location = _location;
-        buffer = _buffer;
-        capacity = _capacity;
-        return this;
-    }
-
-    public final CharBuf addJsonEscapedString(String jsonString) {
-        return addJsonEscapedString(jsonString, false);
-    }
-
-    public final CharBuf addJsonEscapedString(String jsonString, boolean disableUnicodeEscaping) {
-        char[] charArray = FastStringUtils.toCharArray(jsonString);
-        return addJsonEscapedString(charArray, disableUnicodeEscaping);
-    }
-
-    private static boolean shouldEscape(int c, boolean disableUnicodeEscaping) {
-        if (c < 32) { /* less than space is a control char */
-            return true;
-        } else if (c == 34) {  /* double quote */
-            return true;
-        } else if (c == 92) {  /* backslash */
-            return true;
-        } else if (!disableUnicodeEscaping && c > 126) {  /* non-ascii char range */
-            return true;
-        }
-
-        return false;
-    }
-
-    private static boolean hasAnyJSONControlChars(final char[] charArray, boolean disableUnicodeEscaping) {
-        int index = 0;
-        char c;
-        while (true) {
-            c = charArray[index];
-            if (shouldEscape(c, disableUnicodeEscaping)) {
-                return true;
-            }
-            if (++index >= charArray.length) return false;
-        }
-    }
-
-    public final CharBuf addJsonEscapedString(final char[] charArray) {
-        return addJsonEscapedString(charArray, false);
-    }
-
-    public final CharBuf addJsonEscapedString(final char[] charArray, boolean disableUnicodeEscaping) {
-        if (charArray.length == 0) return this;
-        if (hasAnyJSONControlChars(charArray, disableUnicodeEscaping)) {
-            return doAddJsonEscapedString(charArray, disableUnicodeEscaping);
-        } else {
-            return this.addQuoted(charArray);
-        }
-    }
-
-    final byte[] encoded = new byte[2];
-
-    final byte[] charTo = new byte[2];
-
-    private CharBuf doAddJsonEscapedString(char[] charArray, boolean disableUnicodeEscaping) {
-        char[] _buffer = buffer;
-        int _location = this.location;
-
-        final byte[] _encoded = encoded;
-
-        final byte[] _charTo = charTo;
-        /* We are making a bet that not all chars will be unicode. */
-        int ensureThisMuch = charArray.length * 6 + 2;
-
-        int sizeNeeded = (ensureThisMuch) + _location;
-        if (sizeNeeded > capacity) {
-            int growBy = (_buffer.length * 2) < sizeNeeded ? sizeNeeded : (_buffer.length * 2);
-            _buffer = Chr.grow(buffer, growBy);
-            capacity = _buffer.length;
-        }
-
-        _buffer[_location] = '"';
-        _location++;
-
-        int index = 0;
-        while (true) {
-            char c = charArray[index];
-
-            if (shouldEscape(c, disableUnicodeEscaping)) {
-                   /* We are covering our bet with a safety net.
-                      otherwise we would have to have 5x buffer
-                      allocated for control chars */
-                if (_location + 5 > _buffer.length) {
-                    _buffer = Chr.grow(_buffer, 20);
-                }
-
-                switch (c) {
-                    case '\"':
-                        _buffer[_location] = '\\';
-                        _location++;
-                        _buffer[_location] = '"';
-                        _location++;
-                        break;
-                    case '\\':
-                        _buffer[_location] = '\\';
-                        _location++;
-                        _buffer[_location] = '\\';
-                        _location++;
-                        break;
-                    //There is not requirement to escape solidus so we will not.
-//                        case '/':
-//                            _buffer[_location] = '\\';
-//                            _location ++;
-//                            _buffer[_location] =  '/';
-//                            _location ++;
-//                            break;
-
-                    case '\b':
-                        _buffer[_location] = '\\';
-                        _location++;
-                        _buffer[_location] = 'b';
-                        _location++;
-                        break;
-                    case '\f':
-                        _buffer[_location] = '\\';
-                        _location++;
-                        _buffer[_location] = 'f';
-                        _location++;
-                        break;
-                    case '\n':
-                        _buffer[_location] = '\\';
-                        _location++;
-                        _buffer[_location] = 'n';
-                        _location++;
-                        break;
-                    case '\r':
-                        _buffer[_location] = '\\';
-                        _location++;
-                        _buffer[_location] = 'r';
-                        _location++;
-                        break;
-                    case '\t':
-                        _buffer[_location] = '\\';
-                        _location++;
-                        _buffer[_location] = 't';
-                        _location++;
-                        break;
-                    default:
-                        _buffer[_location] = '\\';
-                        _location++;
-                        _buffer[_location] = 'u';
-                        _location++;
-                        if (c <= 255) {
-                            _buffer[_location] = '0';
-                            _location++;
-                            _buffer[_location] = '0';
-                            _location++;
-                            ByteScanner.encodeByteIntoTwoAsciiCharBytes(c, _encoded);
-                            for (int b : _encoded) {
-                                _buffer[_location] = (char) b;
-                                _location++;
-                            }
-                        } else {
-                            _charTo[1] = (byte) (c);
-                            _charTo[0] = (byte) (c >>> 8);
-
-                            for (int charByte : _charTo) {
-                                ByteScanner.encodeByteIntoTwoAsciiCharBytes(charByte, _encoded);
-                                for (int b : _encoded) {
-                                    _buffer[_location] = (char) b;
-                                    _location++;
-                                }
-                            }
-                        }
-                }
-            } else {
-                _buffer[_location] = c;
-                _location++;
-            }
-
-            if (++index >= charArray.length) break;
-        }
-        _buffer[_location] = '"';
-        _location++;
-
-        buffer = _buffer;
-        location = _location;
-
-        return this;
-    }
-
-    public final CharBuf addJsonFieldName(String str) {
-        return addJsonFieldName(str, false);
-    }
-
-    public final CharBuf addJsonFieldName(String str, boolean disableUnicodeEscaping) {
-        return addJsonFieldName(FastStringUtils.toCharArray(str), disableUnicodeEscaping);
-    }
-
-    private static final char[] EMPTY_STRING_CHARS = Chr.array('"', '"');
-
-    public final CharBuf addJsonFieldName(char[] chars) {
-        return addJsonFieldName(chars, false);
-    }
-
-    public final CharBuf addJsonFieldName(char[] chars, boolean disableUnicodeEscaping) {
-        if (chars.length > 0) {
-            addJsonEscapedString(chars, disableUnicodeEscaping);
-        } else {
-            addChars(EMPTY_STRING_CHARS);
-        }
-        addChar(':');
-        return this;
-    }
-
-    public final CharBuf addQuoted(String str) {
-        final char[] chars = FastStringUtils.toCharArray(str);
-        addQuoted(chars);
-        return this;
-    }
-
-    public CharBuf add(char[] chars, final int length) {
-        if (length + location < capacity) {
-            Chr._idx(buffer, location, chars, length);
-        } else {
-            buffer = Chr.grow(buffer, buffer.length * 2 + length);
-            Chr._idx(buffer, location, chars);
-            capacity = buffer.length;
-        }
-        location += length;
-        return this;
-    }
-
-    public CharBuf add(byte[] chars) {
-        if (chars.length + location < capacity) {
-            Chr._idx(buffer, location, chars);
-        } else {
-            buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
-            Chr._idx(buffer, location, chars);
-            capacity = buffer.length;
-        }
-        location += chars.length;
-        return this;
-    }
-
-    public CharBuf add(byte[] bytes, int start, int end) {
-        int charsLength = end - start;
-        if (charsLength + location > capacity) {
-            buffer = Chr.grow(buffer, buffer.length * 2 + charsLength);
-        }
-        Chr._idx(buffer, location, bytes, start, end);
-        capacity = buffer.length;
-        location += charsLength;
-        return this;
-    }
-
-    public final CharBuf add(char ch) {
-        if (1 + location < capacity) {
-            buffer[location] = ch;
-        } else {
-            buffer = Chr.grow(buffer);
-            buffer[location] = ch;
-            capacity = buffer.length;
-        }
-        location += 1;
-        return this;
-    }
-
-    public int length() {
-        return len();
-    }
-
-    public char charAt(int index) {
-        return buffer[index];
-    }
-
-    public CharSequence subSequence(int start, int end) {
-        return new String(buffer, start, end - start);
-    }
-
-    public String toString() {
-        return new String(buffer, 0, location);
-    }
-
-    public String toDebugString() {
-        return "CharBuf{" +
-                "capacity=" + capacity +
-                ", location=" + location +
-                '}';
-    }
-
-    public String toStringAndRecycle() {
-        String str = new String(buffer, 0, location);
-        location = 0;
-        return str;
-    }
-
-    public int len() {
-        return location;
-    }
-
-    public char[] toCharArray() {
-        return this.buffer;
-    }
-
-    public void _len(int location) {
-        this.location = location;
-    }
-
-    public char[] readForRecycle() {
-        this.location = 0;
-        return this.buffer;
-    }
-
-    public void recycle() {
-        this.location = 0;
-    }
-
-    public double doubleValue() {
-        return CharScanner.parseDouble(this.buffer, 0, location);
-    }
-
-    public float floatValue() {
-        return CharScanner.parseFloat(this.buffer, 0, location);
-    }
-
-    public int intValue() {
-        return CharScanner.parseIntFromTo(buffer, 0, location);
-    }
-
-    public long longValue() {
-        return CharScanner.parseLongFromTo(buffer, 0, location);
-    }
-
-    public byte byteValue() {
-        return (byte) intValue();
-    }
-
-    public short shortValue() {
-        return (short) intValue();
-    }
-
-    public Number toIntegerWrapper() {
-        if (CharScanner.isInteger(buffer, 0, location)) {
-            return intValue();
-        } else {
-            return longValue();
-        }
-    }
-
-    static final char[] nullChars = "null".toCharArray();
-
-    public final void addNull() {
-        this.add(nullChars);
-    }
-
-    public void removeLastChar() {
-        if (location > 0) {
-            location--;
-        }
-    }
-
-    public void removeLastChar(char expect) {
-        if (location == 0 || buffer[location-1] != expect) {
-            return;
-        }
-        removeLastChar();
-    }
-
-    private Cache<BigDecimal, char[]> bigDCache;
-
-    public CharBuf addBigDecimal(BigDecimal key) {
-        if (bigDCache == null) {
-            bigDCache = new SimpleCache<BigDecimal, char[]>(20);
-        }
-        char[] chars = bigDCache.get(key);
-
-        if (chars == null) {
-            String str = key.toString();
-            chars = FastStringUtils.toCharArray(str);
-            bigDCache.put(key, chars);
-        }
-
-        add(chars);
-
-        return this;
-    }
-
-    private Cache<BigInteger, char[]> bigICache;
-
-    public CharBuf addBigInteger(BigInteger key) {
-        if (bigICache == null) {
-            bigICache = new SimpleCache<BigInteger, char[]>(20);
-        }
-        char[] chars = bigICache.get(key);
-
-        if (chars == null) {
-            String str = key.toString();
-            chars = FastStringUtils.toCharArray(str);
-            bigICache.put(key, chars);
-        }
-
-        add(chars);
-
-        return this;
-    }
-
-    private Cache<Long, char[]> lcache;
-
-    public final CharBuf addLong(long l) {
-        addLong(Long.valueOf(l));
-        return this;
-    }
-
-    public final CharBuf addLong(Long key) {
-        if (lcache == null) {
-            lcache = new SimpleCache<Long, char[]>(20);
-        }
-        char[] chars = lcache.get(key);
-
-        if (chars == null) {
-            String str = Long.toString(key);
-            chars = FastStringUtils.toCharArray(str);
-            lcache.put(key, chars);
-        }
-
-        add(chars);
-
-        return this;
-    }
-
-    public final CharBuf decodeJsonString(char[] chars) {
-        return decodeJsonString(chars, 0, chars.length);
-    }
-
-    public final CharBuf decodeJsonString(char[] chars, int start, int to) {
-        int len = to - start;
-
-        char[] buffer = this.buffer;
-        int location = this.location;
-
-        if (len > capacity) {
-            buffer = Chr.grow(buffer, buffer.length * 2 + len);
-            capacity = buffer.length;
-        }
-
-        for (int index = start; index < to; index++) {
-            char c = chars[index];
-            if (c == '\\') {
-                if (index < to) {
-                    index++;
-                    c = chars[index];
-                    switch (c) {
-
-                        case 'n':
-                            buffer[location++] = '\n';
-                            break;
-
-                        case '/':
-                            buffer[location++] = '/';
-                            break;
-
-                        case '"':
-                            buffer[location++] = '"';
-                            break;
-
-                        case 'f':
-                            buffer[location++] = '\f';
-                            break;
-
-                        case 't':
-                            buffer[location++] = '\t';
-                            break;
-
-                        case '\\':
-                            buffer[location++] = '\\';
-                            break;
-
-                        case 'b':
-                            buffer[location++] = '\b';
-                            break;
-
-                        case 'r':
-                            buffer[location++] = '\r';
-                            break;
-
-                        case 'u':
-                            if (index + 4 < to) {
-                                String hex = new String(chars, index + 1, 4);
-                                char unicode = (char) Integer.parseInt(hex, 16);
-                                buffer[location++] = unicode;
-                                index += 4;
-                            }
-                            break;
-
-                        default:
-                            throw new JsonException("Unable to decode string");
-                    }
-                }
-            } else {
-                buffer[location++] = c;
-            }
-        }
-
-        this.buffer = buffer;
-        this.location = location;
-
-        return this;
-    }
-}
-
-

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java
deleted file mode 100644
index 596c648..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.math.BigDecimal;
-
-import static groovy.json.internal.Exceptions.die;
-import static groovy.json.internal.Exceptions.handle;
-
-/**
- * @author Richard Hightower
- */
-public class CharScanner {
-
-    protected static final int COMMA = ',';
-    protected static final int CLOSED_CURLY = '}';
-    protected static final int CLOSED_BRACKET = ']';
-    protected static final int LETTER_E = 'e';
-    protected static final int LETTER_BIG_E = 'E';
-    protected static final int DECIMAL_POINT = '.';
-    protected static final int ALPHA_0 = '0';
-    protected static final int ALPHA_9 = '9';
-    protected static final int MINUS = '-';
-    protected static final int PLUS = '+';
-
-    static final String MIN_LONG_STR_NO_SIGN = String.valueOf(Long.MIN_VALUE);
-    static final String MAX_LONG_STR = String.valueOf(Long.MAX_VALUE);
-    static final String MIN_INT_STR_NO_SIGN = String.valueOf(Integer.MIN_VALUE);
-    static final String MAX_INT_STR = String.valueOf(Integer.MAX_VALUE);
-
-    private static double powersOf10[] = {
-            1.0,
-            10.0,
-            100.0,
-            1000.0,
-            10000.0,
-            100000.0,
-            1000000.0,
-            10000000.0,
-            100000000.0,
-            1000000000.0,
-            10000000000.0,
-            100000000000.0,
-            1000000000000.0,
-            10000000000000.0,
-            100000000000000.0,
-            1000000000000000.0,
-            10000000000000000.0,
-            100000000000000000.0,
-            1000000000000000000.0,
-    };
-
-    public static boolean isDigit(int c) {
-        return c >= ALPHA_0 && c <= ALPHA_9;
-    }
-
-    public static boolean isDecimalDigit(int c) {
-        return isDigit(c) || isDecimalChar(c);
-    }
-
-    public static boolean isDecimalChar(int currentChar) {
-        switch (currentChar) {
-            case MINUS:
-            case PLUS:
-            case LETTER_E:
-            case LETTER_BIG_E:
-            case DECIMAL_POINT:
-                return true;
-        }
-        return false;
-    }
-
-    public static boolean hasDecimalChar(char[] chars, boolean negative) {
-        int index = 0;
-
-        if (negative) index++;
-
-        for (; index < chars.length; index++) {
-            switch (chars[index]) {
-                case MINUS:
-                case PLUS:
-                case LETTER_E:
-                case LETTER_BIG_E:
-                case DECIMAL_POINT:
-                    return true;
-            }
-        }
-        return false;
-    }
-
-    public static boolean isLong(char[] digitChars) {
-        return isLong(digitChars, 0, digitChars.length);
-    }
-
-    public static boolean isLong(char[] digitChars, int offset, int len) {
-        String cmpStr = digitChars[offset] == '-' ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR;
-        int cmpLen = cmpStr.length();
-        if (len < cmpLen) return true;
-        if (len > cmpLen) return false;
-
-        for (int i = 0; i < cmpLen; ++i) {
-            int diff = digitChars[offset + i] - cmpStr.charAt(i);
-            if (diff != 0) {
-                return (diff < 0);
-            }
-        }
-        return true;
-    }
-
-    public static boolean isInteger(char[] digitChars) {
-        return isInteger(digitChars, 0, digitChars.length);
-    }
-
-    public static boolean isInteger(char[] digitChars, int offset, int len) {
-        String cmpStr = (digitChars[offset] == '-') ? MIN_INT_STR_NO_SIGN : MAX_INT_STR;
-        int cmpLen = cmpStr.length();
-        if (len < cmpLen) return true;
-        if (len > cmpLen) return false;
-
-        for (int i = 0; i < cmpLen; ++i) {
-            int diff = digitChars[offset + i] - cmpStr.charAt(i);
-            if (diff != 0) {
-                return (diff < 0);
-            }
-        }
-        return true;
-    }
-
-    public static int parseInt(char[] digitChars) {
-        return parseIntFromTo(digitChars, 0, digitChars.length);
-    }
-
-    public static int parseIntFromTo(char[] digitChars, int offset, int to) {
-        try {
-            int num;
-            boolean negative = false;
-            char c = digitChars[offset];
-            if (c == '-') {
-                offset++;
-                negative = true;
-            }
-            if (offset >= to) {
-                die();
-            }
-            num = (digitChars[offset] - '0');
-            if (++offset < to) {
-                num = (num * 10) + (digitChars[offset] - '0');
-                if (++offset < to) {
-                    num = (num * 10) + (digitChars[offset] - '0');
-                    if (++offset < to) {
-                        num = (num * 10) + (digitChars[offset] - '0');
-                        if (++offset < to) {
-                            num = (num * 10) + (digitChars[offset] - '0');
-                            if (++offset < to) {
-                                num = (num * 10) + (digitChars[offset] - '0');
-                                if (++offset < to) {
-                                    num = (num * 10) + (digitChars[offset] - '0');
-                                    if (++offset < to) {
-                                        num = (num * 10) + (digitChars[offset] - '0');
-                                        if (++offset < to) {
-                                            num = (num * 10) + (digitChars[offset] - '0');
-                                            if (++offset < to) {
-                                                num = (num * 10) + (digitChars[offset] - '0');
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            return negative ? num * -1 : num;
-        } catch (Exception ex) {
-            return handle(int.class, ex);
-        }
-    }
-
-    public static int parseIntFromToIgnoreDot(char[] digitChars, int offset, int to) {
-        int num;
-        boolean negative = false;
-        char c = digitChars[offset];
-        if (c == '-') {
-            offset++;
-            negative = true;
-        }
-        if (offset >= to) {
-            die();
-        }
-        c = digitChars[offset];
-        num = (c - '0');
-        offset++;
-
-        for (; offset < to; offset++) {
-            c = digitChars[offset];
-            if (c != '.') {
-                num = (num * 10) + (c - '0');
-            }
-        }
-
-        return negative ? num * -1 : num;
-    }
-
-    public static long parseLongFromToIgnoreDot(char[] digitChars, int offset, int to) {
-        long num;
-        boolean negative = false;
-        char c = digitChars[offset];
-        if (c == '-') {
-            offset++;
-            negative = true;
-        }
-        if (offset >= to) {
-            die();
-        }
-        c = digitChars[offset];
-        num = (c - '0');
-        offset++;
-
-        for (; offset < to; offset++) {
-            c = digitChars[offset];
-            if (c != '.') {
-                num = (num * 10) + (c - '0');
-            }
-        }
-
-        return negative ? num * -1 : num;
-    }
-
-    public static long parseLongFromTo(char[] digitChars, int offset, int to) {
-        long num;
-        boolean negative = false;
-        char c = digitChars[offset];
-        if (c == '-') {
-            offset++;
-            negative = true;
-        }
-        if (offset >= to) {
-            die();
-        }
-        c = digitChars[offset];
-        num = (c - '0');
-        offset++;
-
-        long digit;
-
-        for (; offset < to; offset++) {
-            c = digitChars[offset];
-            digit = (c - '0');
-            num = (num * 10) + digit;
-        }
-
-        return negative ? num * -1 : num;
-    }
-
-    public static long parseLong(char[] digitChars) {
-        return parseLongFromTo(digitChars, 0, digitChars.length);
-    }
-
-    public static Number parseJsonNumber(char[] buffer) {
-        return parseJsonNumber(buffer, 0, buffer.length);
-    }
-
-    public static Number parseJsonNumber(char[] buffer, int from, int to) {
-        return parseJsonNumber(buffer, from, to, null);
-    }
-
-    public static boolean isNumberDigit(int c) {
-        return c >= ALPHA_0 && c <= ALPHA_9;
-    }
-
-    protected static boolean isDelimiter(int c) {
-        return c == COMMA || c == CLOSED_CURLY || c == CLOSED_BRACKET;
-    }
-
-    public static Number parseJsonNumber(char[] buffer, int from, int max, int size[]) {
-        Number value = null;
-        boolean simple = true;
-        int digitsPastPoint = 0;
-
-        int index = from;
-
-        if (buffer[index] == '-') {
-            index++;
-        }
-        if (index >= max) {
-            die();
-        }
-
-        boolean foundDot = false;
-        for (; index < max; index++) {
-            char ch = buffer[index];
-            if (isNumberDigit(ch)) {
-                if (foundDot) {
-                    digitsPastPoint++;
-                }
-            } else if (ch <= 32 || isDelimiter(ch)) {
-                break;
-            } else if (ch == '.') {
-                if (foundDot) {
-                    die("unexpected character " + ch);
-                }
-                foundDot = true;
-            } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
-                simple = false;
-            } else {
-                die("unexpected character " + ch);
-            }
-        }
-
-        if (digitsPastPoint >= powersOf10.length - 1) {
-            simple = false;
-        }
-
-        final int length = index - from;
-
-        if (!foundDot && simple) {
-            if (isInteger(buffer, from, length)) {
-                value = parseIntFromTo(buffer, from, index);
-            } else {
-                value = parseLongFromTo(buffer, from, index);
-            }
-        } else {
-            value = new BigDecimal(buffer, from, length);
-        }
-
-        if (size != null) {
-            size[0] = index;
-        }
-
-        return value;
-    }
-
-    public static BigDecimal parseBigDecimal(char[] buffer) {
-        return new BigDecimal(buffer);
-    }
-
-    public static float parseFloat(char[] buffer, int from, int to) {
-        return (float) parseDouble(buffer, from, to);
-    }
-
-    public static double parseDouble(char[] buffer, int from, int to) {
-        double value;
-        boolean simple = true;
-        int digitsPastPoint = 0;
-
-        int index = from;
-
-        if (buffer[index] == '-') {
-            index++;
-        }
-
-        boolean foundDot = false;
-        for (; index < to; index++) {
-            char ch = buffer[index];
-            if (isNumberDigit(ch)) {
-                if (foundDot) {
-                    digitsPastPoint++;
-                }
-            } else if (ch == '.') {
-                if (foundDot) {
-                    die("unexpected character " + ch);
-                }
-                foundDot = true;
-            } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
-                simple = false;
-            } else {
-                die("unexpected character " + ch);
-            }
-        }
-
-        if (digitsPastPoint >= powersOf10.length - 1) {
-            simple = false;
-        }
-
-        final int length = index - from;
-
-        if (!foundDot && simple) {
-            if (isInteger(buffer, from, length)) {
-                value = parseIntFromTo(buffer, from, index);
-            } else {
-                value = parseLongFromTo(buffer, from, index);
-            }
-        } else if (foundDot && simple) {
-            long lvalue;
-
-            if (length < powersOf10.length) {
-                if (isInteger(buffer, from, length)) {
-                    lvalue = parseIntFromToIgnoreDot(buffer, from, index);
-                } else {
-                    lvalue = parseLongFromToIgnoreDot(buffer, from, index);
-                }
-
-                double power = powersOf10[digitsPastPoint];
-                value = lvalue / power;
-            } else {
-                value = Double.parseDouble(new String(buffer, from, length));
-            }
-        } else {
-            value = Double.parseDouble(new String(buffer, from, index - from));
-        }
-
-        return value;
-    }
-
-    public static int skipWhiteSpace(char[] array, int index, final int length) {
-        int c;
-        for (; index < length; index++) {
-            c = array[index];
-            if (c > 32) {
-                return index;
-            }
-        }
-        return index;
-    }
-
-    public static char[] readNumber(char[] array, int idx, final int len) {
-        final int startIndex = idx;
-
-        while (true) {
-            if (!CharScanner.isDecimalDigit(array[idx])) {
-                break;
-            } else {
-                idx++;
-                if (idx >= len) break;
-            }
-        }
-
-        return ArrayUtils.copyRange(array, startIndex, idx);
-    }
-
-    public static String errorDetails(String message, char[] array, int index, int ch) {
-        CharBuf buf = CharBuf.create(255);
-
-        buf.addLine(message);
-
-        buf.addLine("");
-        buf.addLine("The current character read is " + debugCharDescription(ch));
-
-        buf.addLine(message);
-
-        int line = 0;
-        int lastLineIndex = 0;
-
-        for (int i = 0; i < index && i < array.length; i++) {
-            if (array[i] == '\n') {
-                line++;
-                lastLineIndex = i + 1;
-            }
-        }
-
-        int count = 0;
-
-        for (int i = lastLineIndex; i < array.length; i++, count++) {
-            if (array[i] == '\n') {
-                break;
-            }
-        }
-
-        buf.addLine("line number " + (line + 1));
-        buf.addLine("index number " + index);
-
-        try {
-            buf.addLine(new String(array, lastLineIndex, count));
-        } catch (Exception ex) {
-            try {
-                int start = index = (index - 10 < 0) ? 0 : index - 10;
-
-                buf.addLine(new String(array, start, index));
-            } catch (Exception ex2) {
-                buf.addLine(new String(array, 0, array.length));
-            }
-        }
-        for (int i = 0; i < (index - lastLineIndex); i++) {
-            buf.add('.');
-        }
-        buf.add('^');
-
-        return buf.toString();
-    }
-
-    public static String debugCharDescription(int c) {
-        String charString;
-        if (c == ' ') {
-            charString = "[SPACE]";
-        } else if (c == '\t') {
-            charString = "[TAB]";
-        } else if (c == '\n') {
-            charString = "[NEWLINE]";
-        } else {
-            charString = "'" + (char) c + "'";
-        }
-
-        charString = charString + " with an int value of " + ((int) c);
-        return charString;
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java
deleted file mode 100644
index 6b0477f..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.Date;
-
-import static groovy.json.internal.CharScanner.isInteger;
-import static groovy.json.internal.CharScanner.parseIntFromTo;
-import static groovy.json.internal.CharScanner.parseLongFromTo;
-import static groovy.json.internal.Exceptions.die;
-
-/**
- * @author Rick Hightower
- */
-public class CharSequenceValue implements Value, CharSequence {
-
-    private final Type type;
-    private final boolean checkDate;
-    private final boolean decodeStrings;
-
-    private char[] buffer;
-    private boolean chopped;
-    private int startIndex;
-    private int endIndex;
-    private Object value;
-
-    public CharSequenceValue(boolean chop, Type type, int startIndex, int endIndex, char[] buffer,
-                             boolean encoded, boolean checkDate) {
-        this.type = type;
-        this.checkDate = checkDate;
-        this.decodeStrings = encoded;
-
-        if (chop) {
-            try {
-                this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
-            } catch (Exception ex) {
-                Exceptions.handle(ex);
-            }
-            this.startIndex = 0;
-            this.endIndex = this.buffer.length;
-            this.chopped = true;
-        } else {
-            this.startIndex = startIndex;
-            this.endIndex = endIndex;
-            this.buffer = buffer;
-        }
-    }
-
-    public String toString() {
-        if (startIndex == 0 && endIndex == buffer.length) {
-            return FastStringUtils.noCopyStringFromChars(buffer);
-        } else {
-            return new String(buffer, startIndex, (endIndex - startIndex));
-        }
-    }
-
-    public final Object toValue() {
-        return value != null ? value : (value = doToValue());
-    }
-
-    public <T extends Enum> T toEnum(Class<T> cls) {
-        switch (type) {
-            case STRING:
-                return toEnum(cls, stringValue());
-            case INTEGER:
-                return toEnum(cls, intValue());
-            case NULL:
-                return null;
-        }
-        die("toEnum " + cls + " value was " + stringValue());
-        return null;
-    }
-
-    public static <T extends Enum> T toEnum(Class<T> cls, String value) {
-        try {
-            return (T) Enum.valueOf(cls, value);
-        } catch (Exception ex) {
-            return (T) Enum.valueOf(cls, value.toUpperCase().replace('-', '_'));
-        }
-    }
-
-    public static <T extends Enum> T toEnum(Class<T> cls, int value) {
-        T[] enumConstants = cls.getEnumConstants();
-        for (T e : enumConstants) {
-            if (e.ordinal() == value) {
-                return e;
-            }
-        }
-        die("Can't convert ordinal value " + value + " into enum of type " + cls);
-        return null;
-    }
-
-    public boolean isContainer() {
-        return false;
-    }
-
-    private Object doToValue() {
-        switch (type) {
-            case DOUBLE:
-                return doubleValue();
-            case INTEGER:
-                if (isInteger(buffer, startIndex, endIndex - startIndex)) {
-                    return intValue();
-                } else {
-                    return longValue();
-                }
-            case STRING:
-                if (checkDate) {
-                    Date date = null;
-                    if (Dates.isISO8601QuickCheck(buffer, startIndex, endIndex)) {
-                        if (Dates.isJsonDate(buffer, startIndex, endIndex)) {
-                            date = Dates.fromJsonDate(buffer, startIndex, endIndex);
-                        } else if (Dates.isISO8601(buffer, startIndex, endIndex)) {
-                            date = Dates.fromISO8601(buffer, startIndex, endIndex);
-                        } else {
-                            return stringValue();
-                        }
-
-                        if (date == null) {
-                            return stringValue();
-                        } else {
-                            return date;
-                        }
-                    }
-                }
-                return stringValue();
-        }
-        die();
-        return null;
-    }
-
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof Value)) return false;
-
-        CharSequenceValue value1 = (CharSequenceValue) o;
-
-        if (endIndex != value1.endIndex) return false;
-        if (startIndex != value1.startIndex) return false;
-        if (!Arrays.equals(buffer, value1.buffer)) return false;
-        if (type != value1.type) return false;
-        return value != null ? value.equals(value1.value) : value1.value == null;
-
-    }
-
-    public int hashCode() {
-        int result = type != null ? type.hashCode() : 0;
-        result = 31 * result + (buffer != null ? Arrays.hashCode(buffer) : 0);
-        result = 31 * result + startIndex;
-        result = 31 * result + endIndex;
-        result = 31 * result + (value != null ? value.hashCode() : 0);
-        return result;
-    }
-
-    public final int length() {
-        return buffer.length;
-    }
-
-    public final char charAt(int index) {
-        return buffer[index];
-    }
-
-    public final CharSequence subSequence(int start, int end) {
-        return new CharSequenceValue(false, type, start, end, buffer, decodeStrings, checkDate);
-    }
-
-    public BigDecimal bigDecimalValue() {
-        return new BigDecimal(buffer, startIndex, endIndex - startIndex);
-    }
-
-    public BigInteger bigIntegerValue() {
-        return new BigInteger(toString());
-    }
-
-    public String stringValue() {
-        if (this.decodeStrings) {
-            return JsonStringDecoder.decodeForSure(buffer, startIndex, endIndex);
-        } else {
-            return toString();
-        }
-    }
-
-    public String stringValueEncoded() {
-        return JsonStringDecoder.decode(buffer, startIndex, endIndex);
-    }
-
-    public Date dateValue() {
-        if (type == Type.STRING) {
-
-            if (Dates.isISO8601QuickCheck(buffer, startIndex, endIndex)) {
-
-                if (Dates.isJsonDate(buffer, startIndex, endIndex)) {
-                    return Dates.fromJsonDate(buffer, startIndex, endIndex);
-
-                } else if (Dates.isISO8601(buffer, startIndex, endIndex)) {
-                    return Dates.fromISO8601(buffer, startIndex, endIndex);
-                } else {
-                    throw new JsonException("Unable to convert " + stringValue() + " to date ");
-                }
-            } else {
-                throw new JsonException("Unable to convert " + stringValue() + " to date ");
-            }
-        } else {
-            return new Date(Dates.utc(longValue()));
-        }
-    }
-
-    public int intValue() {
-        int sign = 1;
-        if (buffer[startIndex] == '-') {
-            startIndex++;
-            sign = -1;
-        }
-        return parseIntFromTo(buffer, startIndex, endIndex) * sign;
-    }
-
-    public long longValue() {
-        if (isInteger(buffer, startIndex, endIndex - startIndex)) {
-            return parseIntFromTo(buffer, startIndex, endIndex);
-        } else {
-            return parseLongFromTo(buffer, startIndex, endIndex);
-        }
-    }
-
-    public byte byteValue() {
-        return (byte) intValue();
-    }
-
-    public short shortValue() {
-        return (short) intValue();
-    }
-
-    public double doubleValue() {
-        return CharScanner.parseDouble(this.buffer, startIndex, endIndex);
-    }
-
-    public boolean booleanValue() {
-        return Boolean.parseBoolean(toString());
-    }
-
-    public float floatValue() {
-        return CharScanner.parseFloat(this.buffer, startIndex, endIndex);
-    }
-
-    public final void chop() {
-        if (!chopped) {
-            this.chopped = true;
-            this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
-            this.startIndex = 0;
-            this.endIndex = this.buffer.length;
-        }
-    }
-
-    public char charValue() {
-        return buffer[startIndex];
-    }
-}


[5/7] groovy git commit: GROOVY-8379: Rework groovy-json FastStringUtils (closes #667)

Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java
deleted file mode 100644
index cffcd34..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Richard Hightower
- */
-public class JsonStringDecoder {
-
-    public static String decode(char[] chars, int start, int to) {
-        if (!Chr.contains(chars, '\\', start, to - start)) {
-            return new String(chars, start, to - start);
-        }
-        return decodeForSure(chars, start, to);
-    }
-
-    public static String decodeForSure(char[] chars, int start, int to) {
-        CharBuf builder = CharBuf.create(to - start);
-        builder.decodeJsonString(chars, start, to);
-        return builder.toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java
deleted file mode 100644
index 6d14ed1..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.lang.reflect.Array;
-import java.util.AbstractMap;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-/**
- * This maps only builds once you ask for a key for the first time.
- * It is designed to not incur the overhead of creating a map unless needed.
- *
- * @author Rick Hightower
- */
-public class LazyMap extends AbstractMap<String, Object> {
-
-    static final String JDK_MAP_ALTHASHING_SYSPROP = System.getProperty("jdk.map.althashing.threshold");
-
-    /* Holds the actual map that will be lazily created. */
-    private Map<String, Object> map;
-    /* The size of the map. */
-    private int size;
-    /* The keys  stored in the map. */
-    private String[] keys;
-    /* The values stored in the map. */
-    private Object[] values;
-
-    public LazyMap() {
-        keys = new String[5];
-        values = new Object[5];
-    }
-
-    public LazyMap(int initialSize) {
-        keys = new String[initialSize];
-        values = new Object[initialSize];
-    }
-
-    public Object put(String key, Object value) {
-        if (map == null) {
-            for (int i = 0; i < size; i++) {
-                String curKey = keys[i];
-                if ((key == null && curKey == null)
-                     || (key != null && key.equals(curKey))) {
-                    Object val = values[i];
-                    keys[i] = key;
-                    values[i] = value;
-                    return val;
-                }
-            }
-            keys[size] = key;
-            values[size] = value;
-            size++;
-            if (size == keys.length) {
-                keys = grow(keys);
-                values = grow(values);
-            }
-            return null;
-        } else {
-            return map.put(key, value);
-        }
-    }
-
-    public Set<Entry<String, Object>> entrySet() {
-        buildIfNeeded();
-        return map.entrySet();
-    }
-
-    public int size() {
-        if (map == null) {
-            return size;
-        } else {
-            return map.size();
-        }
-    }
-
-    public boolean isEmpty() {
-        if (map == null) {
-            return size == 0;
-        } else {
-            return map.isEmpty();
-        }
-    }
-
-    public boolean containsValue(Object value) {
-        buildIfNeeded();
-        return map.containsValue(value);
-    }
-
-    public boolean containsKey(Object key) {
-        buildIfNeeded();
-        return map.containsKey(key);
-    }
-
-    public Object get(Object key) {
-        buildIfNeeded();
-        return map.get(key);
-    }
-
-    private void buildIfNeeded() {
-        if (map == null) {
-            // added to avoid hash collision attack
-            if (Sys.is1_8OrLater() || (Sys.is1_7() && JDK_MAP_ALTHASHING_SYSPROP != null)) {
-                map = new LinkedHashMap<String, Object>(size, 0.01f);
-            } else {
-                map = new TreeMap<String, Object>();
-            }
-
-            for (int index = 0; index < size; index++) {
-                map.put(keys[index], values[index]);
-            }
-            this.keys = null;
-            this.values = null;
-        }
-    }
-
-    public Object remove(Object key) {
-        buildIfNeeded();
-        return map.remove(key);
-    }
-
-    public void putAll(Map m) {
-        buildIfNeeded();
-        map.putAll(m);
-    }
-
-    public void clear() {
-        if (map == null) {
-            size = 0;
-        } else {
-            map.clear();
-        }
-    }
-
-    public Set<String> keySet() {
-        buildIfNeeded();
-        return map.keySet();
-    }
-
-    public Collection<Object> values() {
-        buildIfNeeded();
-        return map.values();
-    }
-
-    public boolean equals(Object o) {
-        buildIfNeeded();
-        return map.equals(o);
-    }
-
-    public int hashCode() {
-        buildIfNeeded();
-        return map.hashCode();
-    }
-
-    public String toString() {
-        buildIfNeeded();
-        return map.toString();
-    }
-
-    protected Object clone() throws CloneNotSupportedException {
-        if (map == null) {
-            return null;
-        } else {
-            if (map instanceof LinkedHashMap) {
-                return ((LinkedHashMap) map).clone();
-            } else {
-                return new LinkedHashMap(this);
-            }
-        }
-    }
-
-    public LazyMap clearAndCopy() {
-        LazyMap map = new LazyMap();
-        for (int index = 0; index < size; index++) {
-            map.put(keys[index], values[index]);
-        }
-        size = 0;
-        return map;
-    }
-
-    public static <V> V[] grow(V[] array) {
-        Object newArray = Array.newInstance(array.getClass().getComponentType(), array.length * 2);
-        System.arraycopy(array, 0, newArray, 0, array.length);
-        return (V[]) newArray;
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java
deleted file mode 100644
index 364a76e..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.util.AbstractMap;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-import static groovy.json.internal.Exceptions.die;
-
-/**
- * This class is important to the performance of the parser.
- * It stores Value objects in a map where they are evaluated lazily.
- * This is great for JSONPath types of application, and Object Serialization but not for maps that are going to be stored in a cache.
- * <p/>
- * This is because the Value construct is a type of index overlay that merely tracks where the token is located in the buffer,
- * and what if any thing we noted about it (like can be converted to a decimal number, etc.).
- * <p/>
- * To mitigate memory leaks this class along with CharSequenceValue implement two constructs, namely,
- * chop,  and lazyChop.
- * <p/>
- * A chop is when we convert backing buffer of a Value object into a smaller buffer.
- * A lazyChop is when we do a chop but only when a get operation is called.
- * <p/>
- * The lazyChop is performed on the tree that is touched by the JSONPath expression or its ilk.
- * <p/>
- * The chop operation can be done during parsing or lazily by storing the values in this construct.
- *
- * @author Rick Hightower (insane chipmonk)
- */
-public class LazyValueMap extends AbstractMap<String, Object> implements ValueMap<String, Object> {
-
-    /**
-     * holds the map that gets lazily created on first access.
-     */
-    private Map<String, Object> map = null;
-    /**
-     * holds the list of items that we are managing.
-     */
-    private Entry<String, Value>[] items;
-    /**
-     * Holds the current number mapping managed by this map.
-     */
-    private int len = 0;
-    /**
-     * Holds whether or not we ae in lazy chop mode or not.
-     */
-    private final boolean lazyChop;
-
-    /**
-     * Keep track if this map has already been chopped so we don't waste time trying to chop it again.
-     */
-    boolean mapChopped = false;
-
-    public LazyValueMap(boolean lazyChop) {
-        this.items = new Entry[5];
-        this.lazyChop = lazyChop;
-    }
-
-    public LazyValueMap(boolean lazyChop, int initialSize) {
-        this.items = new Entry[initialSize];
-        this.lazyChop = lazyChop;
-    }
-
-    /**
-     * Adds a new MapItemValue to the mapping.
-     *
-     * @param miv miv we are adding.
-     */
-    public final void add(MapItemValue miv) {
-        if (len >= items.length) {
-            items = LazyMap.grow(items);
-        }
-        items[len] = miv;
-        len++;
-    }
-
-    /**
-     * Gets the item by key from the mapping.
-     *
-     * @param key to lookup
-     * @return the item for the given key
-     */
-    public final Object get(Object key) {
-        Object object = null;
-
-        /* if the map is null, then we create it. */
-        if (map == null) {
-            buildMap();
-        }
-        object = map.get(key);
-
-        lazyChopIfNeeded(object);
-        return object;
-    }
-
-    /**
-     * If in lazy chop mode, and the object is a Lazy Value Map or a ValueList
-     * then we force a chop operation for each of its items.
-     */
-    private void lazyChopIfNeeded(Object object) {
-        if (lazyChop) {
-            if (object instanceof LazyValueMap) {
-                LazyValueMap m = (LazyValueMap) object;
-                m.chopMap();
-            } else if (object instanceof ValueList) {
-                ValueList list = (ValueList) object;
-                list.chopList();
-            }
-        }
-    }
-
-    /**
-     * Chop this map.
-     */
-    public final void chopMap() {
-        /* if it has been chopped then you have to return. */
-        if (mapChopped) {
-            return;
-        }
-        mapChopped = true;
-
-        /* If the internal map was not create yet, don't. We can chop the value w/o creating the internal map.*/
-        if (this.map == null) {
-            for (int index = 0; index < len; index++) {
-                MapItemValue entry = (MapItemValue) items[index];
-
-                Value value = entry.getValue();
-                if (value == null) continue;
-                if (value.isContainer()) {
-                    chopContainer(value);
-                } else {
-                    value.chop();
-                }
-            }
-        } else {
-            /* Iterate through the map and do the same thing. Make sure children and children of children are chopped.  */
-            for (Map.Entry<String, Object> entry : map.entrySet()) {
-
-                Object object = entry.getValue();
-                if (object instanceof Value) {
-                    Value value = (Value) object;
-                    if (value.isContainer()) {
-                        chopContainer(value);
-                    } else {
-                        value.chop();
-                    }
-                } else if (object instanceof LazyValueMap) {
-                    LazyValueMap m = (LazyValueMap) object;
-                    m.chopMap();
-                } else if (object instanceof ValueList) {
-                    ValueList list = (ValueList) object;
-                    list.chopList();
-                }
-            }
-        }
-    }
-
-    /* We need to chop up this child container. */
-    private static void chopContainer(Value value) {
-        Object obj = value.toValue();
-        if (obj instanceof LazyValueMap) {
-            LazyValueMap map = (LazyValueMap) obj;
-            map.chopMap();
-        } else if (obj instanceof ValueList) {
-            ValueList list = (ValueList) obj;
-            list.chopList();
-        }
-    }
-
-    public Value put(String key, Object value) {
-        die("Not that kind of map");
-        return null;
-    }
-
-    public Set<Entry<String, Object>> entrySet() {
-        if (map == null) {
-            buildMap();
-        }
-        return map.entrySet();
-    }
-
-    private void buildMap() {
-        // added to avoid hash collision attack
-        if (Sys.is1_8OrLater() || (Sys.is1_7() && LazyMap.JDK_MAP_ALTHASHING_SYSPROP != null)) {
-            map = new HashMap<String, Object>(items.length);
-        } else {
-            map = new TreeMap<String, Object>();
-        }
-
-        for (Entry<String, Value> miv : items) {
-            if (miv == null) {
-                break;
-            }
-            map.put(miv.getKey(), miv.getValue().toValue());
-        }
-
-        len = 0;
-        items = null;
-    }
-
-    public Collection<Object> values() {
-        if (map == null) buildMap();
-        return map.values();
-    }
-
-    public int size() {
-        if (map == null) buildMap();
-        return map.size();
-    }
-
-    public String toString() {
-        if (map == null) buildMap();
-        return map.toString();
-    }
-
-    public int len() {
-        return len;
-    }
-
-    public boolean hydrated() {
-        return map != null;
-    }
-
-    public Entry<String, Value>[] items() {
-        return items;
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java
deleted file mode 100644
index 0047ae7..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static groovy.json.internal.Exceptions.die;
-
-/**
- * This holds a mapping from value key to value value to maximize laziness.
- *
- * @author Rick Hightower
- */
-public class MapItemValue implements Map.Entry<String, Value> {
-
-    final Value name;
-    final Value value;
-
-    private String key = null;
-
-    private static final boolean internKeys = Boolean.parseBoolean(System.getProperty("groovy.json.implementation.internKeys", "false"));
-
-    protected static ConcurrentHashMap<String, String> internedKeysCache;
-
-    static {
-        if (internKeys) {
-            internedKeysCache = new ConcurrentHashMap<String, String>();
-        }
-    }
-
-    public MapItemValue(Value name, Value value) {
-        this.name = name;
-        this.value = value;
-    }
-
-    public String getKey() {
-        if (key == null) {
-            if (internKeys) {
-                key = name.toString();
-
-                String keyPrime = internedKeysCache.get(key);
-                if (keyPrime == null) {
-                    key = key.intern();
-                    internedKeysCache.put(key, key);
-                } else {
-                    key = keyPrime;
-                }
-            } else {
-                key = name.toString();
-            }
-        }
-        return key;
-    }
-
-    public Value getValue() {
-        return value;
-    }
-
-    public Value setValue(Value value) {
-        die("not that kind of Entry");
-        return null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java
deleted file mode 100644
index 800431a..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.Date;
-
-import static groovy.json.internal.CharScanner.isInteger;
-import static groovy.json.internal.CharScanner.parseIntFromTo;
-import static groovy.json.internal.CharScanner.parseLongFromTo;
-import static groovy.json.internal.Exceptions.die;
-import static groovy.json.internal.Exceptions.sputs;
-
-/**
- * @author Rick Hightower
- */
-public class NumberValue extends java.lang.Number implements Value {
-
-    private char[] buffer;
-    private boolean chopped;
-    private int startIndex;
-    private int endIndex;
-    private final Type type;
-    private Object value;
-
-    public NumberValue(Type type) {
-        this.type = type;
-    }
-
-    public NumberValue() {
-        this.type = null;
-    }
-
-    public NumberValue(boolean chop, Type type, int startIndex, int endIndex, char[] buffer) {
-        this.type = type;
-
-        try {
-            if (chop) {
-                this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
-                this.startIndex = 0;
-                this.endIndex = this.buffer.length;
-                chopped = true;
-            } else {
-                this.startIndex = startIndex;
-                this.endIndex = endIndex;
-                this.buffer = buffer;
-            }
-        } catch (Exception ex) {
-            Exceptions.handle(sputs("exception", ex, "start", startIndex, "end", endIndex), ex);
-        }
-
-        // Check for a single minus now, rather than finding out later during lazy parsing.
-        if (this.endIndex - this.startIndex == 1 && this.buffer[this.startIndex] == '-') {
-            die("A single minus is not a valid number");
-        }
-
-    }
-
-    public String toString() {
-        if (startIndex == 0 && endIndex == buffer.length) {
-            return FastStringUtils.noCopyStringFromChars(buffer);
-        } else {
-            return new String(buffer, startIndex, (endIndex - startIndex));
-        }
-    }
-
-    public final Object toValue() {
-        return value != null ? value : (value = doToValue());
-    }
-
-    public <T extends Enum> T toEnum(Class<T> cls) {
-        return toEnum(cls, intValue());
-    }
-
-    public static <T extends Enum> T toEnum(Class<T> cls, int value) {
-        T[] enumConstants = cls.getEnumConstants();
-        for (T e : enumConstants) {
-            if (e.ordinal() == value) {
-                return e;
-            }
-        }
-        die("Can't convert ordinal value " + value + " into enum of type " + cls);
-        return null;
-    }
-
-    public boolean isContainer() {
-        return false;
-    }
-
-    private Object doToValue() {
-        switch (type) {
-            case DOUBLE:
-                return bigDecimalValue();
-            case INTEGER:
-                if (isInteger(buffer, startIndex, endIndex - startIndex)) {
-                    return intValue();
-                } else {
-                    return longValue();
-                }
-        }
-        die();
-        return null;
-    }
-
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof Value)) return false;
-
-        NumberValue value1 = (NumberValue) o;
-
-        if (endIndex != value1.endIndex) return false;
-        if (startIndex != value1.startIndex) return false;
-        if (!Arrays.equals(buffer, value1.buffer)) return false;
-        if (type != value1.type) return false;
-        return value != null ? value.equals(value1.value) : value1.value == null;
-
-    }
-
-    public int hashCode() {
-        int result = type != null ? type.hashCode() : 0;
-        result = 31 * result + (buffer != null ? Arrays.hashCode(buffer) : 0);
-        result = 31 * result + startIndex;
-        result = 31 * result + endIndex;
-        result = 31 * result + (value != null ? value.hashCode() : 0);
-        return result;
-    }
-
-    public BigDecimal bigDecimalValue() {
-        try {
-            return new BigDecimal(buffer, startIndex, endIndex - startIndex);
-        } catch (NumberFormatException e) {
-            throw new JsonException("unable to parse " + new String(buffer, startIndex, endIndex - startIndex), e);
-        }
-    }
-
-    public BigInteger bigIntegerValue() {
-        return new BigInteger(toString());
-    }
-
-    public String stringValue() {
-        return toString();
-    }
-
-    public String stringValueEncoded() {
-        return toString();
-    }
-
-    public Date dateValue() {
-        return new Date(Dates.utc(longValue()));
-    }
-
-    public int intValue() {
-        return parseIntFromTo(buffer, startIndex, endIndex);
-    }
-
-    public long longValue() {
-        if (isInteger(buffer, startIndex, endIndex - startIndex)) {
-            return parseIntFromTo(buffer, startIndex, endIndex);
-        } else {
-            return parseLongFromTo(buffer, startIndex, endIndex);
-        }
-    }
-
-    public byte byteValue() {
-        return (byte) intValue();
-    }
-
-    public short shortValue() {
-        return (short) intValue();
-    }
-
-    public double doubleValue() {
-        return CharScanner.parseDouble(this.buffer, startIndex, endIndex);
-    }
-
-    public boolean booleanValue() {
-        return Boolean.parseBoolean(toString());
-    }
-
-    public float floatValue() {
-        return CharScanner.parseFloat(this.buffer, startIndex, endIndex);
-    }
-
-    public final void chop() {
-        if (!chopped) {
-            this.chopped = true;
-            this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
-            this.startIndex = 0;
-            this.endIndex = this.buffer.length;
-        }
-    }
-
-    public char charValue() {
-        return buffer[startIndex];
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java
deleted file mode 100644
index 22976bd..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-
-/**
- * @author Richard Hightower
- */
-public class ReaderCharacterSource implements CharacterSource {
-
-    private static final int MAX_TOKEN_SIZE = 5;
-
-    private final Reader reader;
-    private final int readAheadSize;
-    private int ch = -2;
-
-    private boolean foundEscape;
-
-    private final char[] readBuf;
-
-    private int index;
-
-    private int length;
-
-    boolean more = true;
-    private boolean done = false;
-
-    public ReaderCharacterSource(final Reader reader, final int readAheadSize) {
-        this.reader = reader;
-        this.readBuf = new char[readAheadSize + MAX_TOKEN_SIZE];
-        this.readAheadSize = readAheadSize;
-    }
-
-    public ReaderCharacterSource(final Reader reader) {
-        this.reader = reader;
-        this.readAheadSize = 10000;
-        this.readBuf = new char[readAheadSize + MAX_TOKEN_SIZE];
-    }
-
-    public ReaderCharacterSource(final String string) {
-        this(new StringReader(string));
-    }
-
-    private void readForToken() {
-        try {
-            length += reader.read(readBuf, readBuf.length - MAX_TOKEN_SIZE, MAX_TOKEN_SIZE);
-        } catch (IOException e) {
-            Exceptions.handle(e);
-        }
-    }
-
-    private void ensureBuffer() {
-        try {
-            if (index >= length && !done) {
-                readNextBuffer();
-            } else {
-                more = !(done && index >= length);
-            }
-        } catch (Exception ex) {
-            String str = CharScanner.errorDetails("ensureBuffer issue", readBuf, index, ch);
-            Exceptions.handle(str, ex);
-        }
-    }
-
-    private void readNextBuffer() throws IOException {
-        length = reader.read(readBuf, 0, readAheadSize);
-
-        index = 0;
-        if (length == -1) {
-            ch = -1;
-            length = 0;
-            more = false;
-            done = true;
-        } else {
-            more = true;
-        }
-    }
-
-    public final int nextChar() {
-        ensureBuffer();
-        return ch = readBuf[index++];
-    }
-
-    public final int currentChar() {
-        ensureBuffer();
-        return readBuf[index];
-    }
-
-    public final boolean hasChar() {
-        ensureBuffer();
-        return more;
-    }
-
-    public final boolean consumeIfMatch(char[] match) {
-        try {
-            char[] _chars = readBuf;
-            int i = 0;
-            int idx = index;
-            boolean ok = true;
-
-            if (idx + match.length > length) {
-                readForToken();
-            }
-
-            for (; i < match.length; i++, idx++) {
-                ok &= (match[i] == _chars[idx]);
-                if (!ok) break;
-            }
-
-            if (ok) {
-                index = idx;
-                return true;
-            } else {
-                return false;
-            }
-        } catch (Exception ex) {
-            String str = CharScanner.errorDetails("consumeIfMatch issue", readBuf, index, ch);
-            return Exceptions.handle(boolean.class, str, ex);
-        }
-    }
-
-    public final int location() {
-        return index;
-    }
-
-    public final int safeNextChar() {
-        try {
-            ensureBuffer();
-            return index + 1 < readBuf.length ? readBuf[index++] : -1;
-        } catch (Exception ex) {
-            String str = CharScanner.errorDetails("safeNextChar issue", readBuf, index, ch);
-            return Exceptions.handle(int.class, str, ex);
-        }
-    }
-
-    private static final char[] EMPTY_CHARS = new char[0];
-
-    public char[] findNextChar(int match, int esc) {
-        try {
-            ensureBuffer();
-
-            foundEscape = false;
-            if (readBuf[index] == '"') {
-                index++;
-                return EMPTY_CHARS;
-            }
-
-            int start = index;
-
-            char[] results = null;
-            boolean foundEnd = false;
-            boolean wasEscaped = false;
-            while (!foundEnd) {
-                for (; index < length; index++) {
-                    ch = readBuf[index];
-                    if (wasEscaped) {
-                        wasEscaped = false;
-                    } else if (ch == match) {
-                        foundEnd = true;
-                        break;
-                    } else if (ch == esc) {
-                        foundEscape = true;
-                        wasEscaped = true;
-                    }
-                }
-
-                if (results != null) {
-                    results = Chr.add(results, ArrayUtils.copyRange(readBuf, start, index));
-                }
-                else {
-                    results = ArrayUtils.copyRange(readBuf, start, index);
-                }
-
-                ensureBuffer();
-
-                // Reset start if new buffer
-                if (index == 0) {
-                    start = 0;
-                }
-
-                // Exit early if we run out of data
-                if (done) {
-                    break;
-                }
-            }
-
-            // done will only be true if we ran out of data without seeing the match character
-            if (done) {
-                return Exceptions.die(char[].class, "Unable to find close char " + (char)match + ": " + new String(results));
-            } else {
-                index++;
-                return results;
-            }
-        } catch (Exception ex) {
-            String str = CharScanner.errorDetails("findNextChar issue", readBuf, index, ch);
-            return Exceptions.handle(char[].class, str, ex);
-        }
-    }
-
-    public boolean hadEscape() {
-        return foundEscape;
-    }
-
-    public void skipWhiteSpace() {
-        try {
-            index = CharScanner.skipWhiteSpace(readBuf, index, length);
-            if (index >= length && more) {
-                ensureBuffer();
-
-                skipWhiteSpace();
-            }
-        } catch (Exception ex) {
-            String str = CharScanner.errorDetails("skipWhiteSpace issue", readBuf, index, ch);
-            Exceptions.handle(str, ex);
-        }
-    }
-
-    public char[] readNumber() {
-        try {
-            ensureBuffer();
-
-            char[] results = CharScanner.readNumber(readBuf, index, length);
-            index += results.length;
-
-            if (index >= length && more) {
-                ensureBuffer();
-                if (length != 0) {
-                    char results2[] = readNumber();
-                    return Chr.add(results, results2);
-                } else {
-                    return results;
-                }
-            } else {
-                return results;
-            }
-        } catch (Exception ex) {
-            String str = CharScanner.errorDetails("readNumber issue", readBuf, index, ch);
-            return Exceptions.handle(char[].class, str, ex);
-        }
-    }
-
-    public String errorDetails(String message) {
-        return CharScanner.errorDetails(message, readBuf, index, ch);
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java
deleted file mode 100644
index 92bb400..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import org.codehaus.groovy.runtime.memoize.CommonCache;
-import org.codehaus.groovy.runtime.memoize.EvictableCache;
-
-/**
- * @author Richard Hightower
- */
-public class SimpleCache<K, V> implements Cache<K, V> {
-    private EvictableCache<K, V> cache;
-
-    public SimpleCache(final int limit, CacheType type) {
-        if (type.equals(CacheType.LRU)) {
-            cache = new CommonCache<K, V>(limit);
-        } else {
-            cache = new CommonCache<K, V>(CommonCache.DEFAULT_INITIAL_CAPACITY, limit, EvictableCache.EvictionStrategy.FIFO);
-        }
-    }
-
-    public SimpleCache(final int limit) {
-        this(limit, CacheType.LRU);
-    }
-
-    public void put(K key, V value) {
-        cache.put(key, value);
-    }
-
-    public V get(K key) {
-        return cache.get(key);
-    }
-
-    //For testing only
-
-    public V getSilent(K key) {
-        V value = cache.get(key);
-        if (value != null) {
-            cache.remove(key);
-            cache.put(key, value);
-        }
-        return value;
-    }
-
-    public void remove(K key) {
-        cache.remove(key);
-    }
-
-    public int size() {
-        return cache.size();
-    }
-
-    public String toString() {
-        return cache.toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java
deleted file mode 100644
index 4d8c3ed..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.math.BigDecimal;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-class Sys {
-
-    private static final boolean is1_8OrLater;
-    private static final boolean is1_7;
-    private static final boolean is1_8;
-
-    static {
-        BigDecimal v = new BigDecimal("-1");
-        String sversion = System.getProperty("java.version");
-        if (sversion.indexOf("_") != -1) {
-            final String[] split = sversion.split("_");
-            try {
-                String ver = split[0];
-
-                if (ver.startsWith("1.7")) {
-                    v = new BigDecimal("1.7");
-                }
-
-                if (ver.startsWith("1.8")) {
-                    v = new BigDecimal("1.8");
-                }
-
-                if (ver.startsWith("1.9")) {
-                    v = new BigDecimal("1.9");
-                }
-            } catch (Exception ex) {
-                ex.printStackTrace();
-                System.err.println("Unable to determine build number or version");
-            }
-        } else if ("1.8.0".equals(sversion)) {
-            v = new BigDecimal("1.8");
-        } else {
-            Pattern p = Pattern.compile("^([1-9]\\.[0-9]+)");
-            Matcher matcher = p.matcher(sversion);
-            if (matcher.find()) {
-                v = new BigDecimal(matcher.group(0));
-            }
-        }
-
-        is1_8OrLater = v.compareTo(new BigDecimal("1.8")) >= 0;
-        is1_7 = v.compareTo(new BigDecimal("1.7")) == 0;
-        is1_8 = v.compareTo(new BigDecimal("1.8")) == 0;
-    }
-
-    public static boolean is1_7OrLater() {
-        return true;
-    }
-
-    public static boolean is1_8OrLater() {
-        return is1_8OrLater;
-    }
-
-    public static boolean is1_7() {
-        return is1_7;
-    }
-
-    public static boolean is1_8() {
-        return is1_8;
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Type.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Type.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Type.java
deleted file mode 100644
index b37d4eb..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Type.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Richard Hightower
- */
-public enum Type {
-
-    INTEGER, STRING, DOUBLE, TRUE, FALSE, NULL, MAP, LIST
-
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Value.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Value.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Value.java
deleted file mode 100644
index 095609b..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Value.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Date;
-
-/**
- * @author Rick Hightower
- */
-public interface Value {
-
-    byte byteValue();
-
-    short shortValue();
-
-    int intValue();
-
-    long longValue();
-
-    BigDecimal bigDecimalValue();
-
-    BigInteger bigIntegerValue();
-
-    float floatValue();
-
-    double doubleValue();
-
-    boolean booleanValue();
-
-    Date dateValue();
-
-    String stringValue();
-
-    String stringValueEncoded();
-
-    Object toValue();
-
-    <T extends Enum> T toEnum(Class<T> cls);
-
-    boolean isContainer(); //either a map or a collection
-
-    void chop();
-
-    char charValue();
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java
deleted file mode 100644
index a173ea5..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-import static groovy.json.internal.Exceptions.die;
-import static groovy.json.internal.Exceptions.sputs;
-
-/**
- * @author Rick Hightower
- */
-public class ValueContainer implements CharSequence, Value {
-
-    public static final Value TRUE = new ValueContainer(Type.TRUE);
-    public static final Value FALSE = new ValueContainer(Type.FALSE);
-    public static final Value NULL = new ValueContainer(Type.NULL);
-
-    public Object value;
-
-    public Type type;
-    private boolean container;
-
-    public boolean decodeStrings;
-
-    public ValueContainer(Object value, Type type, boolean decodeStrings) {
-        this.value = value;
-        this.type = type;
-        this.decodeStrings = decodeStrings;
-    }
-
-    public ValueContainer(Type type) {
-        this.type = type;
-    }
-
-    public ValueContainer(Map<String, Object> map) {
-        this.value = map;
-        this.type = Type.MAP;
-        this.container = true;
-    }
-
-    public ValueContainer(List<Object> list) {
-        this.value = list;
-        this.type = Type.LIST;
-        this.container = true;
-    }
-
-    public int intValue() {
-        return die(int.class, sputs("intValue not supported for type ", type));
-    }
-
-    public long longValue() {
-        return die(int.class, sputs("intValue not supported for type ", type));
-    }
-
-    public boolean booleanValue() {
-        switch (type) {
-            case FALSE:
-                return false;
-            case TRUE:
-                return true;
-        }
-        die();
-        return false;
-    }
-
-    public String stringValue() {
-        if (type == Type.NULL) {
-            return null;
-        } else {
-            return type.toString();
-        }
-    }
-
-    public String stringValueEncoded() {
-        return toString();
-    }
-
-    public String toString() {
-        return type.toString();
-    }
-
-    public Object toValue() {
-        if (value != null) {
-            return value;
-        }
-        switch (type) {
-            case FALSE:
-                return (value = false);
-
-            case TRUE:
-                return (value = true);
-            case NULL:
-                return null;
-        }
-        die();
-        return null;
-    }
-
-    public <T extends Enum> T toEnum(Class<T> cls) {
-        return (T) value;
-    }
-
-    public boolean isContainer() {
-        return container;
-    }
-
-    public void chop() {
-    }
-
-    public char charValue() {
-        return 0;
-    }
-
-    public int length() {
-        return 0;
-    }
-
-    public char charAt(int index) {
-        return '0';
-    }
-
-    public CharSequence subSequence(int start, int end) {
-        return "";
-    }
-
-    public Date dateValue() {
-        return null;
-    }
-
-    public byte byteValue() {
-        return 0;
-    }
-
-    public short shortValue() {
-        return 0;
-    }
-
-    public BigDecimal bigDecimalValue() {
-        return null;
-    }
-
-    public BigInteger bigIntegerValue() {
-        return null;
-    }
-
-    public double doubleValue() {
-        return 0;
-    }
-
-    public float floatValue() {
-        return 0;
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java
deleted file mode 100644
index 0320791..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.util.AbstractList;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * @author Rick Hightower
- */
-public class ValueList extends AbstractList<Object> {
-
-    List<Object> list = new ArrayList<Object>(5);
-
-    private final boolean lazyChop;
-    boolean converted = false;
-
-    public ValueList(boolean lazyChop) {
-        this.lazyChop = lazyChop;
-    }
-
-    public Object get(int index) {
-        Object obj = list.get(index);
-
-        if (obj instanceof Value) {
-            obj = convert((Value) obj);
-            list.set(index, obj);
-        }
-
-        chopIfNeeded(obj);
-        return obj;
-    }
-
-    private static Object convert(Value value) {
-        return value.toValue();
-    }
-
-    public int size() {
-        return list.size();
-    }
-
-    public Iterator<Object> iterator() {
-        convertAllIfNeeded();
-        return list.iterator();
-    }
-
-    private void convertAllIfNeeded() {
-        if (!converted) {
-            converted = true;
-            for (int index = 0; index < list.size(); index++) {
-                this.get(index);
-            }
-        }
-    }
-
-    public void clear() {
-        list.clear();
-    }
-
-    public boolean add(Object obj) {
-        return list.add(obj);
-    }
-
-    public void chopList() {
-        for (Object obj : list) {
-            if (obj == null) continue;
-
-            if (obj instanceof Value) {
-                Value value = (Value) obj;
-                if (value.isContainer()) {
-                    chopContainer(value);
-                } else {
-                    value.chop();
-                }
-            }
-        }
-    }
-
-    private void chopIfNeeded(Object object) {
-        if (lazyChop) {
-            if (object instanceof LazyValueMap) {
-                LazyValueMap m = (LazyValueMap) object;
-                m.chopMap();
-            } else if (object instanceof ValueList) {
-                ValueList list = (ValueList) object;
-                list.chopList();
-            }
-        }
-    }
-
-    static void chopContainer(Value value) {
-        Object obj = value.toValue();
-        if (obj instanceof LazyValueMap) {
-            LazyValueMap map = (LazyValueMap) obj;
-            map.chopMap();
-        } else if (obj instanceof ValueList) {
-            ValueList list = (ValueList) obj;
-            list.chopList();
-        }
-    }
-
-    public List<Object> list() {
-        return this.list;
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java
deleted file mode 100644
index f9d1482..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.util.Map;
-
-/**
- * @author Richard Hightower
- */
-public interface ValueMap<K, V> extends Map<K, V> {
-
-    /* add a map item value. */
-    void add(MapItemValue miv);
-
-    /**
-     * Return size w/o hydrating the map.
-     */
-    int len();
-
-    /**
-     * Has the map been hydrated.
-     */
-    boolean hydrated();
-
-    /**
-     * Give me the items in the map without hydrating the map.
-     * Realize that the array is likely larger than the length so array items can be null.
-     */
-    Entry<String, Value>[] items();
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java
deleted file mode 100644
index 31a7b2c..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.util.AbstractMap;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import static groovy.json.internal.Exceptions.die;
-
-/**
- * This map is for object serialization mainly.
- * The idea is the final conversion of
- * the Value objects are delayed until the last possible moment, i.e., just before injected into a bean.
- *
- * @author Rick Hightower
- */
-public class ValueMapImpl extends AbstractMap<String, Value> implements ValueMap<String, Value> {
-
-    /**
-     * The internal map to hold the Value map.
-     */
-    private Map<String, Value> map = null;
-
-    /**
-     * The items held in the map.
-     */
-    private Entry<String, Value>[] items = new Entry[20];
-
-    /* The current length of the map. */
-    private int len = 0;
-
-    /**
-     * Add a MapItemValue to the map.
-     *
-     * @param miv map value item.
-     */
-
-    public void add(MapItemValue miv) {
-        if (len >= items.length) {
-            items = LazyMap.grow(items);
-        }
-        items[len] = miv;
-        len++;
-    }
-
-    public int len() {
-        return len;
-    }
-
-    public boolean hydrated() {
-        return map != null;
-    }
-
-    public Entry<String, Value>[] items() {
-        return items;
-    }
-
-    /**
-     * Get the items for the key.
-     *
-     * @param key
-     * @return the items for the given key
-     */
-
-    public Value get(Object key) {
-        /* If the length is under and we are asking for the key, then just look for the key. Don't build the map. */
-        if (map == null && items.length < 20) {
-            for (Object item : items) {
-                MapItemValue miv = (MapItemValue) item;
-                if (key.equals(miv.name.toValue())) {
-                    return miv.value;
-                }
-            }
-            return null;
-        } else {
-            if (map == null) buildIfNeededMap();
-            return map.get(key);
-        }
-    }
-
-    public Value put(String key, Value value) {
-        die("Not that kind of map");
-        return null;
-    }
-
-    /**
-     * If the map has not been built yet, then we just return a fake entry set.
-     */
-
-    public Set<Entry<String, Value>> entrySet() {
-        buildIfNeededMap();
-        return map.entrySet();
-    }
-
-    /**
-     * Build the map if requested to, it does this lazily.
-     */
-    private void buildIfNeededMap() {
-        if (map == null) {
-            map = new HashMap<String, Value>(items.length);
-
-            for (Entry<String, Value> miv : items) {
-                if (miv == null) {
-                    break;
-                }
-                map.put(miv.getKey(), miv.getValue());
-            }
-        }
-    }
-
-    /**
-     * Return a collection of values.
-     */
-    public Collection<Value> values() {
-        this.buildIfNeededMap();
-        return map.values();
-    }
-
-    /**
-     * Return the size of the map. Use the map if it has already been created.
-     *
-     * @return size
-     */
-    public int size() {
-        this.buildIfNeededMap();
-        return map.size();
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringService.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringService.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringService.java
new file mode 100644
index 0000000..3e96459
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringService.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json;
+
+import org.apache.groovy.json.FastStringService;
+
+/**
+ * Internal class for fast processing of Strings during JSON parsing - default version
+ */
+public class DefaultFastStringService implements FastStringService {
+    @Override
+    public char[] toCharArray(String string) {
+        return string.toCharArray();
+    }
+
+    @Override
+    public String noCopyStringFromChars(char[] chars) {
+        return new String(chars);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringServiceFactory.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringServiceFactory.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringServiceFactory.java
new file mode 100644
index 0000000..46d8a34
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringServiceFactory.java
@@ -0,0 +1,26 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json;
+
+public class DefaultFastStringServiceFactory implements FastStringServiceFactory {
+    @Override
+    public FastStringService getService() {
+        return new DefaultFastStringService();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringService.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringService.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringService.java
new file mode 100644
index 0000000..4381383
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringService.java
@@ -0,0 +1,33 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json;
+
+public interface FastStringService {
+    /**
+     * @param string string to grab array from.
+     * @return char array from string
+     */
+    char[] toCharArray(String string);
+
+    /**
+     * @param chars to shove array into.
+     * @return new string with chars copied into it
+     */
+    String noCopyStringFromChars(char[] chars);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringServiceFactory.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringServiceFactory.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringServiceFactory.java
new file mode 100644
index 0000000..6568793
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringServiceFactory.java
@@ -0,0 +1,28 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json;
+
+/**
+ * Factory method to create the service. Should return null if the particular implementation
+ * isn't suitable because of the JDK environment (e.g. JVM version) or config settings otherwise
+ * disable the service.
+ */
+public interface FastStringServiceFactory {
+    FastStringService getService();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ArrayUtils.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ArrayUtils.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ArrayUtils.java
new file mode 100644
index 0000000..4894f08
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ArrayUtils.java
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Richard Hightower
+ */
+public class ArrayUtils {
+
+    public static char[] copyRange(char[] source, int startIndex, int endIndex) {
+        int len = endIndex - startIndex;
+        char[] copy = new char[len];
+        System.arraycopy(source, startIndex, copy, 0, Math.min(source.length - startIndex, len));
+        return copy;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/BaseJsonParser.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/BaseJsonParser.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/BaseJsonParser.java
new file mode 100644
index 0000000..c2e58b2
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/BaseJsonParser.java
@@ -0,0 +1,228 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+import groovy.json.JsonParser;
+import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport;
+import org.codehaus.groovy.runtime.ResourceGroovyMethods;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Base JSON parser.
+ * Scaled down version of Boon JsonParser with features
+ * removed that are JDK 1.7 dependent or Groovy duplicated functionality.
+ *
+ * @author Rick Hightower
+ */
+public abstract class BaseJsonParser implements JsonParser {
+
+    protected static final int COLON = ':';
+    protected static final int COMMA = ',';
+    protected static final int CLOSED_CURLY = '}';
+    protected static final int CLOSED_BRACKET = ']';
+
+    protected static final int LETTER_E = 'e';
+    protected static final int LETTER_BIG_E = 'E';
+
+    protected static final int MINUS = '-';
+    protected static final int PLUS = '+';
+
+    protected static final int DECIMAL_POINT = '.';
+
+    protected static final int ALPHA_0 = '0';
+    protected static final int ALPHA_1 = '1';
+    protected static final int ALPHA_2 = '2';
+    protected static final int ALPHA_3 = '3';
+    protected static final int ALPHA_4 = '4';
+    protected static final int ALPHA_5 = '5';
+    protected static final int ALPHA_6 = '6';
+    protected static final int ALPHA_7 = '7';
+    protected static final int ALPHA_8 = '8';
+    protected static final int ALPHA_9 = '9';
+
+    protected static final int DOUBLE_QUOTE = '"';
+
+    protected static final int ESCAPE = '\\';
+
+    protected static final boolean internKeys = Boolean.parseBoolean(System.getProperty("groovy.json.internKeys", "false"));
+    protected static ConcurrentHashMap<String, String> internedKeysCache;
+
+    private static final Charset UTF_8 = Charset.forName("UTF-8");
+
+    protected String charset = UTF_8.name();
+
+    private CharBuf fileInputBuf;
+
+    protected int bufSize = 256;
+
+    static {
+        if (internKeys) {
+            internedKeysCache = new ConcurrentHashMap<String, String>();
+        }
+    }
+
+    protected String charDescription(int c) {
+        String charString;
+        if (c == ' ') {
+            charString = "[SPACE]";
+        } else if (c == '\t') {
+            charString = "[TAB]";
+
+        } else if (c == '\n') {
+            charString = "[NEWLINE]";
+
+        } else {
+            charString = "'" + (char) c + "'";
+        }
+
+        charString = charString + " with an int value of " + ((int) c);
+        return charString;
+    }
+
+    public void setCharset(String charset) {
+        this.charset = charset;
+    }
+
+    public Object parse(String jsonString) {
+        return parse(FastStringUtils.toCharArray(jsonString));
+    }
+
+    public Object parse(byte[] bytes) {
+        return parse(bytes, charset);
+    }
+
+    public Object parse(byte[] bytes, String charset) {
+        try {
+            return parse(new String(bytes, charset));
+        } catch (UnsupportedEncodingException e) {
+            return Exceptions.handle(Object.class, e);
+        }
+    }
+
+    public Object parse(CharSequence charSequence) {
+        return parse(FastStringUtils.toCharArray(charSequence));
+    }
+
+    public Object parse(Reader reader) {
+        fileInputBuf = IO.read(reader, fileInputBuf, bufSize);
+        return parse(fileInputBuf.readForRecycle());
+    }
+
+    public Object parse(InputStream input) {
+        return parse(input, charset);
+    }
+
+    public Object parse(InputStream input, String charset) {
+        try {
+            return parse(new InputStreamReader(input, charset));
+        } catch (UnsupportedEncodingException e) {
+            return Exceptions.handle(Object.class, e);
+        }
+    }
+
+    public Object parse(File file, String charset) {
+        Reader reader = null;
+        try {
+            if (charset == null || charset.length() == 0) {
+                reader = ResourceGroovyMethods.newReader(file);
+            } else {
+                reader = ResourceGroovyMethods.newReader(file, charset);
+            }
+            return parse(reader);
+        } catch (IOException ioe) {
+            throw new JsonException("Unable to process file: " + file.getPath(), ioe);
+        } finally {
+            if (reader != null) {
+                DefaultGroovyMethodsSupport.closeWithWarning(reader);
+            }
+        }
+    }
+
+    protected static boolean isDecimalChar(int currentChar) {
+        switch (currentChar) {
+            case MINUS:
+            case PLUS:
+            case LETTER_E:
+            case LETTER_BIG_E:
+            case DECIMAL_POINT:
+                return true;
+        }
+        return false;
+    }
+
+    protected static boolean isDelimiter(int c) {
+        return c == COMMA || c == CLOSED_CURLY || c == CLOSED_BRACKET;
+    }
+
+    protected static final boolean isNumberDigit(int c) {
+        return c >= ALPHA_0 && c <= ALPHA_9;
+    }
+
+    protected static final boolean isDoubleQuote(int c) {
+        return c == DOUBLE_QUOTE;
+    }
+
+    protected static final boolean isEscape(int c) {
+        return c == ESCAPE;
+    }
+
+    protected static boolean hasEscapeChar(char[] array, int index, int[] indexHolder) {
+        char currentChar;
+        for (; index < array.length; index++) {
+            currentChar = array[index];
+            if (isDoubleQuote(currentChar)) {
+                indexHolder[0] = index;
+                return false;
+            } else if (isEscape(currentChar)) {
+                indexHolder[0] = index;
+                return true;
+            }
+        }
+
+        indexHolder[0] = index;
+        return false;
+    }
+
+    int[] indexHolder = new int[1];
+
+    protected static int findEndQuote(final char[] array, int index) {
+        char currentChar;
+        boolean escape = false;
+
+        for (; index < array.length; index++) {
+            currentChar = array[index];
+            if (isDoubleQuote(currentChar)) {
+                if (!escape) {
+                    break;
+                }
+            }
+            escape = isEscape(currentChar) && !escape;
+        }
+        return index;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ByteScanner.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ByteScanner.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ByteScanner.java
new file mode 100644
index 0000000..8ddfb96
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ByteScanner.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+
+/**
+ * @author Richard Hightower
+ */
+public class ByteScanner {
+
+    /**
+     * Turns a single nibble into an ascii HEX digit.
+     *
+     * @param nibble the nibble to serializeObject.
+     * @return the encoded nibble (1/2 byte).
+     */
+    protected static int encodeNibbleToHexAsciiCharByte(final int nibble) {
+        switch (nibble) {
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07:
+            case 0x08:
+            case 0x09:
+                return nibble + 0x30; // 0x30('0') - 0x39('9')
+            case 0x0A:
+            case 0x0B:
+            case 0x0C:
+            case 0x0D:
+            case 0x0E:
+            case 0x0F:
+                return nibble + 0x57; // 0x41('a') - 0x46('f')
+            default:
+                die("illegal nibble: " + nibble);
+                return -1;
+        }
+    }
+
+    /**
+     * Turn a single bytes into two hex character representation.
+     *
+     * @param decoded the byte to serializeObject.
+     * @param encoded the array to which each encoded nibbles are now ascii hex representations.
+     */
+    public static void encodeByteIntoTwoAsciiCharBytes(final int decoded, final byte[] encoded) {
+        encoded[0] = (byte) encodeNibbleToHexAsciiCharByte((decoded >> 4) & 0x0F);
+        encoded[1] = (byte) encodeNibbleToHexAsciiCharByte(decoded & 0x0F);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Cache.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Cache.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Cache.java
new file mode 100644
index 0000000..f5cfaaa
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Cache.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * Cache
+ *
+ * @param <KEY>   key
+ * @param <VALUE> value
+ * @author Rick Hightower
+ */
+public interface Cache<KEY, VALUE> {
+
+    void put(KEY key, VALUE value);
+
+    VALUE get(KEY key);
+
+    VALUE getSilent(KEY key);
+
+    void remove(KEY key);
+
+    int size();
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CacheType.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CacheType.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CacheType.java
new file mode 100644
index 0000000..8d25bff
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CacheType.java
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Rick Hightower
+ */
+public enum CacheType {
+
+    LRU,
+    LFU,
+    FIFO
+}
+


[4/7] groovy git commit: GROOVY-8379: Rework groovy-json FastStringUtils (closes #667)

Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharBuf.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharBuf.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharBuf.java
new file mode 100644
index 0000000..db850e1
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharBuf.java
@@ -0,0 +1,842 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * @author Rick Hightower
+ */
+public class CharBuf extends Writer implements CharSequence {
+
+    protected int capacity = 16;
+    protected int location = 0;
+
+    protected char[] buffer;
+
+    public CharBuf(char[] buffer) {
+        __init__(buffer);
+    }
+
+    private void __init__(char[] buffer) {
+        this.buffer = buffer;
+        this.capacity = buffer.length;
+    }
+
+    public CharBuf(byte[] bytes) {
+        this.buffer = null;
+        try {
+            String str = new String(bytes, "UTF-8");
+            __init__(FastStringUtils.toCharArray(str));
+        } catch (UnsupportedEncodingException e) {
+            Exceptions.handle(e);
+        }
+    }
+
+    public static CharBuf createExact(final int capacity) {
+        return new CharBuf(capacity) {
+            public CharBuf add(char[] chars) {
+                Chr._idx(buffer, location, chars);
+                location += chars.length;
+                return this;
+            }
+        };
+    }
+
+    public static CharBuf create(int capacity) {
+        return new CharBuf(capacity);
+    }
+
+    public static CharBuf create(char[] buffer) {
+        return new CharBuf(buffer);
+    }
+
+    protected CharBuf(int capacity) {
+        this.capacity = capacity;
+        init();
+    }
+
+    protected CharBuf() {
+        init();
+    }
+
+    public void write(char[] cbuf, int off, int len) {
+        if (off == 0 && cbuf.length == len) {
+            this.add(cbuf);
+        } else {
+            char[] buffer = ArrayUtils.copyRange(cbuf, off, off + len);
+            this.add(buffer);
+        }
+    }
+
+    public void flush() throws IOException {
+    }
+
+    public void close() throws IOException {
+    }
+
+    public void init() {
+        buffer = new char[capacity];
+    }
+
+    public final CharBuf add(String str) {
+        add(FastStringUtils.toCharArray(str));
+        return this;
+    }
+
+    public final CharBuf addString(String str) {
+        add(FastStringUtils.toCharArray(str));
+        return this;
+    }
+
+    public final CharBuf add(int i) {
+        add(Integer.toString(i));
+        return this;
+    }
+
+    private Cache<Integer, char[]> icache;
+
+    public final CharBuf addInt(int i) {
+        switch (i) {
+            case 0:
+                addChar('0');
+                return this;
+            case 1:
+                addChar('1');
+                return this;
+            case -1:
+                addChar('-');
+                addChar('1');
+                return this;
+        }
+
+        addInt(Integer.valueOf(i));
+        return this;
+    }
+
+    public final CharBuf addInt(Integer key) {
+        if (icache == null) {
+            icache = new SimpleCache<Integer, char[]>(20);
+        }
+        char[] chars = icache.get(key);
+
+        if (chars == null) {
+            String str = Integer.toString(key);
+            chars = FastStringUtils.toCharArray(str);
+            icache.put(key, chars);
+        }
+
+        addChars(chars);
+        return this;
+    }
+
+    final char[] trueChars = "true".toCharArray();
+    final char[] falseChars = "false".toCharArray();
+
+    public final CharBuf add(boolean b) {
+        addChars(b ? trueChars : falseChars);
+        return this;
+    }
+
+    public final CharBuf addBoolean(boolean b) {
+        add(Boolean.toString(b));
+        return this;
+    }
+
+    public final CharBuf add(byte i) {
+        add(Byte.toString(i));
+        return this;
+    }
+
+    public final CharBuf addByte(byte i) {
+        addInt(i);
+        return this;
+    }
+
+    public final CharBuf add(short i) {
+        add(Short.toString(i));
+        return this;
+    }
+
+    public final CharBuf addShort(short i) {
+        addInt(i);
+        return this;
+    }
+
+    public final CharBuf add(long l) {
+        add(Long.toString(l));
+        return this;
+    }
+
+    public final CharBuf add(double d) {
+        add(Double.toString(d));
+        return this;
+    }
+
+    private Cache<Double, char[]> dcache;
+
+    public final CharBuf addDouble(double d) {
+        addDouble(Double.valueOf(d));
+        return this;
+    }
+
+    public final CharBuf addDouble(Double key) {
+        if (dcache == null) {
+            dcache = new SimpleCache<Double, char[]>(20);
+        }
+        char[] chars = dcache.get(key);
+
+        if (chars == null) {
+            String str = Double.toString(key);
+            chars = FastStringUtils.toCharArray(str);
+            dcache.put(key, chars);
+        }
+
+        add(chars);
+        return this;
+    }
+
+    public final CharBuf add(float d) {
+        add(Float.toString(d));
+        return this;
+    }
+
+    private Cache<Float, char[]> fcache;
+
+    public final CharBuf addFloat(float d) {
+        addFloat(Float.valueOf(d));
+        return this;
+    }
+
+    public final CharBuf addFloat(Float key) {
+        if (fcache == null) {
+            fcache = new SimpleCache<Float, char[]>(20);
+        }
+        char[] chars = fcache.get(key);
+
+        if (chars == null) {
+            String str = Float.toString(key);
+            chars = FastStringUtils.toCharArray(str);
+            fcache.put(key, chars);
+        }
+
+        add(chars);
+
+        return this;
+    }
+
+    public final CharBuf addChar(byte i) {
+        add((char) i);
+        return this;
+    }
+
+    public final CharBuf addChar(int i) {
+        add((char) i);
+        return this;
+    }
+
+    public final CharBuf addChar(short i) {
+        add((char) i);
+        return this;
+    }
+
+    public final CharBuf addChar(final char ch) {
+        int _location = location;
+        char[] _buffer = buffer;
+        int _capacity = capacity;
+
+        if (1 + _location > _capacity) {
+            _buffer = Chr.grow(_buffer);
+            _capacity = _buffer.length;
+        }
+
+        _buffer[_location] = ch;
+        _location++;
+
+        location = _location;
+        buffer = _buffer;
+        capacity = _capacity;
+        return this;
+    }
+
+    public CharBuf addLine(String str) {
+        add(str.toCharArray());
+        add('\n');
+        return this;
+    }
+
+    public CharBuf addLine(CharSequence str) {
+        add(str.toString());
+        add('\n');
+        return this;
+    }
+
+    public CharBuf add(char[] chars) {
+        if (chars.length + location > capacity) {
+            buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
+            capacity = buffer.length;
+        }
+
+        Chr._idx(buffer, location, chars);
+        location += chars.length;
+        return this;
+    }
+
+    public final CharBuf addChars(char[] chars) {
+        if (chars.length + location > capacity) {
+            buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
+            capacity = buffer.length;
+        }
+
+        System.arraycopy(chars, 0, buffer, location, chars.length);
+        location += chars.length;
+        return this;
+    }
+
+    public final CharBuf addQuoted(char[] chars) {
+        int _location = location;
+        char[] _buffer = buffer;
+        int _capacity = capacity;
+
+        int sizeNeeded = chars.length + 2 + _location;
+        if (sizeNeeded > _capacity) {
+            _buffer = Chr.grow(_buffer, sizeNeeded * 2);
+            _capacity = _buffer.length;
+        }
+        _buffer[_location] = '"';
+        _location++;
+
+        System.arraycopy(chars, 0, _buffer, _location, chars.length);
+
+        _location += (chars.length);
+        _buffer[_location] = '"';
+        _location++;
+
+        location = _location;
+        buffer = _buffer;
+        capacity = _capacity;
+        return this;
+    }
+
+    public final CharBuf addJsonEscapedString(String jsonString) {
+        return addJsonEscapedString(jsonString, false);
+    }
+
+    public final CharBuf addJsonEscapedString(String jsonString, boolean disableUnicodeEscaping) {
+        char[] charArray = FastStringUtils.toCharArray(jsonString);
+        return addJsonEscapedString(charArray, disableUnicodeEscaping);
+    }
+
+    private static boolean shouldEscape(int c, boolean disableUnicodeEscaping) {
+        if (c < 32) { /* less than space is a control char */
+            return true;
+        } else if (c == 34) {  /* double quote */
+            return true;
+        } else if (c == 92) {  /* backslash */
+            return true;
+        } else if (!disableUnicodeEscaping && c > 126) {  /* non-ascii char range */
+            return true;
+        }
+
+        return false;
+    }
+
+    private static boolean hasAnyJSONControlChars(final char[] charArray, boolean disableUnicodeEscaping) {
+        int index = 0;
+        char c;
+        while (true) {
+            c = charArray[index];
+            if (shouldEscape(c, disableUnicodeEscaping)) {
+                return true;
+            }
+            if (++index >= charArray.length) return false;
+        }
+    }
+
+    public final CharBuf addJsonEscapedString(final char[] charArray) {
+        return addJsonEscapedString(charArray, false);
+    }
+
+    public final CharBuf addJsonEscapedString(final char[] charArray, boolean disableUnicodeEscaping) {
+        if (charArray.length == 0) return this;
+        if (hasAnyJSONControlChars(charArray, disableUnicodeEscaping)) {
+            return doAddJsonEscapedString(charArray, disableUnicodeEscaping);
+        } else {
+            return this.addQuoted(charArray);
+        }
+    }
+
+    final byte[] encoded = new byte[2];
+
+    final byte[] charTo = new byte[2];
+
+    private CharBuf doAddJsonEscapedString(char[] charArray, boolean disableUnicodeEscaping) {
+        char[] _buffer = buffer;
+        int _location = this.location;
+
+        final byte[] _encoded = encoded;
+
+        final byte[] _charTo = charTo;
+        /* We are making a bet that not all chars will be unicode. */
+        int ensureThisMuch = charArray.length * 6 + 2;
+
+        int sizeNeeded = (ensureThisMuch) + _location;
+        if (sizeNeeded > capacity) {
+            int growBy = (_buffer.length * 2) < sizeNeeded ? sizeNeeded : (_buffer.length * 2);
+            _buffer = Chr.grow(buffer, growBy);
+            capacity = _buffer.length;
+        }
+
+        _buffer[_location] = '"';
+        _location++;
+
+        int index = 0;
+        while (true) {
+            char c = charArray[index];
+
+            if (shouldEscape(c, disableUnicodeEscaping)) {
+                   /* We are covering our bet with a safety net.
+                      otherwise we would have to have 5x buffer
+                      allocated for control chars */
+                if (_location + 5 > _buffer.length) {
+                    _buffer = Chr.grow(_buffer, 20);
+                }
+
+                switch (c) {
+                    case '\"':
+                        _buffer[_location] = '\\';
+                        _location++;
+                        _buffer[_location] = '"';
+                        _location++;
+                        break;
+                    case '\\':
+                        _buffer[_location] = '\\';
+                        _location++;
+                        _buffer[_location] = '\\';
+                        _location++;
+                        break;
+                    //There is not requirement to escape solidus so we will not.
+//                        case '/':
+//                            _buffer[_location] = '\\';
+//                            _location ++;
+//                            _buffer[_location] =  '/';
+//                            _location ++;
+//                            break;
+
+                    case '\b':
+                        _buffer[_location] = '\\';
+                        _location++;
+                        _buffer[_location] = 'b';
+                        _location++;
+                        break;
+                    case '\f':
+                        _buffer[_location] = '\\';
+                        _location++;
+                        _buffer[_location] = 'f';
+                        _location++;
+                        break;
+                    case '\n':
+                        _buffer[_location] = '\\';
+                        _location++;
+                        _buffer[_location] = 'n';
+                        _location++;
+                        break;
+                    case '\r':
+                        _buffer[_location] = '\\';
+                        _location++;
+                        _buffer[_location] = 'r';
+                        _location++;
+                        break;
+                    case '\t':
+                        _buffer[_location] = '\\';
+                        _location++;
+                        _buffer[_location] = 't';
+                        _location++;
+                        break;
+                    default:
+                        _buffer[_location] = '\\';
+                        _location++;
+                        _buffer[_location] = 'u';
+                        _location++;
+                        if (c <= 255) {
+                            _buffer[_location] = '0';
+                            _location++;
+                            _buffer[_location] = '0';
+                            _location++;
+                            ByteScanner.encodeByteIntoTwoAsciiCharBytes(c, _encoded);
+                            for (int b : _encoded) {
+                                _buffer[_location] = (char) b;
+                                _location++;
+                            }
+                        } else {
+                            _charTo[1] = (byte) (c);
+                            _charTo[0] = (byte) (c >>> 8);
+
+                            for (int charByte : _charTo) {
+                                ByteScanner.encodeByteIntoTwoAsciiCharBytes(charByte, _encoded);
+                                for (int b : _encoded) {
+                                    _buffer[_location] = (char) b;
+                                    _location++;
+                                }
+                            }
+                        }
+                }
+            } else {
+                _buffer[_location] = c;
+                _location++;
+            }
+
+            if (++index >= charArray.length) break;
+        }
+        _buffer[_location] = '"';
+        _location++;
+
+        buffer = _buffer;
+        location = _location;
+
+        return this;
+    }
+
+    public final CharBuf addJsonFieldName(String str) {
+        return addJsonFieldName(str, false);
+    }
+
+    public final CharBuf addJsonFieldName(String str, boolean disableUnicodeEscaping) {
+        return addJsonFieldName(FastStringUtils.toCharArray(str), disableUnicodeEscaping);
+    }
+
+    private static final char[] EMPTY_STRING_CHARS = Chr.array('"', '"');
+
+    public final CharBuf addJsonFieldName(char[] chars) {
+        return addJsonFieldName(chars, false);
+    }
+
+    public final CharBuf addJsonFieldName(char[] chars, boolean disableUnicodeEscaping) {
+        if (chars.length > 0) {
+            addJsonEscapedString(chars, disableUnicodeEscaping);
+        } else {
+            addChars(EMPTY_STRING_CHARS);
+        }
+        addChar(':');
+        return this;
+    }
+
+    public final CharBuf addQuoted(String str) {
+        final char[] chars = FastStringUtils.toCharArray(str);
+        addQuoted(chars);
+        return this;
+    }
+
+    public CharBuf add(char[] chars, final int length) {
+        if (length + location < capacity) {
+            Chr._idx(buffer, location, chars, length);
+        } else {
+            buffer = Chr.grow(buffer, buffer.length * 2 + length);
+            Chr._idx(buffer, location, chars);
+            capacity = buffer.length;
+        }
+        location += length;
+        return this;
+    }
+
+    public CharBuf add(byte[] chars) {
+        if (chars.length + location < capacity) {
+            Chr._idx(buffer, location, chars);
+        } else {
+            buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
+            Chr._idx(buffer, location, chars);
+            capacity = buffer.length;
+        }
+        location += chars.length;
+        return this;
+    }
+
+    public CharBuf add(byte[] bytes, int start, int end) {
+        int charsLength = end - start;
+        if (charsLength + location > capacity) {
+            buffer = Chr.grow(buffer, buffer.length * 2 + charsLength);
+        }
+        Chr._idx(buffer, location, bytes, start, end);
+        capacity = buffer.length;
+        location += charsLength;
+        return this;
+    }
+
+    public final CharBuf add(char ch) {
+        if (1 + location < capacity) {
+            buffer[location] = ch;
+        } else {
+            buffer = Chr.grow(buffer);
+            buffer[location] = ch;
+            capacity = buffer.length;
+        }
+        location += 1;
+        return this;
+    }
+
+    public int length() {
+        return len();
+    }
+
+    public char charAt(int index) {
+        return buffer[index];
+    }
+
+    public CharSequence subSequence(int start, int end) {
+        return new String(buffer, start, end - start);
+    }
+
+    public String toString() {
+        return new String(buffer, 0, location);
+    }
+
+    public String toDebugString() {
+        return "CharBuf{" +
+                "capacity=" + capacity +
+                ", location=" + location +
+                '}';
+    }
+
+    public String toStringAndRecycle() {
+        String str = new String(buffer, 0, location);
+        location = 0;
+        return str;
+    }
+
+    public int len() {
+        return location;
+    }
+
+    public char[] toCharArray() {
+        return this.buffer;
+    }
+
+    public void _len(int location) {
+        this.location = location;
+    }
+
+    public char[] readForRecycle() {
+        this.location = 0;
+        return this.buffer;
+    }
+
+    public void recycle() {
+        this.location = 0;
+    }
+
+    public double doubleValue() {
+        return CharScanner.parseDouble(this.buffer, 0, location);
+    }
+
+    public float floatValue() {
+        return CharScanner.parseFloat(this.buffer, 0, location);
+    }
+
+    public int intValue() {
+        return CharScanner.parseIntFromTo(buffer, 0, location);
+    }
+
+    public long longValue() {
+        return CharScanner.parseLongFromTo(buffer, 0, location);
+    }
+
+    public byte byteValue() {
+        return (byte) intValue();
+    }
+
+    public short shortValue() {
+        return (short) intValue();
+    }
+
+    public Number toIntegerWrapper() {
+        if (CharScanner.isInteger(buffer, 0, location)) {
+            return intValue();
+        } else {
+            return longValue();
+        }
+    }
+
+    static final char[] nullChars = "null".toCharArray();
+
+    public final void addNull() {
+        this.add(nullChars);
+    }
+
+    public void removeLastChar() {
+        if (location > 0) {
+            location--;
+        }
+    }
+
+    public void removeLastChar(char expect) {
+        if (location == 0 || buffer[location-1] != expect) {
+            return;
+        }
+        removeLastChar();
+    }
+
+    private Cache<BigDecimal, char[]> bigDCache;
+
+    public CharBuf addBigDecimal(BigDecimal key) {
+        if (bigDCache == null) {
+            bigDCache = new SimpleCache<BigDecimal, char[]>(20);
+        }
+        char[] chars = bigDCache.get(key);
+
+        if (chars == null) {
+            String str = key.toString();
+            chars = FastStringUtils.toCharArray(str);
+            bigDCache.put(key, chars);
+        }
+
+        add(chars);
+
+        return this;
+    }
+
+    private Cache<BigInteger, char[]> bigICache;
+
+    public CharBuf addBigInteger(BigInteger key) {
+        if (bigICache == null) {
+            bigICache = new SimpleCache<BigInteger, char[]>(20);
+        }
+        char[] chars = bigICache.get(key);
+
+        if (chars == null) {
+            String str = key.toString();
+            chars = FastStringUtils.toCharArray(str);
+            bigICache.put(key, chars);
+        }
+
+        add(chars);
+
+        return this;
+    }
+
+    private Cache<Long, char[]> lcache;
+
+    public final CharBuf addLong(long l) {
+        addLong(Long.valueOf(l));
+        return this;
+    }
+
+    public final CharBuf addLong(Long key) {
+        if (lcache == null) {
+            lcache = new SimpleCache<Long, char[]>(20);
+        }
+        char[] chars = lcache.get(key);
+
+        if (chars == null) {
+            String str = Long.toString(key);
+            chars = FastStringUtils.toCharArray(str);
+            lcache.put(key, chars);
+        }
+
+        add(chars);
+
+        return this;
+    }
+
+    public final CharBuf decodeJsonString(char[] chars) {
+        return decodeJsonString(chars, 0, chars.length);
+    }
+
+    public final CharBuf decodeJsonString(char[] chars, int start, int to) {
+        int len = to - start;
+
+        char[] buffer = this.buffer;
+        int location = this.location;
+
+        if (len > capacity) {
+            buffer = Chr.grow(buffer, buffer.length * 2 + len);
+            capacity = buffer.length;
+        }
+
+        for (int index = start; index < to; index++) {
+            char c = chars[index];
+            if (c == '\\') {
+                if (index < to) {
+                    index++;
+                    c = chars[index];
+                    switch (c) {
+
+                        case 'n':
+                            buffer[location++] = '\n';
+                            break;
+
+                        case '/':
+                            buffer[location++] = '/';
+                            break;
+
+                        case '"':
+                            buffer[location++] = '"';
+                            break;
+
+                        case 'f':
+                            buffer[location++] = '\f';
+                            break;
+
+                        case 't':
+                            buffer[location++] = '\t';
+                            break;
+
+                        case '\\':
+                            buffer[location++] = '\\';
+                            break;
+
+                        case 'b':
+                            buffer[location++] = '\b';
+                            break;
+
+                        case 'r':
+                            buffer[location++] = '\r';
+                            break;
+
+                        case 'u':
+                            if (index + 4 < to) {
+                                String hex = new String(chars, index + 1, 4);
+                                char unicode = (char) Integer.parseInt(hex, 16);
+                                buffer[location++] = unicode;
+                                index += 4;
+                            }
+                            break;
+
+                        default:
+                            throw new JsonException("Unable to decode string");
+                    }
+                }
+            } else {
+                buffer[location++] = c;
+            }
+        }
+
+        this.buffer = buffer;
+        this.location = location;
+
+        return this;
+    }
+}
+
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharScanner.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharScanner.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharScanner.java
new file mode 100644
index 0000000..2dfacf9
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharScanner.java
@@ -0,0 +1,512 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.math.BigDecimal;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+import static org.apache.groovy.json.internal.Exceptions.handle;
+
+/**
+ * @author Richard Hightower
+ */
+public class CharScanner {
+
+    protected static final int COMMA = ',';
+    protected static final int CLOSED_CURLY = '}';
+    protected static final int CLOSED_BRACKET = ']';
+    protected static final int LETTER_E = 'e';
+    protected static final int LETTER_BIG_E = 'E';
+    protected static final int DECIMAL_POINT = '.';
+    protected static final int ALPHA_0 = '0';
+    protected static final int ALPHA_9 = '9';
+    protected static final int MINUS = '-';
+    protected static final int PLUS = '+';
+
+    static final String MIN_LONG_STR_NO_SIGN = String.valueOf(Long.MIN_VALUE);
+    static final String MAX_LONG_STR = String.valueOf(Long.MAX_VALUE);
+    static final String MIN_INT_STR_NO_SIGN = String.valueOf(Integer.MIN_VALUE);
+    static final String MAX_INT_STR = String.valueOf(Integer.MAX_VALUE);
+
+    private static double powersOf10[] = {
+            1.0,
+            10.0,
+            100.0,
+            1000.0,
+            10000.0,
+            100000.0,
+            1000000.0,
+            10000000.0,
+            100000000.0,
+            1000000000.0,
+            10000000000.0,
+            100000000000.0,
+            1000000000000.0,
+            10000000000000.0,
+            100000000000000.0,
+            1000000000000000.0,
+            10000000000000000.0,
+            100000000000000000.0,
+            1000000000000000000.0,
+    };
+
+    public static boolean isDigit(int c) {
+        return c >= ALPHA_0 && c <= ALPHA_9;
+    }
+
+    public static boolean isDecimalDigit(int c) {
+        return isDigit(c) || isDecimalChar(c);
+    }
+
+    public static boolean isDecimalChar(int currentChar) {
+        switch (currentChar) {
+            case MINUS:
+            case PLUS:
+            case LETTER_E:
+            case LETTER_BIG_E:
+            case DECIMAL_POINT:
+                return true;
+        }
+        return false;
+    }
+
+    public static boolean hasDecimalChar(char[] chars, boolean negative) {
+        int index = 0;
+
+        if (negative) index++;
+
+        for (; index < chars.length; index++) {
+            switch (chars[index]) {
+                case MINUS:
+                case PLUS:
+                case LETTER_E:
+                case LETTER_BIG_E:
+                case DECIMAL_POINT:
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isLong(char[] digitChars) {
+        return isLong(digitChars, 0, digitChars.length);
+    }
+
+    public static boolean isLong(char[] digitChars, int offset, int len) {
+        String cmpStr = digitChars[offset] == '-' ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR;
+        int cmpLen = cmpStr.length();
+        if (len < cmpLen) return true;
+        if (len > cmpLen) return false;
+
+        for (int i = 0; i < cmpLen; ++i) {
+            int diff = digitChars[offset + i] - cmpStr.charAt(i);
+            if (diff != 0) {
+                return (diff < 0);
+            }
+        }
+        return true;
+    }
+
+    public static boolean isInteger(char[] digitChars) {
+        return isInteger(digitChars, 0, digitChars.length);
+    }
+
+    public static boolean isInteger(char[] digitChars, int offset, int len) {
+        String cmpStr = (digitChars[offset] == '-') ? MIN_INT_STR_NO_SIGN : MAX_INT_STR;
+        int cmpLen = cmpStr.length();
+        if (len < cmpLen) return true;
+        if (len > cmpLen) return false;
+
+        for (int i = 0; i < cmpLen; ++i) {
+            int diff = digitChars[offset + i] - cmpStr.charAt(i);
+            if (diff != 0) {
+                return (diff < 0);
+            }
+        }
+        return true;
+    }
+
+    public static int parseInt(char[] digitChars) {
+        return parseIntFromTo(digitChars, 0, digitChars.length);
+    }
+
+    public static int parseIntFromTo(char[] digitChars, int offset, int to) {
+        try {
+            int num;
+            boolean negative = false;
+            char c = digitChars[offset];
+            if (c == '-') {
+                offset++;
+                negative = true;
+            }
+            if (offset >= to) {
+                die();
+            }
+            num = (digitChars[offset] - '0');
+            if (++offset < to) {
+                num = (num * 10) + (digitChars[offset] - '0');
+                if (++offset < to) {
+                    num = (num * 10) + (digitChars[offset] - '0');
+                    if (++offset < to) {
+                        num = (num * 10) + (digitChars[offset] - '0');
+                        if (++offset < to) {
+                            num = (num * 10) + (digitChars[offset] - '0');
+                            if (++offset < to) {
+                                num = (num * 10) + (digitChars[offset] - '0');
+                                if (++offset < to) {
+                                    num = (num * 10) + (digitChars[offset] - '0');
+                                    if (++offset < to) {
+                                        num = (num * 10) + (digitChars[offset] - '0');
+                                        if (++offset < to) {
+                                            num = (num * 10) + (digitChars[offset] - '0');
+                                            if (++offset < to) {
+                                                num = (num * 10) + (digitChars[offset] - '0');
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            return negative ? num * -1 : num;
+        } catch (Exception ex) {
+            return handle(int.class, ex);
+        }
+    }
+
+    public static int parseIntFromToIgnoreDot(char[] digitChars, int offset, int to) {
+        int num;
+        boolean negative = false;
+        char c = digitChars[offset];
+        if (c == '-') {
+            offset++;
+            negative = true;
+        }
+        if (offset >= to) {
+            die();
+        }
+        c = digitChars[offset];
+        num = (c - '0');
+        offset++;
+
+        for (; offset < to; offset++) {
+            c = digitChars[offset];
+            if (c != '.') {
+                num = (num * 10) + (c - '0');
+            }
+        }
+
+        return negative ? num * -1 : num;
+    }
+
+    public static long parseLongFromToIgnoreDot(char[] digitChars, int offset, int to) {
+        long num;
+        boolean negative = false;
+        char c = digitChars[offset];
+        if (c == '-') {
+            offset++;
+            negative = true;
+        }
+        if (offset >= to) {
+            die();
+        }
+        c = digitChars[offset];
+        num = (c - '0');
+        offset++;
+
+        for (; offset < to; offset++) {
+            c = digitChars[offset];
+            if (c != '.') {
+                num = (num * 10) + (c - '0');
+            }
+        }
+
+        return negative ? num * -1 : num;
+    }
+
+    public static long parseLongFromTo(char[] digitChars, int offset, int to) {
+        long num;
+        boolean negative = false;
+        char c = digitChars[offset];
+        if (c == '-') {
+            offset++;
+            negative = true;
+        }
+        if (offset >= to) {
+            die();
+        }
+        c = digitChars[offset];
+        num = (c - '0');
+        offset++;
+
+        long digit;
+
+        for (; offset < to; offset++) {
+            c = digitChars[offset];
+            digit = (c - '0');
+            num = (num * 10) + digit;
+        }
+
+        return negative ? num * -1 : num;
+    }
+
+    public static long parseLong(char[] digitChars) {
+        return parseLongFromTo(digitChars, 0, digitChars.length);
+    }
+
+    public static Number parseJsonNumber(char[] buffer) {
+        return parseJsonNumber(buffer, 0, buffer.length);
+    }
+
+    public static Number parseJsonNumber(char[] buffer, int from, int to) {
+        return parseJsonNumber(buffer, from, to, null);
+    }
+
+    public static boolean isNumberDigit(int c) {
+        return c >= ALPHA_0 && c <= ALPHA_9;
+    }
+
+    protected static boolean isDelimiter(int c) {
+        return c == COMMA || c == CLOSED_CURLY || c == CLOSED_BRACKET;
+    }
+
+    public static Number parseJsonNumber(char[] buffer, int from, int max, int size[]) {
+        Number value = null;
+        boolean simple = true;
+        int digitsPastPoint = 0;
+
+        int index = from;
+
+        if (buffer[index] == '-') {
+            index++;
+        }
+        if (index >= max) {
+            die();
+        }
+
+        boolean foundDot = false;
+        for (; index < max; index++) {
+            char ch = buffer[index];
+            if (isNumberDigit(ch)) {
+                if (foundDot) {
+                    digitsPastPoint++;
+                }
+            } else if (ch <= 32 || isDelimiter(ch)) {
+                break;
+            } else if (ch == '.') {
+                if (foundDot) {
+                    die("unexpected character " + ch);
+                }
+                foundDot = true;
+            } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
+                simple = false;
+            } else {
+                die("unexpected character " + ch);
+            }
+        }
+
+        if (digitsPastPoint >= powersOf10.length - 1) {
+            simple = false;
+        }
+
+        final int length = index - from;
+
+        if (!foundDot && simple) {
+            if (isInteger(buffer, from, length)) {
+                value = parseIntFromTo(buffer, from, index);
+            } else {
+                value = parseLongFromTo(buffer, from, index);
+            }
+        } else {
+            value = new BigDecimal(buffer, from, length);
+        }
+
+        if (size != null) {
+            size[0] = index;
+        }
+
+        return value;
+    }
+
+    public static BigDecimal parseBigDecimal(char[] buffer) {
+        return new BigDecimal(buffer);
+    }
+
+    public static float parseFloat(char[] buffer, int from, int to) {
+        return (float) parseDouble(buffer, from, to);
+    }
+
+    public static double parseDouble(char[] buffer, int from, int to) {
+        double value;
+        boolean simple = true;
+        int digitsPastPoint = 0;
+
+        int index = from;
+
+        if (buffer[index] == '-') {
+            index++;
+        }
+
+        boolean foundDot = false;
+        for (; index < to; index++) {
+            char ch = buffer[index];
+            if (isNumberDigit(ch)) {
+                if (foundDot) {
+                    digitsPastPoint++;
+                }
+            } else if (ch == '.') {
+                if (foundDot) {
+                    die("unexpected character " + ch);
+                }
+                foundDot = true;
+            } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
+                simple = false;
+            } else {
+                die("unexpected character " + ch);
+            }
+        }
+
+        if (digitsPastPoint >= powersOf10.length - 1) {
+            simple = false;
+        }
+
+        final int length = index - from;
+
+        if (!foundDot && simple) {
+            if (isInteger(buffer, from, length)) {
+                value = parseIntFromTo(buffer, from, index);
+            } else {
+                value = parseLongFromTo(buffer, from, index);
+            }
+        } else if (foundDot && simple) {
+            long lvalue;
+
+            if (length < powersOf10.length) {
+                if (isInteger(buffer, from, length)) {
+                    lvalue = parseIntFromToIgnoreDot(buffer, from, index);
+                } else {
+                    lvalue = parseLongFromToIgnoreDot(buffer, from, index);
+                }
+
+                double power = powersOf10[digitsPastPoint];
+                value = lvalue / power;
+            } else {
+                value = Double.parseDouble(new String(buffer, from, length));
+            }
+        } else {
+            value = Double.parseDouble(new String(buffer, from, index - from));
+        }
+
+        return value;
+    }
+
+    public static int skipWhiteSpace(char[] array, int index, final int length) {
+        int c;
+        for (; index < length; index++) {
+            c = array[index];
+            if (c > 32) {
+                return index;
+            }
+        }
+        return index;
+    }
+
+    public static char[] readNumber(char[] array, int idx, final int len) {
+        final int startIndex = idx;
+
+        while (true) {
+            if (!CharScanner.isDecimalDigit(array[idx])) {
+                break;
+            } else {
+                idx++;
+                if (idx >= len) break;
+            }
+        }
+
+        return ArrayUtils.copyRange(array, startIndex, idx);
+    }
+
+    public static String errorDetails(String message, char[] array, int index, int ch) {
+        CharBuf buf = CharBuf.create(255);
+
+        buf.addLine(message);
+
+        buf.addLine("");
+        buf.addLine("The current character read is " + debugCharDescription(ch));
+
+        buf.addLine(message);
+
+        int line = 0;
+        int lastLineIndex = 0;
+
+        for (int i = 0; i < index && i < array.length; i++) {
+            if (array[i] == '\n') {
+                line++;
+                lastLineIndex = i + 1;
+            }
+        }
+
+        int count = 0;
+
+        for (int i = lastLineIndex; i < array.length; i++, count++) {
+            if (array[i] == '\n') {
+                break;
+            }
+        }
+
+        buf.addLine("line number " + (line + 1));
+        buf.addLine("index number " + index);
+
+        try {
+            buf.addLine(new String(array, lastLineIndex, count));
+        } catch (Exception ex) {
+            try {
+                int start = index = (index - 10 < 0) ? 0 : index - 10;
+
+                buf.addLine(new String(array, start, index));
+            } catch (Exception ex2) {
+                buf.addLine(new String(array, 0, array.length));
+            }
+        }
+        for (int i = 0; i < (index - lastLineIndex); i++) {
+            buf.add('.');
+        }
+        buf.add('^');
+
+        return buf.toString();
+    }
+
+    public static String debugCharDescription(int c) {
+        String charString;
+        if (c == ' ') {
+            charString = "[SPACE]";
+        } else if (c == '\t') {
+            charString = "[TAB]";
+        } else if (c == '\n') {
+            charString = "[NEWLINE]";
+        } else {
+            charString = "'" + (char) c + "'";
+        }
+
+        charString = charString + " with an int value of " + ((int) c);
+        return charString;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharSequenceValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharSequenceValue.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharSequenceValue.java
new file mode 100644
index 0000000..40ebc16
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharSequenceValue.java
@@ -0,0 +1,278 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Date;
+
+import static org.apache.groovy.json.internal.CharScanner.isInteger;
+import static org.apache.groovy.json.internal.CharScanner.parseIntFromTo;
+import static org.apache.groovy.json.internal.CharScanner.parseLongFromTo;
+import static org.apache.groovy.json.internal.Exceptions.die;
+
+/**
+ * @author Rick Hightower
+ */
+public class CharSequenceValue implements Value, CharSequence {
+
+    private final Type type;
+    private final boolean checkDate;
+    private final boolean decodeStrings;
+
+    private char[] buffer;
+    private boolean chopped;
+    private int startIndex;
+    private int endIndex;
+    private Object value;
+
+    public CharSequenceValue(boolean chop, Type type, int startIndex, int endIndex, char[] buffer,
+                             boolean encoded, boolean checkDate) {
+        this.type = type;
+        this.checkDate = checkDate;
+        this.decodeStrings = encoded;
+
+        if (chop) {
+            try {
+                this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
+            } catch (Exception ex) {
+                Exceptions.handle(ex);
+            }
+            this.startIndex = 0;
+            this.endIndex = this.buffer.length;
+            this.chopped = true;
+        } else {
+            this.startIndex = startIndex;
+            this.endIndex = endIndex;
+            this.buffer = buffer;
+        }
+    }
+
+    public String toString() {
+        if (startIndex == 0 && endIndex == buffer.length) {
+            return FastStringUtils.noCopyStringFromChars(buffer);
+        } else {
+            return new String(buffer, startIndex, (endIndex - startIndex));
+        }
+    }
+
+    public final Object toValue() {
+        return value != null ? value : (value = doToValue());
+    }
+
+    public <T extends Enum> T toEnum(Class<T> cls) {
+        switch (type) {
+            case STRING:
+                return toEnum(cls, stringValue());
+            case INTEGER:
+                return toEnum(cls, intValue());
+            case NULL:
+                return null;
+        }
+        die("toEnum " + cls + " value was " + stringValue());
+        return null;
+    }
+
+    public static <T extends Enum> T toEnum(Class<T> cls, String value) {
+        try {
+            return (T) Enum.valueOf(cls, value);
+        } catch (Exception ex) {
+            return (T) Enum.valueOf(cls, value.toUpperCase().replace('-', '_'));
+        }
+    }
+
+    public static <T extends Enum> T toEnum(Class<T> cls, int value) {
+        T[] enumConstants = cls.getEnumConstants();
+        for (T e : enumConstants) {
+            if (e.ordinal() == value) {
+                return e;
+            }
+        }
+        die("Can't convert ordinal value " + value + " into enum of type " + cls);
+        return null;
+    }
+
+    public boolean isContainer() {
+        return false;
+    }
+
+    private Object doToValue() {
+        switch (type) {
+            case DOUBLE:
+                return doubleValue();
+            case INTEGER:
+                if (isInteger(buffer, startIndex, endIndex - startIndex)) {
+                    return intValue();
+                } else {
+                    return longValue();
+                }
+            case STRING:
+                if (checkDate) {
+                    Date date = null;
+                    if (Dates.isISO8601QuickCheck(buffer, startIndex, endIndex)) {
+                        if (Dates.isJsonDate(buffer, startIndex, endIndex)) {
+                            date = Dates.fromJsonDate(buffer, startIndex, endIndex);
+                        } else if (Dates.isISO8601(buffer, startIndex, endIndex)) {
+                            date = Dates.fromISO8601(buffer, startIndex, endIndex);
+                        } else {
+                            return stringValue();
+                        }
+
+                        if (date == null) {
+                            return stringValue();
+                        } else {
+                            return date;
+                        }
+                    }
+                }
+                return stringValue();
+        }
+        die();
+        return null;
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof Value)) return false;
+
+        CharSequenceValue value1 = (CharSequenceValue) o;
+
+        if (endIndex != value1.endIndex) return false;
+        if (startIndex != value1.startIndex) return false;
+        if (!Arrays.equals(buffer, value1.buffer)) return false;
+        if (type != value1.type) return false;
+        return value != null ? value.equals(value1.value) : value1.value == null;
+
+    }
+
+    public int hashCode() {
+        int result = type != null ? type.hashCode() : 0;
+        result = 31 * result + (buffer != null ? Arrays.hashCode(buffer) : 0);
+        result = 31 * result + startIndex;
+        result = 31 * result + endIndex;
+        result = 31 * result + (value != null ? value.hashCode() : 0);
+        return result;
+    }
+
+    public final int length() {
+        return buffer.length;
+    }
+
+    public final char charAt(int index) {
+        return buffer[index];
+    }
+
+    public final CharSequence subSequence(int start, int end) {
+        return new CharSequenceValue(false, type, start, end, buffer, decodeStrings, checkDate);
+    }
+
+    public BigDecimal bigDecimalValue() {
+        return new BigDecimal(buffer, startIndex, endIndex - startIndex);
+    }
+
+    public BigInteger bigIntegerValue() {
+        return new BigInteger(toString());
+    }
+
+    public String stringValue() {
+        if (this.decodeStrings) {
+            return JsonStringDecoder.decodeForSure(buffer, startIndex, endIndex);
+        } else {
+            return toString();
+        }
+    }
+
+    public String stringValueEncoded() {
+        return JsonStringDecoder.decode(buffer, startIndex, endIndex);
+    }
+
+    public Date dateValue() {
+        if (type == Type.STRING) {
+
+            if (Dates.isISO8601QuickCheck(buffer, startIndex, endIndex)) {
+
+                if (Dates.isJsonDate(buffer, startIndex, endIndex)) {
+                    return Dates.fromJsonDate(buffer, startIndex, endIndex);
+
+                } else if (Dates.isISO8601(buffer, startIndex, endIndex)) {
+                    return Dates.fromISO8601(buffer, startIndex, endIndex);
+                } else {
+                    throw new JsonException("Unable to convert " + stringValue() + " to date ");
+                }
+            } else {
+                throw new JsonException("Unable to convert " + stringValue() + " to date ");
+            }
+        } else {
+            return new Date(Dates.utc(longValue()));
+        }
+    }
+
+    public int intValue() {
+        int sign = 1;
+        if (buffer[startIndex] == '-') {
+            startIndex++;
+            sign = -1;
+        }
+        return parseIntFromTo(buffer, startIndex, endIndex) * sign;
+    }
+
+    public long longValue() {
+        if (isInteger(buffer, startIndex, endIndex - startIndex)) {
+            return parseIntFromTo(buffer, startIndex, endIndex);
+        } else {
+            return parseLongFromTo(buffer, startIndex, endIndex);
+        }
+    }
+
+    public byte byteValue() {
+        return (byte) intValue();
+    }
+
+    public short shortValue() {
+        return (short) intValue();
+    }
+
+    public double doubleValue() {
+        return CharScanner.parseDouble(this.buffer, startIndex, endIndex);
+    }
+
+    public boolean booleanValue() {
+        return Boolean.parseBoolean(toString());
+    }
+
+    public float floatValue() {
+        return CharScanner.parseFloat(this.buffer, startIndex, endIndex);
+    }
+
+    public final void chop() {
+        if (!chopped) {
+            this.chopped = true;
+            this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
+            this.startIndex = 0;
+            this.endIndex = this.buffer.length;
+        }
+    }
+
+    public char charValue() {
+        return buffer[startIndex];
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharacterSource.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharacterSource.java
new file mode 100644
index 0000000..6fdecd4
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharacterSource.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Richard Hightower
+ */
+public interface CharacterSource {
+
+    /**
+     * Skip white space.
+     */
+    void skipWhiteSpace();
+
+    /**
+     * returns the next character moving the file pointer or index to the next location.
+     */
+    int nextChar();
+
+    /**
+     * returns the current character without changing the IO pointer or index.
+     */
+    int currentChar();
+
+    /**
+     * Checks to see if there is a next character.
+     */
+    boolean hasChar();
+
+    /**
+     * Useful for finding constants in a string like true, false, etc.
+     */
+    boolean consumeIfMatch(char[] match);
+
+    /**
+     * This is mostly for debugging and testing.
+     */
+    int location();
+
+    /**
+     * Combines the operations of nextChar and hasChar.
+     * Characters is -1 if not found which signifies end of file.
+     * This might be preferable to avoid two method calls.
+     */
+    int safeNextChar();
+
+    /**
+     * Used to find strings and their ilk
+     * Finds the next non-escaped char
+     *
+     * @param ch  character to find
+     * @param esc escape character to avoid next char if escaped
+     * @return list of chars until this is found.
+     */
+    char[] findNextChar(int ch, int esc);
+
+    boolean hadEscape();
+
+    /**
+     * Reads a number from the character source.
+     */
+    char[] readNumber();
+
+    String errorDetails(String message);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Chr.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Chr.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Chr.java
new file mode 100644
index 0000000..6996a8e
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Chr.java
@@ -0,0 +1,213 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Rick Hightower
+ */
+public class Chr {
+
+    public static char[] array(final char... array) {
+        return array;
+    }
+
+    public static char[] chars(final String array) {
+        return array.toCharArray();
+    }
+
+    public static boolean in(char value, char[] array) {
+        for (char currentValue : array) {
+            if (currentValue == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean in(int value, char[] array) {
+        for (int currentValue : array) {
+            if (currentValue == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean in(char value, int offset, char[] array) {
+        for (int index = offset; index < array.length; index++) {
+            char currentValue = array[index];
+            if (currentValue == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean in(char value, int offset, int end, char[] array) {
+        for (int index = offset; index < end; index++) {
+            char currentValue = array[index];
+            if (currentValue == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static char[] grow(char[] array, final int size) {
+        char[] newArray = new char[array.length + size];
+        arraycopy(array, 0, newArray, 0, array.length);
+        return newArray;
+    }
+
+    public static char[] grow(char[] array) {
+        char[] newArray = new char[array.length * 2];
+        arraycopy(array, 0, newArray, 0, array.length);
+        return newArray;
+    }
+
+    public static char[] copy(char[] array) {
+        char[] newArray = new char[array.length];
+        arraycopy(array, 0, newArray, 0, array.length);
+        return newArray;
+    }
+
+    public static char[] copy(char[] array, int offset, int length) {
+        char[] newArray = new char[length];
+        arraycopy(array, offset, newArray, 0, length);
+        return newArray;
+    }
+
+    public static char[] add(char[] array, char v) {
+        char[] newArray = new char[array.length + 1];
+        arraycopy(array, 0, newArray, 0, array.length);
+        newArray[array.length] = v;
+        return newArray;
+    }
+
+    public static char[] add(char[] array, String str) {
+        return add(array, str.toCharArray());
+    }
+
+    public static char[] add(char[] array, StringBuilder stringBuilder) {
+        return add(array, getCharsFromStringBuilder(stringBuilder));
+    }
+
+    public static char[] add(char[] array, char[] array2) {
+        char[] newArray = new char[array.length + array2.length];
+        arraycopy(array, 0, newArray, 0, array.length);
+        arraycopy(array2, 0, newArray, array.length, array2.length);
+        return newArray;
+    }
+
+    /* End universal methods. */
+
+    private static char[] getCharsFromStringBuilder(StringBuilder sbuf) {
+        final int length = sbuf.length();
+        char[] array2 = new char[length];
+        sbuf.getChars(0, length, array2, 0);
+        return array2;
+    }
+
+    public static char[] lpad(final char[] in, final int size, char pad) {
+        if (in.length >= size) {
+            return in;
+        }
+
+        int delta = size - in.length;
+        int index = 0;
+        char[] newArray = new char[size];
+
+        for (; index < delta; index++) {
+            newArray[index] = pad;
+        }
+
+        for (int index2 = 0; index2 < in.length; index++, index2++) {
+            newArray[index] = in[index2];
+        }
+
+        return newArray;
+    }
+
+    public static boolean contains(char[] chars, char c, int start, final int length) {
+        final int to = length + start;
+        for (int index = start; index < to; index++) {
+            char ch = chars[index];
+            if (ch == c) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static void _idx(char[] buffer, int location, byte[] chars) {
+        int index2 = 0;
+        int endLocation = (location + chars.length);
+        for (int index = location; index < endLocation; index++, index2++) {
+            buffer[index] = (char) chars[index2];
+        }
+    }
+
+    public static void _idx(final char[] array, int startIndex, char[] input) {
+        try {
+            arraycopy(input, 0, array, startIndex, input.length);
+        } catch (Exception ex) {
+            Exceptions.handle(String.format("array size %d, startIndex %d, input length %d",
+                    array.length, startIndex, input.length), ex);
+        }
+    }
+
+    private static void arraycopy(final char[] src, final int srcPos, final char[] dest, final int destPos, final int length) {
+        System.arraycopy(src, srcPos, dest, destPos, length);
+    }
+
+    public static void _idx(final char[] array, int startIndex, char[] input, final int inputLength) {
+        try {
+            arraycopy(input, 0, array, startIndex, inputLength);
+        } catch (Exception ex) {
+            Exceptions.handle(String.format("array size %d, startIndex %d, input length %d",
+                    array.length, startIndex, input.length), ex);
+        }
+    }
+
+    public static void _idx(char[] buffer, int location, byte[] chars, int start, int end) {
+        int index2 = start;
+        int endLocation = (location + (end - start));
+        for (int index = location; index < endLocation; index++, index2++) {
+            buffer[index] = (char) chars[index2];
+        }
+    }
+
+    public static char[] add(char[]... strings) {
+        int length = 0;
+        for (char[] str : strings) {
+            if (str == null) {
+                continue;
+            }
+            length += str.length;
+        }
+        CharBuf builder = CharBuf.createExact(length);
+        for (char[] str : strings) {
+            if (str == null) {
+                continue;
+            }
+            builder.add(str);
+        }
+        return builder.toCharArray();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Dates.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Dates.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Dates.java
new file mode 100644
index 0000000..0cd95f8
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Dates.java
@@ -0,0 +1,184 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * @author Rick Hightower
+ */
+public class Dates {
+
+    private static TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("UTC");
+
+    public static long utc(long time) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(time);
+        calendar.setTimeZone(UTC_TIME_ZONE);
+        return calendar.getTime().getTime();
+    }
+
+    private static Date internalDate(TimeZone tz, int year, int month, int day, int hour,
+                                     int minute, int second, int miliseconds) {
+
+        Calendar calendar = Calendar.getInstance();
+
+        calendar.set(Calendar.YEAR, year);
+        calendar.set(Calendar.MONTH, month - 1);
+        calendar.set(Calendar.DAY_OF_MONTH, day);
+        calendar.set(Calendar.HOUR_OF_DAY, hour);
+        calendar.set(Calendar.MINUTE, minute);
+        calendar.set(Calendar.SECOND, second);
+        calendar.set(Calendar.MILLISECOND, miliseconds);
+
+        calendar.setTimeZone(tz);
+
+        return calendar.getTime();
+    }
+
+    public static Date toDate(TimeZone tz, int year, int month, int day,
+                              int hour, int minute, int second) {
+        return internalDate(tz, year, month, day, hour, minute, second, 0);
+    }
+
+    public static Date toDate(TimeZone tz, int year, int month, int day,
+                              int hour, int minute, int second, int miliseconds) {
+        return internalDate(tz, year, month, day, hour, minute, second, miliseconds);
+    }
+
+    static final int SHORT_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30Z".length();
+    static final int LONG_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30-05:00".length();
+    public static final int JSON_TIME_LENGTH = "2013-12-14T01:55:33.412Z".length();
+
+    public static Date fromISO8601(char[] charArray, int from, int to) {
+        try {
+            if (isISO8601(charArray, from, to)) {
+                int year = CharScanner.parseIntFromTo(charArray, from, from + 4);
+                int month = CharScanner.parseIntFromTo(charArray, from + 5, from + 7);
+                int day = CharScanner.parseIntFromTo(charArray, from + 8, from + 10);
+                int hour = CharScanner.parseIntFromTo(charArray, from + 11, from + 13);
+
+                int minute = CharScanner.parseIntFromTo(charArray, from + 14, from + 16);
+
+                int second = CharScanner.parseIntFromTo(charArray, from + 17, from + 19);
+                TimeZone tz = null;
+
+                if (charArray[from + 19] == 'Z') {
+                    tz = TimeZone.getTimeZone("GMT");
+                } else {
+                    String tzStr = "GMT" + String.valueOf(charArray, from + 19, 6);
+                    tz = TimeZone.getTimeZone(tzStr);
+                }
+                return toDate(tz, year, month, day, hour, minute, second);
+            } else {
+                return null;
+            }
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    public static Date fromJsonDate(char[] charArray, int from, int to) {
+        try {
+            if (isJsonDate(charArray, from, to)) {
+                int year = CharScanner.parseIntFromTo(charArray, from, from + 4);
+                int month = CharScanner.parseIntFromTo(charArray, from + 5, from + 7);
+                int day = CharScanner.parseIntFromTo(charArray, from + 8, from + 10);
+                int hour = CharScanner.parseIntFromTo(charArray, from + 11, from + 13);
+
+                int minute = CharScanner.parseIntFromTo(charArray, from + 14, from + 16);
+
+                int second = CharScanner.parseIntFromTo(charArray, from + 17, from + 19);
+
+                int miliseconds = CharScanner.parseIntFromTo(charArray, from + 20, from + 23);
+
+                TimeZone tz = TimeZone.getTimeZone("GMT");
+
+                return toDate(tz, year, month, day, hour, minute, second, miliseconds);
+            } else {
+                return null;
+            }
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    public static boolean isISO8601(char[] charArray, int start, int to) {
+        boolean valid = true;
+        final int length = to - start;
+
+        if (length == SHORT_ISO_8601_TIME_LENGTH) {
+            valid &= (charArray[start + 19] == 'Z');
+        } else if (length == LONG_ISO_8601_TIME_LENGTH) {
+            valid &= (charArray[start + 19] == '-' || charArray[start + 19] == '+');
+            valid &= (charArray[start + 22] == ':');
+        } else {
+            return false;
+        }
+
+        //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
+        // "1 9 9 4 - 1 1 - 0 5 T 0 8 : 1 5 : 3 0 - 0 5 : 0 0
+
+        valid &= (charArray[start + 4] == '-') &&
+                (charArray[start + 7] == '-') &&
+                (charArray[start + 10] == 'T') &&
+                (charArray[start + 13] == ':') &&
+                (charArray[start + 16] == ':');
+
+        return valid;
+    }
+
+    public static boolean isISO8601QuickCheck(char[] charArray, int start, int to) {
+        final int length = to - start;
+
+        try {
+            return length == JSON_TIME_LENGTH || length == LONG_ISO_8601_TIME_LENGTH
+                    || length == SHORT_ISO_8601_TIME_LENGTH || (length >= 17 && (charArray[start + 16] == ':'));
+
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return false;
+        }
+    }
+
+    public static boolean isJsonDate(char[] charArray, int start, int to) {
+        boolean valid = true;
+        final int length = to - start;
+
+        if (length != JSON_TIME_LENGTH) {
+            return false;
+        }
+
+        valid &= (charArray[start + 19] == '.' || charArray[start + 19] == '+');
+
+        if (!valid) {
+            return false;
+        }
+
+        valid &= (charArray[start + 4] == '-') &&
+                (charArray[start + 7] == '-') &&
+                (charArray[start + 10] == 'T') &&
+                (charArray[start + 13] == ':') &&
+                (charArray[start + 16] == ':');
+
+        return valid;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java
new file mode 100644
index 0000000..e122778
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java
@@ -0,0 +1,178 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.Collections;
+
+/**
+ * @author Rick Hightower
+ */
+public class Exceptions {
+
+    public static boolean die() {
+        throw new JsonInternalException("died");
+    }
+
+    public static boolean die(String message) {
+        throw new JsonInternalException(message);
+    }
+
+    public static <T> T die(Class<T> clazz, String message) {
+        throw new JsonInternalException(message);
+    }
+
+    public static void handle(java.lang.Exception e) {
+        throw new JsonInternalException(e);
+    }
+
+    public static <T> T handle(Class<T> clazz, java.lang.Exception e) {
+        if (e instanceof JsonInternalException) {
+            throw (JsonInternalException) e;
+        }
+        throw new JsonInternalException(e);
+    }
+
+    public static <T> T handle(Class<T> clazz, String message, Throwable e) {
+        throw new JsonInternalException(message, e);
+    }
+
+    public static void handle(String message, Throwable e) {
+        throw new JsonInternalException(message, e);
+    }
+
+    public static class JsonInternalException extends JsonException {
+
+        public JsonInternalException(String message) {
+            super(message);
+        }
+
+        public JsonInternalException(String message, Throwable cause) {
+            super(message, cause);
+        }
+
+        public JsonInternalException(Throwable cause) {
+            super("Wrapped Exception", cause);
+        }
+
+        public void printStackTrace(PrintStream s) {
+            s.println(this.getMessage());
+            if (getCause() != null) {
+                s.println("This Exception was wrapped, the original exception\n" +
+                        "stack trace is:\n");
+                getCause().printStackTrace(s);
+            } else {
+                super.printStackTrace(s);
+            }
+        }
+
+        public String getMessage() {
+            return super.getMessage() + (getCause() == null ? "" :
+                    getCauseMessage());
+        }
+
+        private String getCauseMessage() {
+            return "\n CAUSE " + getCause().getClass().getName() + " :: " +
+                    getCause().getMessage();
+        }
+
+        public String getLocalizedMessage() {
+            return this.getMessage();
+        }
+
+        public StackTraceElement[] getStackTrace() {
+            if (getCause() != null) {
+                return getCause().getStackTrace();
+            } else {
+                return super.getStackTrace();
+            }
+        }
+
+        public Throwable getCause() {
+            return super.getCause();
+        }
+
+        public void printStackTrace(PrintWriter s) {
+            s.println(this.getMessage());
+
+            if (getCause() != null) {
+                s.println("This Exception was wrapped, the original exception\n" +
+                        "stack trace is:\n");
+                getCause().printStackTrace(s);
+            } else {
+                super.printStackTrace(s);
+            }
+        }
+
+        public void printStackTrace() {
+            System.err.println(this.getMessage());
+
+            if (getCause() != null) {
+                System.err.println("This Exception was wrapped, the original exception\n" +
+                        "stack trace is:\n");
+                getCause().printStackTrace();
+            } else {
+                super.printStackTrace();
+            }
+        }
+    }
+
+    public static String toString(Exception ex) {
+        CharBuf buffer = CharBuf.create(255);
+        buffer.addLine(ex.getLocalizedMessage());
+
+        final StackTraceElement[] stackTrace = ex.getStackTrace();
+        for (StackTraceElement element : stackTrace) {
+            buffer.add(element.getClassName());
+            sputs(buffer, "class", element.getClassName(),
+                    "method", element.getMethodName(), "line", element.getLineNumber());
+        }
+
+        return buffer.toString();
+    }
+
+    public static String sputs(CharBuf buf, Object... messages) {
+        int index = 0;
+        for (Object message : messages) {
+            if (index != 0) {
+                buf.add(' ');
+            }
+            index++;
+
+            if (message == null) {
+                buf.add("<NULL>");
+            } else if (message.getClass().isArray()) {
+                buf.add(Collections.singletonList(message).toString());
+            } else {
+                buf.add(message.toString());
+            }
+        }
+        buf.add('\n');
+
+        return buf.toString();
+    }
+
+    public static String sputs(Object... messages) {
+        CharBuf buf = CharBuf.create(100);
+        return sputs(buf, messages);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/FastStringUtils.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/FastStringUtils.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/FastStringUtils.java
new file mode 100644
index 0000000..a8c5dc6
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/FastStringUtils.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import org.apache.groovy.json.DefaultFastStringService;
+import org.apache.groovy.json.FastStringService;
+import org.apache.groovy.json.FastStringServiceFactory;
+
+import java.util.ServiceLoader;
+
+/**
+ * Internal class for fast processing of Strings during JSON parsing
+ */
+public class FastStringUtils {
+
+    private static class ServiceHolder {
+        static final FastStringService INSTANCE = loadService();
+
+        private static FastStringService loadService() {
+            ClassLoader loader = Thread.currentThread().getContextClassLoader();
+// left classloading very simple in light of potential changes needed for jdk9
+// that means you might need @GrabConfig(systemClassLoader=true) if getting json via grab
+//            ClassLoader rootLoader = DefaultGroovyMethods.getRootLoader(loader);
+            ServiceLoader<FastStringServiceFactory> serviceLoader = ServiceLoader.load(FastStringServiceFactory.class, loader);
+            FastStringService found = null;
+            for (FastStringServiceFactory factory : serviceLoader) {
+                FastStringService service = factory.getService();
+                if (service != null) {
+                    found = service;
+                    if (!(service instanceof DefaultFastStringService)) {
+                        break;
+                    }
+                }
+            }
+            return found;
+        }
+    }
+
+    private static FastStringService getService() {
+        if (ServiceHolder.INSTANCE == null) {
+            throw new RuntimeException("Unable to load FastStringService");
+        }
+        return ServiceHolder.INSTANCE;
+    }
+
+    /**
+     * @param string string to grab array from.
+     * @return char array from string
+     */
+    public static char[] toCharArray(final String string) {
+        return getService().toCharArray(string);
+    }
+
+    /**
+     * @param charSequence to grab array from.
+     * @return char array from char sequence
+     */
+    public static char[] toCharArray(final CharSequence charSequence) {
+        return toCharArray(charSequence.toString());
+    }
+
+    /**
+     * @param chars to shove array into.
+     * @return new string with chars copied into it
+     */
+    public static String noCopyStringFromChars(final char[] chars) {
+        return getService().noCopyStringFromChars(chars);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/IO.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/IO.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/IO.java
new file mode 100644
index 0000000..fdfec3e
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/IO.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+/**
+ * @author Rick Hightower
+ */
+public class IO {
+
+    private static final int EOF = -1;
+
+    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+    public static CharBuf read(Reader input, CharBuf charBuf, final int bufSize) {
+        if (charBuf == null) {
+            charBuf = CharBuf.create(bufSize);
+        } else {
+            charBuf.readForRecycle();
+        }
+
+        try {
+            char[] buffer = charBuf.toCharArray();
+            int size = input.read(buffer);
+            if (size != -1) {
+                charBuf._len(size);
+            }
+            if (size < 0) {
+                return charBuf;
+            }
+
+            copy(input, charBuf);
+        } catch (IOException e) {
+            Exceptions.handle(e);
+        } finally {
+            try {
+                input.close();
+            } catch (IOException e) {
+                Exceptions.handle(e);
+            }
+        }
+
+        return charBuf;
+    }
+
+    public static int copy(Reader input, Writer output) {
+        long count = copyLarge(input, output);
+        if (count > Integer.MAX_VALUE) {
+            return -1;
+        }
+        return (int) count;
+    }
+
+    public static long copyLarge(Reader reader, Writer writer) {
+        return copyLarge(reader, writer, new char[DEFAULT_BUFFER_SIZE]);
+    }
+
+    public static long copyLarge(Reader reader, Writer writer, char[] buffer) {
+        long count = 0;
+        int n;
+
+        try {
+            while (EOF != (n = reader.read(buffer))) {
+                writer.write(buffer, 0, n);
+                count += n;
+            }
+        } catch (IOException e) {
+            Exceptions.handle(e);
+        }
+        return count;
+    }
+}


[2/7] groovy git commit: GROOVY-8379: Rework groovy-json FastStringUtils (closes #667)

Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ReaderCharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ReaderCharacterSource.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ReaderCharacterSource.java
new file mode 100644
index 0000000..4517f7f
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ReaderCharacterSource.java
@@ -0,0 +1,264 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+/**
+ * @author Richard Hightower
+ */
+public class ReaderCharacterSource implements CharacterSource {
+
+    private static final int MAX_TOKEN_SIZE = 5;
+
+    private final Reader reader;
+    private final int readAheadSize;
+    private int ch = -2;
+
+    private boolean foundEscape;
+
+    private final char[] readBuf;
+
+    private int index;
+
+    private int length;
+
+    boolean more = true;
+    private boolean done = false;
+
+    public ReaderCharacterSource(final Reader reader, final int readAheadSize) {
+        this.reader = reader;
+        this.readBuf = new char[readAheadSize + MAX_TOKEN_SIZE];
+        this.readAheadSize = readAheadSize;
+    }
+
+    public ReaderCharacterSource(final Reader reader) {
+        this.reader = reader;
+        this.readAheadSize = 10000;
+        this.readBuf = new char[readAheadSize + MAX_TOKEN_SIZE];
+    }
+
+    public ReaderCharacterSource(final String string) {
+        this(new StringReader(string));
+    }
+
+    private void readForToken() {
+        try {
+            length += reader.read(readBuf, readBuf.length - MAX_TOKEN_SIZE, MAX_TOKEN_SIZE);
+        } catch (IOException e) {
+            Exceptions.handle(e);
+        }
+    }
+
+    private void ensureBuffer() {
+        try {
+            if (index >= length && !done) {
+                readNextBuffer();
+            } else {
+                more = !(done && index >= length);
+            }
+        } catch (Exception ex) {
+            String str = CharScanner.errorDetails("ensureBuffer issue", readBuf, index, ch);
+            Exceptions.handle(str, ex);
+        }
+    }
+
+    private void readNextBuffer() throws IOException {
+        length = reader.read(readBuf, 0, readAheadSize);
+
+        index = 0;
+        if (length == -1) {
+            ch = -1;
+            length = 0;
+            more = false;
+            done = true;
+        } else {
+            more = true;
+        }
+    }
+
+    public final int nextChar() {
+        ensureBuffer();
+        return ch = readBuf[index++];
+    }
+
+    public final int currentChar() {
+        ensureBuffer();
+        return readBuf[index];
+    }
+
+    public final boolean hasChar() {
+        ensureBuffer();
+        return more;
+    }
+
+    public final boolean consumeIfMatch(char[] match) {
+        try {
+            char[] _chars = readBuf;
+            int i = 0;
+            int idx = index;
+            boolean ok = true;
+
+            if (idx + match.length > length) {
+                readForToken();
+            }
+
+            for (; i < match.length; i++, idx++) {
+                ok &= (match[i] == _chars[idx]);
+                if (!ok) break;
+            }
+
+            if (ok) {
+                index = idx;
+                return true;
+            } else {
+                return false;
+            }
+        } catch (Exception ex) {
+            String str = CharScanner.errorDetails("consumeIfMatch issue", readBuf, index, ch);
+            return Exceptions.handle(boolean.class, str, ex);
+        }
+    }
+
+    public final int location() {
+        return index;
+    }
+
+    public final int safeNextChar() {
+        try {
+            ensureBuffer();
+            return index + 1 < readBuf.length ? readBuf[index++] : -1;
+        } catch (Exception ex) {
+            String str = CharScanner.errorDetails("safeNextChar issue", readBuf, index, ch);
+            return Exceptions.handle(int.class, str, ex);
+        }
+    }
+
+    private static final char[] EMPTY_CHARS = new char[0];
+
+    public char[] findNextChar(int match, int esc) {
+        try {
+            ensureBuffer();
+
+            foundEscape = false;
+            if (readBuf[index] == '"') {
+                index++;
+                return EMPTY_CHARS;
+            }
+
+            int start = index;
+
+            char[] results = null;
+            boolean foundEnd = false;
+            boolean wasEscaped = false;
+            while (!foundEnd) {
+                for (; index < length; index++) {
+                    ch = readBuf[index];
+                    if (wasEscaped) {
+                        wasEscaped = false;
+                    } else if (ch == match) {
+                        foundEnd = true;
+                        break;
+                    } else if (ch == esc) {
+                        foundEscape = true;
+                        wasEscaped = true;
+                    }
+                }
+
+                if (results != null) {
+                    results = Chr.add(results, ArrayUtils.copyRange(readBuf, start, index));
+                }
+                else {
+                    results = ArrayUtils.copyRange(readBuf, start, index);
+                }
+
+                ensureBuffer();
+
+                // Reset start if new buffer
+                if (index == 0) {
+                    start = 0;
+                }
+
+                // Exit early if we run out of data
+                if (done) {
+                    break;
+                }
+            }
+
+            // done will only be true if we ran out of data without seeing the match character
+            if (done) {
+                return Exceptions.die(char[].class, "Unable to find close char " + (char)match + ": " + new String(results));
+            } else {
+                index++;
+                return results;
+            }
+        } catch (Exception ex) {
+            String str = CharScanner.errorDetails("findNextChar issue", readBuf, index, ch);
+            return Exceptions.handle(char[].class, str, ex);
+        }
+    }
+
+    public boolean hadEscape() {
+        return foundEscape;
+    }
+
+    public void skipWhiteSpace() {
+        try {
+            index = CharScanner.skipWhiteSpace(readBuf, index, length);
+            if (index >= length && more) {
+                ensureBuffer();
+
+                skipWhiteSpace();
+            }
+        } catch (Exception ex) {
+            String str = CharScanner.errorDetails("skipWhiteSpace issue", readBuf, index, ch);
+            Exceptions.handle(str, ex);
+        }
+    }
+
+    public char[] readNumber() {
+        try {
+            ensureBuffer();
+
+            char[] results = CharScanner.readNumber(readBuf, index, length);
+            index += results.length;
+
+            if (index >= length && more) {
+                ensureBuffer();
+                if (length != 0) {
+                    char results2[] = readNumber();
+                    return Chr.add(results, results2);
+                } else {
+                    return results;
+                }
+            } else {
+                return results;
+            }
+        } catch (Exception ex) {
+            String str = CharScanner.errorDetails("readNumber issue", readBuf, index, ch);
+            return Exceptions.handle(char[].class, str, ex);
+        }
+    }
+
+    public String errorDetails(String message) {
+        return CharScanner.errorDetails(message, readBuf, index, ch);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/SimpleCache.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/SimpleCache.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/SimpleCache.java
new file mode 100644
index 0000000..afa54e8
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/SimpleCache.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import org.codehaus.groovy.runtime.memoize.CommonCache;
+import org.codehaus.groovy.runtime.memoize.EvictableCache;
+
+/**
+ * @author Richard Hightower
+ */
+public class SimpleCache<K, V> implements Cache<K, V> {
+    private EvictableCache<K, V> cache;
+
+    public SimpleCache(final int limit, CacheType type) {
+        if (type.equals(CacheType.LRU)) {
+            cache = new CommonCache<K, V>(limit);
+        } else {
+            cache = new CommonCache<K, V>(CommonCache.DEFAULT_INITIAL_CAPACITY, limit, EvictableCache.EvictionStrategy.FIFO);
+        }
+    }
+
+    public SimpleCache(final int limit) {
+        this(limit, CacheType.LRU);
+    }
+
+    public void put(K key, V value) {
+        cache.put(key, value);
+    }
+
+    public V get(K key) {
+        return cache.get(key);
+    }
+
+    //For testing only
+
+    public V getSilent(K key) {
+        V value = cache.get(key);
+        if (value != null) {
+            cache.remove(key);
+            cache.put(key, value);
+        }
+        return value;
+    }
+
+    public void remove(K key) {
+        cache.remove(key);
+    }
+
+    public int size() {
+        return cache.size();
+    }
+
+    public String toString() {
+        return cache.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java
new file mode 100644
index 0000000..6c7dac5
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.math.BigDecimal;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class Sys {
+
+    private static final boolean is1_8OrLater;
+    private static final boolean is1_7;
+    private static final boolean is1_8;
+
+    static {
+        BigDecimal v = new BigDecimal("-1");
+        String sversion = System.getProperty("java.version");
+        if (sversion.indexOf("_") != -1) {
+            final String[] split = sversion.split("_");
+            try {
+                String ver = split[0];
+
+                if (ver.startsWith("1.7")) {
+                    v = new BigDecimal("1.7");
+                }
+
+                if (ver.startsWith("1.8")) {
+                    v = new BigDecimal("1.8");
+                }
+
+                if (ver.startsWith("1.9")) {
+                    v = new BigDecimal("1.9");
+                }
+            } catch (Exception ex) {
+                ex.printStackTrace();
+                System.err.println("Unable to determine build number or version");
+            }
+        } else if ("1.8.0".equals(sversion)) {
+            v = new BigDecimal("1.8");
+        } else {
+            Pattern p = Pattern.compile("^([1-9]\\.[0-9]+)");
+            Matcher matcher = p.matcher(sversion);
+            if (matcher.find()) {
+                v = new BigDecimal(matcher.group(0));
+            }
+        }
+
+        is1_8OrLater = v.compareTo(new BigDecimal("1.8")) >= 0;
+        is1_7 = v.compareTo(new BigDecimal("1.7")) == 0;
+        is1_8 = v.compareTo(new BigDecimal("1.8")) == 0;
+    }
+
+    public static boolean is1_7OrLater() {
+        return true;
+    }
+
+    public static boolean is1_8OrLater() {
+        return is1_8OrLater;
+    }
+
+    public static boolean is1_7() {
+        return is1_7;
+    }
+
+    public static boolean is1_8() {
+        return is1_8;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Type.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Type.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Type.java
new file mode 100644
index 0000000..5ce3d27
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Type.java
@@ -0,0 +1,28 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Richard Hightower
+ */
+public enum Type {
+
+    INTEGER, STRING, DOUBLE, TRUE, FALSE, NULL, MAP, LIST
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Value.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Value.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Value.java
new file mode 100644
index 0000000..f3024fb
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Value.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * @author Rick Hightower
+ */
+public interface Value {
+
+    byte byteValue();
+
+    short shortValue();
+
+    int intValue();
+
+    long longValue();
+
+    BigDecimal bigDecimalValue();
+
+    BigInteger bigIntegerValue();
+
+    float floatValue();
+
+    double doubleValue();
+
+    boolean booleanValue();
+
+    Date dateValue();
+
+    String stringValue();
+
+    String stringValueEncoded();
+
+    Object toValue();
+
+    <T extends Enum> T toEnum(Class<T> cls);
+
+    boolean isContainer(); //either a map or a collection
+
+    void chop();
+
+    char charValue();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueContainer.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueContainer.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueContainer.java
new file mode 100644
index 0000000..aa21168
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueContainer.java
@@ -0,0 +1,174 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+import static org.apache.groovy.json.internal.Exceptions.sputs;
+
+/**
+ * @author Rick Hightower
+ */
+public class ValueContainer implements CharSequence, Value {
+
+    public static final Value TRUE = new ValueContainer(Type.TRUE);
+    public static final Value FALSE = new ValueContainer(Type.FALSE);
+    public static final Value NULL = new ValueContainer(Type.NULL);
+
+    public Object value;
+
+    public Type type;
+    private boolean container;
+
+    public boolean decodeStrings;
+
+    public ValueContainer(Object value, Type type, boolean decodeStrings) {
+        this.value = value;
+        this.type = type;
+        this.decodeStrings = decodeStrings;
+    }
+
+    public ValueContainer(Type type) {
+        this.type = type;
+    }
+
+    public ValueContainer(Map<String, Object> map) {
+        this.value = map;
+        this.type = Type.MAP;
+        this.container = true;
+    }
+
+    public ValueContainer(List<Object> list) {
+        this.value = list;
+        this.type = Type.LIST;
+        this.container = true;
+    }
+
+    public int intValue() {
+        return die(int.class, sputs("intValue not supported for type ", type));
+    }
+
+    public long longValue() {
+        return die(int.class, sputs("intValue not supported for type ", type));
+    }
+
+    public boolean booleanValue() {
+        switch (type) {
+            case FALSE:
+                return false;
+            case TRUE:
+                return true;
+        }
+        die();
+        return false;
+    }
+
+    public String stringValue() {
+        if (type == Type.NULL) {
+            return null;
+        } else {
+            return type.toString();
+        }
+    }
+
+    public String stringValueEncoded() {
+        return toString();
+    }
+
+    public String toString() {
+        return type.toString();
+    }
+
+    public Object toValue() {
+        if (value != null) {
+            return value;
+        }
+        switch (type) {
+            case FALSE:
+                return (value = false);
+
+            case TRUE:
+                return (value = true);
+            case NULL:
+                return null;
+        }
+        die();
+        return null;
+    }
+
+    public <T extends Enum> T toEnum(Class<T> cls) {
+        return (T) value;
+    }
+
+    public boolean isContainer() {
+        return container;
+    }
+
+    public void chop() {
+    }
+
+    public char charValue() {
+        return 0;
+    }
+
+    public int length() {
+        return 0;
+    }
+
+    public char charAt(int index) {
+        return '0';
+    }
+
+    public CharSequence subSequence(int start, int end) {
+        return "";
+    }
+
+    public Date dateValue() {
+        return null;
+    }
+
+    public byte byteValue() {
+        return 0;
+    }
+
+    public short shortValue() {
+        return 0;
+    }
+
+    public BigDecimal bigDecimalValue() {
+        return null;
+    }
+
+    public BigInteger bigIntegerValue() {
+        return null;
+    }
+
+    public double doubleValue() {
+        return 0;
+    }
+
+    public float floatValue() {
+        return 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueList.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueList.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueList.java
new file mode 100644
index 0000000..7027200
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueList.java
@@ -0,0 +1,123 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author Rick Hightower
+ */
+public class ValueList extends AbstractList<Object> {
+
+    List<Object> list = new ArrayList<Object>(5);
+
+    private final boolean lazyChop;
+    boolean converted = false;
+
+    public ValueList(boolean lazyChop) {
+        this.lazyChop = lazyChop;
+    }
+
+    public Object get(int index) {
+        Object obj = list.get(index);
+
+        if (obj instanceof Value) {
+            obj = convert((Value) obj);
+            list.set(index, obj);
+        }
+
+        chopIfNeeded(obj);
+        return obj;
+    }
+
+    private static Object convert(Value value) {
+        return value.toValue();
+    }
+
+    public int size() {
+        return list.size();
+    }
+
+    public Iterator<Object> iterator() {
+        convertAllIfNeeded();
+        return list.iterator();
+    }
+
+    private void convertAllIfNeeded() {
+        if (!converted) {
+            converted = true;
+            for (int index = 0; index < list.size(); index++) {
+                this.get(index);
+            }
+        }
+    }
+
+    public void clear() {
+        list.clear();
+    }
+
+    public boolean add(Object obj) {
+        return list.add(obj);
+    }
+
+    public void chopList() {
+        for (Object obj : list) {
+            if (obj == null) continue;
+
+            if (obj instanceof Value) {
+                Value value = (Value) obj;
+                if (value.isContainer()) {
+                    chopContainer(value);
+                } else {
+                    value.chop();
+                }
+            }
+        }
+    }
+
+    private void chopIfNeeded(Object object) {
+        if (lazyChop) {
+            if (object instanceof LazyValueMap) {
+                LazyValueMap m = (LazyValueMap) object;
+                m.chopMap();
+            } else if (object instanceof ValueList) {
+                ValueList list = (ValueList) object;
+                list.chopList();
+            }
+        }
+    }
+
+    static void chopContainer(Value value) {
+        Object obj = value.toValue();
+        if (obj instanceof LazyValueMap) {
+            LazyValueMap map = (LazyValueMap) obj;
+            map.chopMap();
+        } else if (obj instanceof ValueList) {
+            ValueList list = (ValueList) obj;
+            list.chopList();
+        }
+    }
+
+    public List<Object> list() {
+        return this.list;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMap.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMap.java
new file mode 100644
index 0000000..c238cbf
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMap.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.Map;
+
+/**
+ * @author Richard Hightower
+ */
+public interface ValueMap<K, V> extends Map<K, V> {
+
+    /* add a map item value. */
+    void add(MapItemValue miv);
+
+    /**
+     * Return size w/o hydrating the map.
+     */
+    int len();
+
+    /**
+     * Has the map been hydrated.
+     */
+    boolean hydrated();
+
+    /**
+     * Give me the items in the map without hydrating the map.
+     * Realize that the array is likely larger than the length so array items can be null.
+     */
+    Entry<String, Value>[] items();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMapImpl.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMapImpl.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMapImpl.java
new file mode 100644
index 0000000..0b3103e
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMapImpl.java
@@ -0,0 +1,147 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+
+/**
+ * This map is for object serialization mainly.
+ * The idea is the final conversion of
+ * the Value objects are delayed until the last possible moment, i.e., just before injected into a bean.
+ *
+ * @author Rick Hightower
+ */
+public class ValueMapImpl extends AbstractMap<String, Value> implements ValueMap<String, Value> {
+
+    /**
+     * The internal map to hold the Value map.
+     */
+    private Map<String, Value> map = null;
+
+    /**
+     * The items held in the map.
+     */
+    private Entry<String, Value>[] items = new Entry[20];
+
+    /* The current length of the map. */
+    private int len = 0;
+
+    /**
+     * Add a MapItemValue to the map.
+     *
+     * @param miv map value item.
+     */
+
+    public void add(MapItemValue miv) {
+        if (len >= items.length) {
+            items = LazyMap.grow(items);
+        }
+        items[len] = miv;
+        len++;
+    }
+
+    public int len() {
+        return len;
+    }
+
+    public boolean hydrated() {
+        return map != null;
+    }
+
+    public Entry<String, Value>[] items() {
+        return items;
+    }
+
+    /**
+     * Get the items for the key.
+     *
+     * @param key
+     * @return the items for the given key
+     */
+
+    public Value get(Object key) {
+        /* If the length is under and we are asking for the key, then just look for the key. Don't build the map. */
+        if (map == null && items.length < 20) {
+            for (Object item : items) {
+                MapItemValue miv = (MapItemValue) item;
+                if (key.equals(miv.name.toValue())) {
+                    return miv.value;
+                }
+            }
+            return null;
+        } else {
+            if (map == null) buildIfNeededMap();
+            return map.get(key);
+        }
+    }
+
+    public Value put(String key, Value value) {
+        die("Not that kind of map");
+        return null;
+    }
+
+    /**
+     * If the map has not been built yet, then we just return a fake entry set.
+     */
+
+    public Set<Entry<String, Value>> entrySet() {
+        buildIfNeededMap();
+        return map.entrySet();
+    }
+
+    /**
+     * Build the map if requested to, it does this lazily.
+     */
+    private void buildIfNeededMap() {
+        if (map == null) {
+            map = new HashMap<String, Value>(items.length);
+
+            for (Entry<String, Value> miv : items) {
+                if (miv == null) {
+                    break;
+                }
+                map.put(miv.getKey(), miv.getValue());
+            }
+        }
+    }
+
+    /**
+     * Return a collection of values.
+     */
+    public Collection<Value> values() {
+        this.buildIfNeededMap();
+        return map.values();
+    }
+
+    /**
+     * Return the size of the map. Use the map if it has already been created.
+     *
+     * @return size
+     */
+    public int size() {
+        this.buildIfNeededMap();
+        return map.size();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory b/subprojects/groovy-json/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
new file mode 100644
index 0000000..eff53ea
--- /dev/null
+++ b/subprojects/groovy-json/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
@@ -0,0 +1,19 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+#
+org.apache.groovy.json.DefaultFastStringServiceFactory

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy
index 8915f55..a09721c 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy
@@ -18,7 +18,7 @@
  */
 package groovy.json
 
-import groovy.json.internal.CharBuf
+import org.apache.groovy.json.internal.CharBuf
 
 /**
  * Test the internal CharBuf class

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy
index ad21ee9..09bb35f 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy
@@ -20,7 +20,7 @@ package groovy.json
 
 import groovy.json.JsonGenerator.Converter
 import groovy.json.JsonGenerator.Options
-import groovy.json.internal.CharBuf
+import org.apache.groovy.json.internal.CharBuf
 
 /**
  * Tests extensibility of JsonGenerator and associated classes

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy
index 3ec2266..17819f5 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy
@@ -18,8 +18,8 @@
  */
 package groovy.json
 
-import groovy.json.internal.CharBuf
-import groovy.json.internal.IO
+import org.apache.groovy.json.internal.CharBuf
+import org.apache.groovy.json.internal.IO
 
 /**
  * Test the internal IO class

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
index 9356825..db039d3 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
@@ -18,7 +18,7 @@
  */
 package groovy.json
 
-import groovy.json.internal.Value
+import org.apache.groovy.json.internal.Value
 
 /**
  * @author Guillaume Laforge

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ArrayUtilsTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ArrayUtilsTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ArrayUtilsTest.groovy
deleted file mode 100644
index 890350e..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ArrayUtilsTest.groovy
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal
-
-class ArrayUtilsTest extends GroovyTestCase {
-
-    void testCopyRange() {
-        char[] chars = "t"
-        assert ArrayUtils.copyRange(chars, 0, 1) == ((char[]) "t")
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy
deleted file mode 100644
index a420eef..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal
-
-class CharScannerTest extends GroovyTestCase {
-
-    void testParseInt() {
-        int i = CharScanner.parseInt("-22".toCharArray())
-        assert i == -22
-
-        i = CharScanner.parseInt("22".toCharArray())
-        assert i == 22
-    }
-
-    void testParseLongTest() {
-        long value = CharScanner.parseLong("-22".toCharArray())
-        assert value == -22L
-
-        value = CharScanner.parseInt("22".toCharArray())
-        assert value == 22
-    }
-
-    void testParseLongTest2() {
-        String test = "" + ((long) (Long.MAX_VALUE / 2L))
-        long value = CharScanner.parseLong(test.toCharArray())
-        assert value == Long.parseLong(test)
-    }
-
-    void testParseLongTest3() {
-        String test = "" + (Long.MIN_VALUE / 2L)
-        long value = CharScanner.parseLong(test.toCharArray())
-        assert value == Long.parseLong(test)
-    }
-
-    void testParseLongTest4() {
-        String test = "" + (Long.MAX_VALUE)
-        long value = CharScanner.parseLong(test.toCharArray())
-        assert value == Long.parseLong(test)
-    }
-
-    void testParseLongTest5() {
-        String test = "" + (Long.MIN_VALUE)
-        long value = CharScanner.parseLong(test.toCharArray())
-        assert value == Long.parseLong(test)
-    }
-
-    void testParseIntMax() {
-        int i = 0
-        i = CharScanner.parseInt(("" + Integer.MAX_VALUE).toCharArray())
-        assert i == Integer.MAX_VALUE
-    }
-
-    void testParseIntMin() {
-        int i = 0
-        i = CharScanner.parseInt(("" + Integer.MIN_VALUE).toCharArray())
-        assert i == Integer.MIN_VALUE
-    }
-
-    void testParseLongMax() {
-        long l = 0
-        l = CharScanner.parseLong(("" + Long.MAX_VALUE).toCharArray())
-        assert l == Long.MAX_VALUE
-    }
-
-    void testParseLongMin() {
-        long l = 0
-        l = CharScanner.parseLong(("" + Long.MIN_VALUE).toCharArray())
-        assert l == Long.MIN_VALUE || die("l", l, "MIN", Long.MIN_VALUE)
-    }
-
-    void testParseDouble() {
-        String str = "123456789"
-        double num =
-            CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length()).doubleValue()
-        assert num == 123456789d
-    }
-
-    void testParseDoubleNegative() {
-        String str = "-1.23456789E8"
-        double num =
-            (Double) CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length())
-        assert num == -1.23456789E8
-    }
-
-    void testParseDoubleNegativeNoE() {
-        String str = "-123456789"
-        testDouble(str)
-    }
-
-    void testParseDoubleNegativeNoE2() {
-        String str = "-1234567890"
-        testDouble(str)
-    }
-
-    void testParseDoubleMax() {
-        String str = "" + Double.MAX_VALUE
-        testDouble(str)
-    }
-
-    void testParseDoubleMin() {
-        String str = "" + Double.MIN_VALUE
-        testDouble(str)
-    }
-
-    void testManyDoubles() {
-        List<String> doubles = ["" + 1.01d, "" + 123456789.234D, "" + 55D,
-                "" + Integer.MAX_VALUE + "." + Integer.MAX_VALUE,
-                "66666666.666", "-6666666666.6666", "1E10"]
-
-        for (String str : doubles) {
-            testDouble(str)
-        }
-    }
-
-    private void testDouble(String str) {
-        double num = CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length()).doubleValue()
-        assert num == Double.parseDouble(str)
-    }
-
-    private void testDoubleInStringThreeOver(String str) {
-        double numTest = Double.parseDouble(str)
-        double num = CharScanner.parseJsonNumber(("   " + str).toCharArray(), 3, str.length() + 3).doubleValue()
-        assert num == numTest
-    }
-
-    void testParseIntIgnore0() {
-        int i = CharScanner.parseIntFromToIgnoreDot("1.1".toCharArray(), 0, "1.1".length())
-        assert i == 11
-    }
-
-    void testSimpleDoubleInString() {
-        testDoubleInStringThreeOver("1.1")
-    }
-
-    void testLongMaxWithOffset() {
-        testDoubleInStringThreeOver("" + Long.MAX_VALUE)
-    }
-
-    void testLargeDecimal() {
-        testDoubleInStringThreeOver("" + Integer.MAX_VALUE + "." + Integer.MAX_VALUE)
-    }
-
-    void testLargeDecimal2() {
-        testDoubleInStringThreeOver("1000" + "." + "10001")
-    }
-
-    void testLargeDecimal3() {
-        testDoubleInStringThreeOver("10000" + "." + "100001")
-    }
-
-    void testLargeDecimal4() {
-        testDoubleInStringThreeOver("" + 10_000_000 + "." + 10_000_001)
-    }
-
-    void testLargeDecimal5() {
-        testDoubleInStringThreeOver("" + 100_000_000 + "." + 100_000_001)
-    }
-
-    void testLargeDecimal6() {
-        testDoubleInStringThreeOver("" + 100_000_000 + "." + 1_000_000_001)
-    }
-
-    void testLargeDecimal7() {
-        testDoubleInStringThreeOver("" + 100_000_000 + "." + 1_000_000_001L)
-    }
-
-    void testLargeDecimal8() {
-        testDoubleInStringThreeOver("" + 1_000_000_000_000L + "." + 1_000_000_001L)
-    }
-
-    void testLargeDecimal9() {
-        testDoubleInStringThreeOver("" + 10_000_000_000_000L + "." + 1_000_000_001L)
-    }
-
-    void testLargeDecimal10() {
-        testDoubleInStringThreeOver("" + 100_000_000_000_000_000L + "." + 1_000_000_001L)
-    }
-
-    void testLargeDecimal11() {
-        testDoubleInStringThreeOver("" + 1_000_000_000_000_000_000L + "." + 1_000_000_001L)
-    }
-
-    void testLongMinWithOffset() {
-        testDoubleInStringThreeOver("" + Long.MIN_VALUE)
-    }
-
-    void testDoubleMaxWithOffset() {
-        testDoubleInStringThreeOver("" + Double.MAX_VALUE)
-    }
-
-    void testDoubleMinWithOffset() {
-        testDoubleInStringThreeOver("" + Double.MIN_VALUE)
-    }
-
-    void testDoubleMaxWithOffset2() {
-        testDoubleInStringThreeOver("" + Double.MAX_VALUE / 2)
-    }
-
-    void testDoubleMinWithOffset2() {
-        testDoubleInStringThreeOver("" + Double.MIN_VALUE / 2)
-    }
-
-    void testDoubleMaxWithOffset3() {
-        testDoubleInStringThreeOver("" + (Double.MAX_VALUE / 9) * 8)
-    }
-
-    void testDoubleMinWithOffset3() {
-        testDoubleInStringThreeOver("" + (Double.MIN_VALUE / 9) * 8)
-    }
-
-    void testParseLong() {
-        String str = "12345678910"
-        long l1 = CharScanner.parseLongFromTo(str.toCharArray(), 0, str.length())
-        assert l1 == 12345678910L
-
-        str = "abc12345678910"
-        l1 = CharScanner.parseLongFromTo(str.toCharArray(), 3, str.length())
-        assert l1 == 12345678910L
-
-        str = "abcdefghijklmnopqrstuvwxyz12345678910"
-        l1 = CharScanner.parseLongFromTo(str.toCharArray(), 26, str.length())
-        assert l1 == 12345678910L
-
-        String str2 = "abcdefghijklmnopqrstuvwxyz12345678910mymilkshakemakestheboysintheyard"
-        l1 = CharScanner.parseLongFromTo(str2.toCharArray(), 26, str.length())
-        assert l1 == 12345678910L
-    }
-
-    void testParseIntFromTo() {
-        String str = "123456789"
-        int i = CharScanner.parseIntFromTo(str.toCharArray(), 0, str.length())
-        assert i == 123456789
-
-        str = "abc-123456789"
-        i = CharScanner.parseIntFromTo(str.toCharArray(), 3, str.length())
-        assert i == -123456789
-
-        str = "abcdefghijklmnopqrstuvwxyz56789"
-        i = CharScanner.parseIntFromTo(str.toCharArray(), 26, str.length())
-        assert i == 56789
-
-        str = "abcdefghijklmnopqrstuvwxyz-6789mymilkshakemakestheboysintheyard"
-        i = CharScanner.parseIntFromTo(str.toCharArray(), 26, 31)
-        assert i == -6789
-    }
-
-    void testParseJsonNumberToDecimal() {
-        def num = CharScanner.parseJsonNumber('123.40'.toCharArray())
-        assert num instanceof BigDecimal
-        assert num == 123.40G
-        assert num.scale() == 2
-
-        num = CharScanner.parseJsonNumber('-123.400'.toCharArray())
-        assert num instanceof BigDecimal
-        assert num == -123.400G
-        assert num.scale() == 3
-
-        num = CharScanner.parseJsonNumber('3.7e-5'.toCharArray())
-        assert num instanceof BigDecimal
-        assert num == 0.000037G
-        assert num.scale() == 6
-
-        num = CharScanner.parseJsonNumber('-1.25E+7'.toCharArray())
-        assert num instanceof BigDecimal
-        assert num == -12500000.0G
-        assert num.scale() == -5
-    }
-
-    protected assertArrayEquals(char[] expected, char[] actual) {
-        assertArrayEquals((Object[]) expected, (Object[]) actual)
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy
deleted file mode 100644
index b790760..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal
-
-import static groovy.json.internal.Chr.*
-
-class ChrTest extends GroovyTestCase {
-
-    void testLpad() {
-        def results = lpad('abc'.toCharArray(), 5, '#' as char)
-
-        assertArrayEquals(
-                '##abc'.toCharArray(),
-                results
-        )
-    }
-
-    void testIsIn() {
-        def letters = 'abcd'.toCharArray()
-
-        assertTrue Chr.in('a' as char, letters)
-        assertFalse Chr.in('z' as char, letters)
-    }
-
-    void testIsInAtOffset() {
-        def letters = 'abcd'.toCharArray()
-
-        assertFalse Chr.in('a' as char, 1, letters)
-        assertTrue Chr.in('c' as char, 1, letters)
-    }
-
-    void testIsInAtRange() {
-        def letters = 'abcd'.toCharArray()
-
-        assertFalse Chr.in('a' as char, 1, 2, letters)
-        assertTrue Chr.in('c' as char, 1, 3, letters)
-    }
-
-    void testGrow() {
-        def letters = 'abcde'.toCharArray()
-        letters = grow(letters, 21)
-
-        assertEquals(
-                'e',
-                letters[4]
-        )
-
-        assertEquals(
-                'a',
-                letters[0]
-        )
-
-        assertEquals(
-                26,
-                letters.length
-        )
-
-        assertEquals(
-                '\0',
-                letters[20]
-        )
-    }
-
-    void testGrowFast() {
-        def letters = 'abcdef'.toCharArray()
-        letters = grow(letters)
-
-        assertEquals(
-                'e',
-                letters[4]
-        )
-
-        assertEquals(
-                'a',
-                letters[0]
-        )
-
-        assertEquals(
-                12,
-                letters.length
-        )
-
-        assertEquals(
-                letters[9],
-                '\0'
-        )
-    }
-
-    void testCopy() {
-        def chars = 'abcde'.toCharArray()
-
-        assertArrayEquals(
-                chars,
-                copy(chars)
-        )
-    }
-
-    void testByteCopyIntoCharArray() {
-        def charArray = new char[1000]
-        def bytes = "0123456789000".bytes
-
-        Chr._idx(charArray, 0, bytes)
-
-        char ch = charArray[0]
-        assert ch == '0'
-
-        ch = charArray[9]
-        assert ch == '9'
-
-        Chr._idx(charArray, 100, bytes, 0, 3)
-
-        ch = charArray[100]
-        assert ch == '0'
-
-        ch = charArray[101]
-        assert ch == '1'
-
-        ch = charArray[102]
-        assert ch == '2'
-
-        Chr._idx(charArray, 200, bytes, 3, 6)
-
-        ch = charArray[200]
-        assert ch == '3' || die(" not '3' " + ch)
-
-        ch = charArray[201]
-        assert ch == '4' || die(" not '4' " + ch)
-
-        ch = charArray[202]
-        assert ch == '5' || die(" not '5' " + ch)
-    }
-
-    protected assertArrayEquals(char[] expected, char[] actual) {
-        assertArrayEquals((Object[]) expected, (Object[]) actual)
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/DatesTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/DatesTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/DatesTest.groovy
deleted file mode 100644
index abc31c0..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/DatesTest.groovy
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal
-
-
-class DatesTest extends GroovyTestCase{
-
-    // GROOVY-7462
-    void testDatesFactory() {
-        Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
-
-        Thread.sleep(1) // lets get some time between calling constructors
-
-        Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
-
-        assert d1 == d2
-    }
-
-    void testDatesFactoryWithDefaultMs() {
-        Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59,0)
-        Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
-
-        assert d1 == d2
-    }
-
-    void testDatesFactoryEnforceDefaultMs() {
-        Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59,1)
-        Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
-
-        assert d1 != d2
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsTest.groovy
deleted file mode 100644
index 1c31673..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsTest.groovy
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal
-
-class FastStringUtilsTest extends GroovyTestCase {
-
-    void testToCharArray() {
-        synchronized (FastStringUtils) {
-            def str = "some test"
-            // FastStringUtils accesses the underlying char array directly
-            if (str.value instanceof char[]) {
-                assert FastStringUtils.toCharArray(str).is(str.value) : FastStringUtils.STRING_IMPLEMENTATION.toString()
-            } else if (str.value instanceof byte[]) {
-                // jdk9
-                assert FastStringUtils.toCharArray(str) == str.toCharArray()
-            } else {
-                fail('unexpected type encountered for String value field')
-            }
-        }
-    }
-
-    void testToCharArrayWithStringBuilder() {
-        synchronized (FastStringUtils) {
-            def str = new StringBuilder().append("some test")
-            // StringBuilder#toString() returns a new String object
-            assert FastStringUtils.toCharArray(str) == "some test".toCharArray()
-        }
-    }
-
-    void testNoCopyStringFromChars() {
-        synchronized (FastStringUtils) {
-            def source = "äöüliu"
-            def chars = source.toCharArray()
-
-            assert FastStringUtils.noCopyStringFromChars(chars) == source
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy
deleted file mode 100644
index 6e3e5f4..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal
-
-class FastStringUtilsUnsafeDisabledTest extends GroovyTestCase {
-
-    FastStringUtils.StringImplementation oldStringImplementation
-
-    void setUp() {
-        // to disable Unsafe usage, we set the StringImplementation to the very safe UNKNOWN
-
-        oldStringImplementation = FastStringUtils.STRING_IMPLEMENTATION
-        FastStringUtils.STRING_IMPLEMENTATION = FastStringUtils.StringImplementation.UNKNOWN
-    }
-
-    @Override
-    void tearDown() {
-        FastStringUtils.STRING_IMPLEMENTATION = oldStringImplementation
-    }
-
-    void testToCharArray() {
-        synchronized (FastStringUtils) {
-            def str = "some test"
-            assert !FastStringUtils.toCharArray(str).is(str.value)
-        }
-    }
-
-    void testToCharArrayWithStringBuilder() {
-        synchronized (FastStringUtils) {
-            def str = new StringBuilder().append("some test")
-            // StringBuilder#toString() returns a new String object
-            assert FastStringUtils.toCharArray(str) == "some test".toCharArray()
-        }
-    }
-
-    void testNoCopyStringFromChars() {
-        synchronized (FastStringUtils) {
-            def source = "äöüliu"
-            def chars = source.toCharArray()
-
-            assert FastStringUtils.noCopyStringFromChars(chars) == source
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/LazyMapTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/LazyMapTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/LazyMapTest.groovy
deleted file mode 100644
index 99c0751..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/LazyMapTest.groovy
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal
-
-class LazyMapTest extends GroovyTestCase {
-
-    // GROOVY-7302
-    void testSizeWhenNoBackingMapCreated() {
-        def map = new LazyMap()
-        map.someProperty = "1"
-        map.someProperty = "2"
-        map.someProperty = "3"
-        assert map.size() == 1
-        map.someProperty2 = "4"
-        assert map.size() == 2
-    }
-
-    void testSizeWhenLazyCreated() {
-        def map = new LazyMap()
-        map.someProperty1 = '1'
-        assert map.@map == null
-        map.someProperty2 = '2'
-        assert map.@map == null
-        map.someProperty3 = '3'
-        assert map.@map == null
-        map.someProperty4 = '4'
-        assert map.@map == null
-        map.someProperty5 = '5'
-        assert map.@map == null
-        map.someProperty6 = '6'
-        assert map.@map == null
-        map.someProperty7 = '7'
-        assert map.someProperty6 == '6'
-        assert map.@map?.size() == 7
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ReaderCharacterSourceTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ReaderCharacterSourceTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ReaderCharacterSourceTest.groovy
deleted file mode 100644
index 6f79081..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ReaderCharacterSourceTest.groovy
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal
-
-import groovy.json.internal.Exceptions.JsonInternalException;
-
-class ReaderCharacterSourceTest extends GroovyTestCase {
-
-    public static final int QUOTE_CHAR = (int)'"'.charAt(0)
-    public static final int BACKSLASH_CHAR = (int)'\\'.charAt(0)
-
-    void testFindNextChar() {
-        def testCases = [
-                [ input: '""', expected: '' ],
-                [ input: '"word"', expected: 'word' ],
-                [ input: '"\\u0026value"', expected: '\\u0026value' ],
-                [ input: '"value\\u0026"', expected: 'value\\u0026' ],
-                [ input: '"double\\"quote"', expected: 'double\\"quote' ],
-                [ input: '"\\"\\"\\"\\""', expected: '\\"\\"\\"\\"' ],
-                [ input: '"\\\\\\\\\\\\"', expected: '\\\\\\\\\\\\' ]
-        ]
-
-        testCases.each {
-            boolean containsEscape = it.input.contains('\\')
-            // Test all possible buffer sizes
-            for (int i = 1; i < it.input.length() + 1; i++) {
-                ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader(it.input), i)
-                rcs.nextChar() // Read the first double quote as if JSON parsing
-
-                String result = new String(rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR))
-
-                assertEquals("Buffer size ${i}", it.expected, result)
-                assertEquals("Expected escape character in ${it.input}, buffer size ${i}", containsEscape, rcs.hadEscape())
-            }
-        }
-    }
-
-    void testFindNextCharException() {
-        shouldFail(JsonInternalException) {
-            ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote'))
-            rcs.nextChar() // Read the first double quote as if JSON parsing
-            rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
-        }
-    }
-
-    void testFindNextCharExceptionWithEscapedEnding() {
-        shouldFail(JsonInternalException) {
-            ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote ending with escape \\'))
-            rcs.nextChar() // Read the first double quote as if JSON parsing
-            rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
-        }
-    }
-
-    void testFindNextCharExceptionWithEscapedQuote() {
-        shouldFail(JsonInternalException) {
-            ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote with escaped quote \\"'))
-            rcs.nextChar() // Read the first double quote as if JSON parsing
-            rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/DefaultFastStringServiceTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/DefaultFastStringServiceTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/DefaultFastStringServiceTest.groovy
new file mode 100644
index 0000000..c79ac34
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/DefaultFastStringServiceTest.groovy
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json
+
+class DefaultFastStringServiceTest extends GroovyTestCase {
+
+    FastStringService service = new DefaultFastStringServiceFactory().service
+
+    void testToCharArray() {
+        def str = "some test"
+        assert service.toCharArray(str) == str.toCharArray()
+    }
+
+    void testNoCopyStringFromChars() {
+        def source = "äöüliu"
+        def chars = source.toCharArray()
+        assert service.noCopyStringFromChars(chars) == source
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ArrayUtilsTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ArrayUtilsTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ArrayUtilsTest.groovy
new file mode 100644
index 0000000..d6bea5c
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ArrayUtilsTest.groovy
@@ -0,0 +1,27 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal
+
+class ArrayUtilsTest extends GroovyTestCase {
+
+    void testCopyRange() {
+        char[] chars = "t"
+        assert ArrayUtils.copyRange(chars, 0, 1) == ((char[]) "t")
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/CharScannerTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/CharScannerTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/CharScannerTest.groovy
new file mode 100644
index 0000000..5e3f49a
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/CharScannerTest.groovy
@@ -0,0 +1,288 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal
+
+class CharScannerTest extends GroovyTestCase {
+
+    void testParseInt() {
+        int i = CharScanner.parseInt("-22".toCharArray())
+        assert i == -22
+
+        i = CharScanner.parseInt("22".toCharArray())
+        assert i == 22
+    }
+
+    void testParseLongTest() {
+        long value = CharScanner.parseLong("-22".toCharArray())
+        assert value == -22L
+
+        value = CharScanner.parseInt("22".toCharArray())
+        assert value == 22
+    }
+
+    void testParseLongTest2() {
+        String test = "" + ((long) (Long.MAX_VALUE / 2L))
+        long value = CharScanner.parseLong(test.toCharArray())
+        assert value == Long.parseLong(test)
+    }
+
+    void testParseLongTest3() {
+        String test = "" + (Long.MIN_VALUE / 2L)
+        long value = CharScanner.parseLong(test.toCharArray())
+        assert value == Long.parseLong(test)
+    }
+
+    void testParseLongTest4() {
+        String test = "" + (Long.MAX_VALUE)
+        long value = CharScanner.parseLong(test.toCharArray())
+        assert value == Long.parseLong(test)
+    }
+
+    void testParseLongTest5() {
+        String test = "" + (Long.MIN_VALUE)
+        long value = CharScanner.parseLong(test.toCharArray())
+        assert value == Long.parseLong(test)
+    }
+
+    void testParseIntMax() {
+        int i = 0
+        i = CharScanner.parseInt(("" + Integer.MAX_VALUE).toCharArray())
+        assert i == Integer.MAX_VALUE
+    }
+
+    void testParseIntMin() {
+        int i = 0
+        i = CharScanner.parseInt(("" + Integer.MIN_VALUE).toCharArray())
+        assert i == Integer.MIN_VALUE
+    }
+
+    void testParseLongMax() {
+        long l = 0
+        l = CharScanner.parseLong(("" + Long.MAX_VALUE).toCharArray())
+        assert l == Long.MAX_VALUE
+    }
+
+    void testParseLongMin() {
+        long l = 0
+        l = CharScanner.parseLong(("" + Long.MIN_VALUE).toCharArray())
+        assert l == Long.MIN_VALUE || die("l", l, "MIN", Long.MIN_VALUE)
+    }
+
+    void testParseDouble() {
+        String str = "123456789"
+        double num =
+            CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length()).doubleValue()
+        assert num == 123456789d
+    }
+
+    void testParseDoubleNegative() {
+        String str = "-1.23456789E8"
+        double num =
+            (Double) CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length())
+        assert num == -1.23456789E8
+    }
+
+    void testParseDoubleNegativeNoE() {
+        String str = "-123456789"
+        testDouble(str)
+    }
+
+    void testParseDoubleNegativeNoE2() {
+        String str = "-1234567890"
+        testDouble(str)
+    }
+
+    void testParseDoubleMax() {
+        String str = "" + Double.MAX_VALUE
+        testDouble(str)
+    }
+
+    void testParseDoubleMin() {
+        String str = "" + Double.MIN_VALUE
+        testDouble(str)
+    }
+
+    void testManyDoubles() {
+        List<String> doubles = ["" + 1.01d, "" + 123456789.234D, "" + 55D,
+                "" + Integer.MAX_VALUE + "." + Integer.MAX_VALUE,
+                "66666666.666", "-6666666666.6666", "1E10"]
+
+        for (String str : doubles) {
+            testDouble(str)
+        }
+    }
+
+    private void testDouble(String str) {
+        double num = CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length()).doubleValue()
+        assert num == Double.parseDouble(str)
+    }
+
+    private void testDoubleInStringThreeOver(String str) {
+        double numTest = Double.parseDouble(str)
+        double num = CharScanner.parseJsonNumber(("   " + str).toCharArray(), 3, str.length() + 3).doubleValue()
+        assert num == numTest
+    }
+
+    void testParseIntIgnore0() {
+        int i = CharScanner.parseIntFromToIgnoreDot("1.1".toCharArray(), 0, "1.1".length())
+        assert i == 11
+    }
+
+    void testSimpleDoubleInString() {
+        testDoubleInStringThreeOver("1.1")
+    }
+
+    void testLongMaxWithOffset() {
+        testDoubleInStringThreeOver("" + Long.MAX_VALUE)
+    }
+
+    void testLargeDecimal() {
+        testDoubleInStringThreeOver("" + Integer.MAX_VALUE + "." + Integer.MAX_VALUE)
+    }
+
+    void testLargeDecimal2() {
+        testDoubleInStringThreeOver("1000" + "." + "10001")
+    }
+
+    void testLargeDecimal3() {
+        testDoubleInStringThreeOver("10000" + "." + "100001")
+    }
+
+    void testLargeDecimal4() {
+        testDoubleInStringThreeOver("" + 10_000_000 + "." + 10_000_001)
+    }
+
+    void testLargeDecimal5() {
+        testDoubleInStringThreeOver("" + 100_000_000 + "." + 100_000_001)
+    }
+
+    void testLargeDecimal6() {
+        testDoubleInStringThreeOver("" + 100_000_000 + "." + 1_000_000_001)
+    }
+
+    void testLargeDecimal7() {
+        testDoubleInStringThreeOver("" + 100_000_000 + "." + 1_000_000_001L)
+    }
+
+    void testLargeDecimal8() {
+        testDoubleInStringThreeOver("" + 1_000_000_000_000L + "." + 1_000_000_001L)
+    }
+
+    void testLargeDecimal9() {
+        testDoubleInStringThreeOver("" + 10_000_000_000_000L + "." + 1_000_000_001L)
+    }
+
+    void testLargeDecimal10() {
+        testDoubleInStringThreeOver("" + 100_000_000_000_000_000L + "." + 1_000_000_001L)
+    }
+
+    void testLargeDecimal11() {
+        testDoubleInStringThreeOver("" + 1_000_000_000_000_000_000L + "." + 1_000_000_001L)
+    }
+
+    void testLongMinWithOffset() {
+        testDoubleInStringThreeOver("" + Long.MIN_VALUE)
+    }
+
+    void testDoubleMaxWithOffset() {
+        testDoubleInStringThreeOver("" + Double.MAX_VALUE)
+    }
+
+    void testDoubleMinWithOffset() {
+        testDoubleInStringThreeOver("" + Double.MIN_VALUE)
+    }
+
+    void testDoubleMaxWithOffset2() {
+        testDoubleInStringThreeOver("" + Double.MAX_VALUE / 2)
+    }
+
+    void testDoubleMinWithOffset2() {
+        testDoubleInStringThreeOver("" + Double.MIN_VALUE / 2)
+    }
+
+    void testDoubleMaxWithOffset3() {
+        testDoubleInStringThreeOver("" + (Double.MAX_VALUE / 9) * 8)
+    }
+
+    void testDoubleMinWithOffset3() {
+        testDoubleInStringThreeOver("" + (Double.MIN_VALUE / 9) * 8)
+    }
+
+    void testParseLong() {
+        String str = "12345678910"
+        long l1 = CharScanner.parseLongFromTo(str.toCharArray(), 0, str.length())
+        assert l1 == 12345678910L
+
+        str = "abc12345678910"
+        l1 = CharScanner.parseLongFromTo(str.toCharArray(), 3, str.length())
+        assert l1 == 12345678910L
+
+        str = "abcdefghijklmnopqrstuvwxyz12345678910"
+        l1 = CharScanner.parseLongFromTo(str.toCharArray(), 26, str.length())
+        assert l1 == 12345678910L
+
+        String str2 = "abcdefghijklmnopqrstuvwxyz12345678910mymilkshakemakestheboysintheyard"
+        l1 = CharScanner.parseLongFromTo(str2.toCharArray(), 26, str.length())
+        assert l1 == 12345678910L
+    }
+
+    void testParseIntFromTo() {
+        String str = "123456789"
+        int i = CharScanner.parseIntFromTo(str.toCharArray(), 0, str.length())
+        assert i == 123456789
+
+        str = "abc-123456789"
+        i = CharScanner.parseIntFromTo(str.toCharArray(), 3, str.length())
+        assert i == -123456789
+
+        str = "abcdefghijklmnopqrstuvwxyz56789"
+        i = CharScanner.parseIntFromTo(str.toCharArray(), 26, str.length())
+        assert i == 56789
+
+        str = "abcdefghijklmnopqrstuvwxyz-6789mymilkshakemakestheboysintheyard"
+        i = CharScanner.parseIntFromTo(str.toCharArray(), 26, 31)
+        assert i == -6789
+    }
+
+    void testParseJsonNumberToDecimal() {
+        def num = CharScanner.parseJsonNumber('123.40'.toCharArray())
+        assert num instanceof BigDecimal
+        assert num == 123.40G
+        assert num.scale() == 2
+
+        num = CharScanner.parseJsonNumber('-123.400'.toCharArray())
+        assert num instanceof BigDecimal
+        assert num == -123.400G
+        assert num.scale() == 3
+
+        num = CharScanner.parseJsonNumber('3.7e-5'.toCharArray())
+        assert num instanceof BigDecimal
+        assert num == 0.000037G
+        assert num.scale() == 6
+
+        num = CharScanner.parseJsonNumber('-1.25E+7'.toCharArray())
+        assert num instanceof BigDecimal
+        assert num == -12500000.0G
+        assert num.scale() == -5
+    }
+
+    protected assertArrayEquals(char[] expected, char[] actual) {
+        assertArrayEquals((Object[]) expected, (Object[]) actual)
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ChrTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ChrTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ChrTest.groovy
new file mode 100644
index 0000000..bcdac93
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ChrTest.groovy
@@ -0,0 +1,152 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal
+
+import static org.apache.groovy.json.internal.Chr.*
+
+class ChrTest extends GroovyTestCase {
+
+    void testLpad() {
+        def results = lpad('abc'.toCharArray(), 5, '#' as char)
+
+        assertArrayEquals(
+                '##abc'.toCharArray(),
+                results
+        )
+    }
+
+    void testIsIn() {
+        def letters = 'abcd'.toCharArray()
+
+        assertTrue Chr.in('a' as char, letters)
+        assertFalse Chr.in('z' as char, letters)
+    }
+
+    void testIsInAtOffset() {
+        def letters = 'abcd'.toCharArray()
+
+        assertFalse Chr.in('a' as char, 1, letters)
+        assertTrue Chr.in('c' as char, 1, letters)
+    }
+
+    void testIsInAtRange() {
+        def letters = 'abcd'.toCharArray()
+
+        assertFalse Chr.in('a' as char, 1, 2, letters)
+        assertTrue Chr.in('c' as char, 1, 3, letters)
+    }
+
+    void testGrow() {
+        def letters = 'abcde'.toCharArray()
+        letters = grow(letters, 21)
+
+        assertEquals(
+                'e',
+                letters[4]
+        )
+
+        assertEquals(
+                'a',
+                letters[0]
+        )
+
+        assertEquals(
+                26,
+                letters.length
+        )
+
+        assertEquals(
+                '\0',
+                letters[20]
+        )
+    }
+
+    void testGrowFast() {
+        def letters = 'abcdef'.toCharArray()
+        letters = grow(letters)
+
+        assertEquals(
+                'e',
+                letters[4]
+        )
+
+        assertEquals(
+                'a',
+                letters[0]
+        )
+
+        assertEquals(
+                12,
+                letters.length
+        )
+
+        assertEquals(
+                letters[9],
+                '\0'
+        )
+    }
+
+    void testCopy() {
+        def chars = 'abcde'.toCharArray()
+
+        assertArrayEquals(
+                chars,
+                copy(chars)
+        )
+    }
+
+    void testByteCopyIntoCharArray() {
+        def charArray = new char[1000]
+        def bytes = "0123456789000".bytes
+
+        Chr._idx(charArray, 0, bytes)
+
+        char ch = charArray[0]
+        assert ch == '0'
+
+        ch = charArray[9]
+        assert ch == '9'
+
+        Chr._idx(charArray, 100, bytes, 0, 3)
+
+        ch = charArray[100]
+        assert ch == '0'
+
+        ch = charArray[101]
+        assert ch == '1'
+
+        ch = charArray[102]
+        assert ch == '2'
+
+        Chr._idx(charArray, 200, bytes, 3, 6)
+
+        ch = charArray[200]
+        assert ch == '3' || die(" not '3' " + ch)
+
+        ch = charArray[201]
+        assert ch == '4' || die(" not '4' " + ch)
+
+        ch = charArray[202]
+        assert ch == '5' || die(" not '5' " + ch)
+    }
+
+    protected assertArrayEquals(char[] expected, char[] actual) {
+        assertArrayEquals((Object[]) expected, (Object[]) actual)
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/DatesTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/DatesTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/DatesTest.groovy
new file mode 100644
index 0000000..f130362
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/DatesTest.groovy
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal
+
+class DatesTest extends GroovyTestCase{
+
+    // GROOVY-7462
+    void testDatesFactory() {
+        Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
+
+        Thread.sleep(1) // lets get some time between calling constructors
+
+        Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
+
+        assert d1 == d2
+    }
+
+    void testDatesFactoryWithDefaultMs() {
+        Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59,0)
+        Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
+
+        assert d1 == d2
+    }
+
+    void testDatesFactoryEnforceDefaultMs() {
+        Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59,1)
+        Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
+
+        assert d1 != d2
+    }
+}


[6/7] groovy git commit: GROOVY-8379: Rework groovy-json FastStringUtils (closes #667)

Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/CharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharacterSource.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharacterSource.java
deleted file mode 100644
index 871cf13..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharacterSource.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Richard Hightower
- */
-public interface CharacterSource {
-
-    /**
-     * Skip white space.
-     */
-    void skipWhiteSpace();
-
-    /**
-     * returns the next character moving the file pointer or index to the next location.
-     */
-    int nextChar();
-
-    /**
-     * returns the current character without changing the IO pointer or index.
-     */
-    int currentChar();
-
-    /**
-     * Checks to see if there is a next character.
-     */
-    boolean hasChar();
-
-    /**
-     * Useful for finding constants in a string like true, false, etc.
-     */
-    boolean consumeIfMatch(char[] match);
-
-    /**
-     * This is mostly for debugging and testing.
-     */
-    int location();
-
-    /**
-     * Combines the operations of nextChar and hasChar.
-     * Characters is -1 if not found which signifies end of file.
-     * This might be preferable to avoid two method calls.
-     */
-    int safeNextChar();
-
-    /**
-     * Used to find strings and their ilk
-     * Finds the next non-escaped char
-     *
-     * @param ch  character to find
-     * @param esc escape character to avoid next char if escaped
-     * @return list of chars until this is found.
-     */
-    char[] findNextChar(int ch, int esc);
-
-    boolean hadEscape();
-
-    /**
-     * Reads a number from the character source.
-     */
-    char[] readNumber();
-
-    String errorDetails(String message);
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java
deleted file mode 100644
index a5146b0..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Rick Hightower
- */
-public class Chr {
-
-    public static char[] array(final char... array) {
-        return array;
-    }
-
-    public static char[] chars(final String array) {
-        return array.toCharArray();
-    }
-
-    public static boolean in(char value, char[] array) {
-        for (char currentValue : array) {
-            if (currentValue == value) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static boolean in(int value, char[] array) {
-        for (int currentValue : array) {
-            if (currentValue == value) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static boolean in(char value, int offset, char[] array) {
-        for (int index = offset; index < array.length; index++) {
-            char currentValue = array[index];
-            if (currentValue == value) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static boolean in(char value, int offset, int end, char[] array) {
-        for (int index = offset; index < end; index++) {
-            char currentValue = array[index];
-            if (currentValue == value) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static char[] grow(char[] array, final int size) {
-        char[] newArray = new char[array.length + size];
-        arraycopy(array, 0, newArray, 0, array.length);
-        return newArray;
-    }
-
-    public static char[] grow(char[] array) {
-        char[] newArray = new char[array.length * 2];
-        arraycopy(array, 0, newArray, 0, array.length);
-        return newArray;
-    }
-
-    public static char[] copy(char[] array) {
-        char[] newArray = new char[array.length];
-        arraycopy(array, 0, newArray, 0, array.length);
-        return newArray;
-    }
-
-    public static char[] copy(char[] array, int offset, int length) {
-        char[] newArray = new char[length];
-        arraycopy(array, offset, newArray, 0, length);
-        return newArray;
-    }
-
-    public static char[] add(char[] array, char v) {
-        char[] newArray = new char[array.length + 1];
-        arraycopy(array, 0, newArray, 0, array.length);
-        newArray[array.length] = v;
-        return newArray;
-    }
-
-    public static char[] add(char[] array, String str) {
-        return add(array, str.toCharArray());
-    }
-
-    public static char[] add(char[] array, StringBuilder stringBuilder) {
-        return add(array, getCharsFromStringBuilder(stringBuilder));
-    }
-
-    public static char[] add(char[] array, char[] array2) {
-        char[] newArray = new char[array.length + array2.length];
-        arraycopy(array, 0, newArray, 0, array.length);
-        arraycopy(array2, 0, newArray, array.length, array2.length);
-        return newArray;
-    }
-
-    /* End universal methods. */
-
-    private static char[] getCharsFromStringBuilder(StringBuilder sbuf) {
-        final int length = sbuf.length();
-        char[] array2 = new char[length];
-        sbuf.getChars(0, length, array2, 0);
-        return array2;
-    }
-
-    public static char[] lpad(final char[] in, final int size, char pad) {
-        if (in.length >= size) {
-            return in;
-        }
-
-        int delta = size - in.length;
-        int index = 0;
-        char[] newArray = new char[size];
-
-        for (; index < delta; index++) {
-            newArray[index] = pad;
-        }
-
-        for (int index2 = 0; index2 < in.length; index++, index2++) {
-            newArray[index] = in[index2];
-        }
-
-        return newArray;
-    }
-
-    public static boolean contains(char[] chars, char c, int start, final int length) {
-        final int to = length + start;
-        for (int index = start; index < to; index++) {
-            char ch = chars[index];
-            if (ch == c) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static void _idx(char[] buffer, int location, byte[] chars) {
-        int index2 = 0;
-        int endLocation = (location + chars.length);
-        for (int index = location; index < endLocation; index++, index2++) {
-            buffer[index] = (char) chars[index2];
-        }
-    }
-
-    public static void _idx(final char[] array, int startIndex, char[] input) {
-        try {
-            arraycopy(input, 0, array, startIndex, input.length);
-        } catch (Exception ex) {
-            Exceptions.handle(String.format("array size %d, startIndex %d, input length %d",
-                    array.length, startIndex, input.length), ex);
-        }
-    }
-
-    private static void arraycopy(final char[] src, final int srcPos, final char[] dest, final int destPos, final int length) {
-        System.arraycopy(src, srcPos, dest, destPos, length);
-    }
-
-    public static void _idx(final char[] array, int startIndex, char[] input, final int inputLength) {
-        try {
-            arraycopy(input, 0, array, startIndex, inputLength);
-        } catch (Exception ex) {
-            Exceptions.handle(String.format("array size %d, startIndex %d, input length %d",
-                    array.length, startIndex, input.length), ex);
-        }
-    }
-
-    public static void _idx(char[] buffer, int location, byte[] chars, int start, int end) {
-        int index2 = start;
-        int endLocation = (location + (end - start));
-        for (int index = location; index < endLocation; index++, index2++) {
-            buffer[index] = (char) chars[index2];
-        }
-    }
-
-    public static char[] add(char[]... strings) {
-        int length = 0;
-        for (char[] str : strings) {
-            if (str == null) {
-                continue;
-            }
-            length += str.length;
-        }
-        CharBuf builder = CharBuf.createExact(length);
-        for (char[] str : strings) {
-            if (str == null) {
-                continue;
-            }
-            builder.add(str);
-        }
-        return builder.toCharArray();
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java
deleted file mode 100644
index 5a07c6b..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.util.Calendar;
-import java.util.Date;
-import java.util.TimeZone;
-
-/**
- * @author Rick Hightower
- */
-public class Dates {
-
-    private static TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("UTC");
-
-    public static long utc(long time) {
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTimeInMillis(time);
-        calendar.setTimeZone(UTC_TIME_ZONE);
-        return calendar.getTime().getTime();
-    }
-
-    private static Date internalDate(TimeZone tz, int year, int month, int day, int hour,
-                                     int minute, int second, int miliseconds) {
-
-        Calendar calendar = Calendar.getInstance();
-
-        calendar.set(Calendar.YEAR, year);
-        calendar.set(Calendar.MONTH, month - 1);
-        calendar.set(Calendar.DAY_OF_MONTH, day);
-        calendar.set(Calendar.HOUR_OF_DAY, hour);
-        calendar.set(Calendar.MINUTE, minute);
-        calendar.set(Calendar.SECOND, second);
-        calendar.set(Calendar.MILLISECOND, miliseconds);
-
-        calendar.setTimeZone(tz);
-
-        return calendar.getTime();
-    }
-
-    public static Date toDate(TimeZone tz, int year, int month, int day,
-                              int hour, int minute, int second) {
-        return internalDate(tz, year, month, day, hour, minute, second, 0);
-    }
-
-    public static Date toDate(TimeZone tz, int year, int month, int day,
-                              int hour, int minute, int second, int miliseconds) {
-        return internalDate(tz, year, month, day, hour, minute, second, miliseconds);
-    }
-
-    static final int SHORT_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30Z".length();
-    static final int LONG_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30-05:00".length();
-    public static final int JSON_TIME_LENGTH = "2013-12-14T01:55:33.412Z".length();
-
-    public static Date fromISO8601(char[] charArray, int from, int to) {
-        try {
-            if (isISO8601(charArray, from, to)) {
-                int year = CharScanner.parseIntFromTo(charArray, from, from + 4);
-                int month = CharScanner.parseIntFromTo(charArray, from + 5, from + 7);
-                int day = CharScanner.parseIntFromTo(charArray, from + 8, from + 10);
-                int hour = CharScanner.parseIntFromTo(charArray, from + 11, from + 13);
-
-                int minute = CharScanner.parseIntFromTo(charArray, from + 14, from + 16);
-
-                int second = CharScanner.parseIntFromTo(charArray, from + 17, from + 19);
-                TimeZone tz = null;
-
-                if (charArray[from + 19] == 'Z') {
-                    tz = TimeZone.getTimeZone("GMT");
-                } else {
-                    String tzStr = "GMT" + String.valueOf(charArray, from + 19, 6);
-                    tz = TimeZone.getTimeZone(tzStr);
-                }
-                return toDate(tz, year, month, day, hour, minute, second);
-            } else {
-                return null;
-            }
-        } catch (Exception ex) {
-            return null;
-        }
-    }
-
-    public static Date fromJsonDate(char[] charArray, int from, int to) {
-        try {
-            if (isJsonDate(charArray, from, to)) {
-                int year = CharScanner.parseIntFromTo(charArray, from, from + 4);
-                int month = CharScanner.parseIntFromTo(charArray, from + 5, from + 7);
-                int day = CharScanner.parseIntFromTo(charArray, from + 8, from + 10);
-                int hour = CharScanner.parseIntFromTo(charArray, from + 11, from + 13);
-
-                int minute = CharScanner.parseIntFromTo(charArray, from + 14, from + 16);
-
-                int second = CharScanner.parseIntFromTo(charArray, from + 17, from + 19);
-
-                int miliseconds = CharScanner.parseIntFromTo(charArray, from + 20, from + 23);
-
-                TimeZone tz = TimeZone.getTimeZone("GMT");
-
-                return toDate(tz, year, month, day, hour, minute, second, miliseconds);
-            } else {
-                return null;
-            }
-        } catch (Exception ex) {
-            return null;
-        }
-    }
-
-    public static boolean isISO8601(char[] charArray, int start, int to) {
-        boolean valid = true;
-        final int length = to - start;
-
-        if (length == SHORT_ISO_8601_TIME_LENGTH) {
-            valid &= (charArray[start + 19] == 'Z');
-        } else if (length == LONG_ISO_8601_TIME_LENGTH) {
-            valid &= (charArray[start + 19] == '-' || charArray[start + 19] == '+');
-            valid &= (charArray[start + 22] == ':');
-        } else {
-            return false;
-        }
-
-        //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
-        // "1 9 9 4 - 1 1 - 0 5 T 0 8 : 1 5 : 3 0 - 0 5 : 0 0
-
-        valid &= (charArray[start + 4] == '-') &&
-                (charArray[start + 7] == '-') &&
-                (charArray[start + 10] == 'T') &&
-                (charArray[start + 13] == ':') &&
-                (charArray[start + 16] == ':');
-
-        return valid;
-    }
-
-    public static boolean isISO8601QuickCheck(char[] charArray, int start, int to) {
-        final int length = to - start;
-
-        try {
-            return length == JSON_TIME_LENGTH || length == LONG_ISO_8601_TIME_LENGTH
-                    || length == SHORT_ISO_8601_TIME_LENGTH || (length >= 17 && (charArray[start + 16] == ':'));
-
-        } catch (Exception ex) {
-            ex.printStackTrace();
-            return false;
-        }
-    }
-
-    public static boolean isJsonDate(char[] charArray, int start, int to) {
-        boolean valid = true;
-        final int length = to - start;
-
-        if (length != JSON_TIME_LENGTH) {
-            return false;
-        }
-
-        valid &= (charArray[start + 19] == '.' || charArray[start + 19] == '+');
-
-        if (!valid) {
-            return false;
-        }
-
-        valid &= (charArray[start + 4] == '-') &&
-                (charArray[start + 7] == '-') &&
-                (charArray[start + 10] == 'T') &&
-                (charArray[start + 13] == ':') &&
-                (charArray[start + 16] == ':');
-
-        return valid;
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java
deleted file mode 100644
index 6617031..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.util.Collections;
-
-/**
- * @author Rick Hightower
- */
-public class Exceptions {
-
-    public static boolean die() {
-        throw new JsonInternalException("died");
-    }
-
-    public static boolean die(String message) {
-        throw new JsonInternalException(message);
-    }
-
-    public static <T> T die(Class<T> clazz, String message) {
-        throw new JsonInternalException(message);
-    }
-
-    public static void handle(java.lang.Exception e) {
-        throw new JsonInternalException(e);
-    }
-
-    public static <T> T handle(Class<T> clazz, java.lang.Exception e) {
-        if (e instanceof JsonInternalException) {
-            throw (JsonInternalException) e;
-        }
-        throw new JsonInternalException(e);
-    }
-
-    public static <T> T handle(Class<T> clazz, String message, Throwable e) {
-        throw new JsonInternalException(message, e);
-    }
-
-    public static void handle(String message, Throwable e) {
-        throw new JsonInternalException(message, e);
-    }
-
-    public static class JsonInternalException extends JsonException {
-
-        public JsonInternalException(String message) {
-            super(message);
-        }
-
-        public JsonInternalException(String message, Throwable cause) {
-            super(message, cause);
-        }
-
-        public JsonInternalException(Throwable cause) {
-            super("Wrapped Exception", cause);
-        }
-
-        public void printStackTrace(PrintStream s) {
-            s.println(this.getMessage());
-            if (getCause() != null) {
-                s.println("This Exception was wrapped, the original exception\n" +
-                        "stack trace is:\n");
-                getCause().printStackTrace(s);
-            } else {
-                super.printStackTrace(s);
-            }
-        }
-
-        public String getMessage() {
-            return super.getMessage() + (getCause() == null ? "" :
-                    getCauseMessage());
-        }
-
-        private String getCauseMessage() {
-            return "\n CAUSE " + getCause().getClass().getName() + " :: " +
-                    getCause().getMessage();
-        }
-
-        public String getLocalizedMessage() {
-            return this.getMessage();
-        }
-
-        public StackTraceElement[] getStackTrace() {
-            if (getCause() != null) {
-                return getCause().getStackTrace();
-            } else {
-                return super.getStackTrace();
-            }
-        }
-
-        public Throwable getCause() {
-            return super.getCause();
-        }
-
-        public void printStackTrace(PrintWriter s) {
-            s.println(this.getMessage());
-
-            if (getCause() != null) {
-                s.println("This Exception was wrapped, the original exception\n" +
-                        "stack trace is:\n");
-                getCause().printStackTrace(s);
-            } else {
-                super.printStackTrace(s);
-            }
-        }
-
-        public void printStackTrace() {
-            System.err.println(this.getMessage());
-
-            if (getCause() != null) {
-                System.err.println("This Exception was wrapped, the original exception\n" +
-                        "stack trace is:\n");
-                getCause().printStackTrace();
-            } else {
-                super.printStackTrace();
-            }
-        }
-    }
-
-    public static String toString(Exception ex) {
-        CharBuf buffer = CharBuf.create(255);
-        buffer.addLine(ex.getLocalizedMessage());
-
-        final StackTraceElement[] stackTrace = ex.getStackTrace();
-        for (StackTraceElement element : stackTrace) {
-            buffer.add(element.getClassName());
-            sputs(buffer, "class", element.getClassName(),
-                    "method", element.getMethodName(), "line", element.getLineNumber());
-        }
-
-        return buffer.toString();
-    }
-
-    public static String sputs(CharBuf buf, Object... messages) {
-        int index = 0;
-        for (Object message : messages) {
-            if (index != 0) {
-                buf.add(' ');
-            }
-            index++;
-
-            if (message == null) {
-                buf.add("<NULL>");
-            } else if (message.getClass().isArray()) {
-                buf.add(Collections.singletonList(message).toString());
-            } else {
-                buf.add(message.toString());
-            }
-        }
-        buf.add('\n');
-
-        return buf.toString();
-    }
-
-    public static String sputs(Object... messages) {
-        CharBuf buf = CharBuf.create(100);
-        return sputs(buf, messages);
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java
deleted file mode 100644
index 9986a1b..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import sun.misc.Unsafe;
-
-import java.lang.reflect.Field;
-
-/**
- * Internal class for fast processing of Strings during JSON parsing
- */
-public class FastStringUtils {
-
-    public static final Unsafe UNSAFE;
-    public static final long STRING_VALUE_FIELD_OFFSET;
-    public static final long STRING_OFFSET_FIELD_OFFSET;
-    public static final long STRING_COUNT_FIELD_OFFSET;
-    public static final boolean ENABLED;
-
-    private static final boolean WRITE_TO_FINAL_FIELDS = Boolean.parseBoolean(System.getProperty("groovy.json.faststringutils.write.to.final.fields", "false"));
-    private static final boolean DISABLE = Boolean.parseBoolean(System.getProperty("groovy.json.faststringutils.disable", "false"));
-
-    private static Unsafe loadUnsafe() {
-        try {
-            Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
-            unsafeField.setAccessible(true);
-            return (Unsafe) unsafeField.get(null);
-
-        } catch (Exception e) {
-            return null;
-        }
-    }
-
-    static {
-        UNSAFE = DISABLE ? null : loadUnsafe();
-        ENABLED = UNSAFE != null;
-    }
-
-    private static long getFieldOffset(String fieldName) {
-        if (ENABLED) {
-            try {
-                return UNSAFE.objectFieldOffset(String.class.getDeclaredField(fieldName));
-            } catch (NoSuchFieldException e) {
-                // field undefined
-            }
-        }
-        return -1L;
-    }
-
-    static {
-        STRING_VALUE_FIELD_OFFSET = getFieldOffset("value");
-        STRING_OFFSET_FIELD_OFFSET = getFieldOffset("offset");
-        STRING_COUNT_FIELD_OFFSET = getFieldOffset("count");
-    }
-
-    protected enum StringImplementation {
-        /**
-         * JDK 7 drops offset and count so there is special handling for later version of JDK 7.
-         */
-        DIRECT_CHARS {
-            @Override
-            public char[] toCharArray(String string) {
-                return (char[]) UNSAFE.getObject(string, STRING_VALUE_FIELD_OFFSET);
-            }
-
-            @Override
-            public String noCopyStringFromChars(char[] chars) {
-                if (WRITE_TO_FINAL_FIELDS) {
-                    String string = new String();
-                    UNSAFE.putObject(string, STRING_VALUE_FIELD_OFFSET, chars);
-                    return string;
-                } else {
-                    return new String(chars);
-                }
-            }
-        },
-        /**
-         * JDK 4 and JDK 5 have offset and count fields.
-         */
-        OFFSET {
-            @Override
-            public char[] toCharArray(String string) {
-                char[] value = (char[]) UNSAFE.getObject(string, STRING_VALUE_FIELD_OFFSET);
-                int offset = UNSAFE.getInt(string, STRING_OFFSET_FIELD_OFFSET);
-                int count = UNSAFE.getInt(string, STRING_COUNT_FIELD_OFFSET);
-                if (offset == 0 && count == value.length) {
-                    // no need to copy
-                    return value;
-                } else {
-                    return string.toCharArray();
-                }
-            }
-
-            @Override
-            public String noCopyStringFromChars(char[] chars) {
-                if (WRITE_TO_FINAL_FIELDS) {
-                    String string = new String();
-                    UNSAFE.putObject(string, STRING_VALUE_FIELD_OFFSET, chars);
-                    UNSAFE.putInt(string, STRING_COUNT_FIELD_OFFSET, chars.length);
-                    return string;
-                } else {
-                    return new String(chars);
-                }
-            }
-        },
-        UNKNOWN {
-            @Override
-            public char[] toCharArray(String string) {
-                return string.toCharArray();
-            }
-
-            @Override
-            public String noCopyStringFromChars(char[] chars) {
-                return new String(chars);
-            }
-        };
-
-        public abstract char[] toCharArray(String string);
-
-        public abstract String noCopyStringFromChars(char[] chars);
-    }
-
-    public static StringImplementation STRING_IMPLEMENTATION = computeStringImplementation();
-
-    private static StringImplementation computeStringImplementation() {
-        if (STRING_VALUE_FIELD_OFFSET != -1L) {
-            if (STRING_OFFSET_FIELD_OFFSET != -1L && STRING_COUNT_FIELD_OFFSET != -1L) {
-                return StringImplementation.OFFSET;
-            } else if (STRING_OFFSET_FIELD_OFFSET == -1L && STRING_COUNT_FIELD_OFFSET == -1L && valueFieldIsCharArray()) {
-                return StringImplementation.DIRECT_CHARS;
-            } else {
-                // JDK 9
-                // TODO: GROOVY-7716 workaround - find way to optimize JDK9 String (or rethink need for Unsafe usage)
-                return StringImplementation.UNKNOWN;
-            }
-        } else {
-            return StringImplementation.UNKNOWN;
-        }
-    }
-
-    /**
-     * JDK9 Compat Strings enhancement changed the internal representation of the value field from a char[]
-     * to a byte[] (see http://openjdk.java.net/jeps/254).
-     *
-     * @return true if internal String value field is a char[], otherwise false
-     */
-    private static boolean valueFieldIsCharArray() {
-        Object o = UNSAFE.getObject("", STRING_VALUE_FIELD_OFFSET);
-        return (o instanceof char[]);
-    }
-
-    /**
-     * @param string string to grab array from.
-     * @return char array from string
-     */
-    public static char[] toCharArray(final String string) {
-        return STRING_IMPLEMENTATION.toCharArray(string);
-    }
-
-    /**
-     * @param charSequence to grab array from.
-     * @return char array from char sequence
-     */
-    public static char[] toCharArray(final CharSequence charSequence) {
-        return toCharArray(charSequence.toString());
-    }
-
-    /**
-     * @param chars to shove array into.
-     * @return new string with chars copied into it
-     */
-    public static String noCopyStringFromChars(final char[] chars) {
-        return STRING_IMPLEMENTATION.noCopyStringFromChars(chars);
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java
deleted file mode 100644
index 4c2847f..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-
-/**
- * @author Rick Hightower
- */
-public class IO {
-
-    private static final int EOF = -1;
-
-    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
-
-    public static CharBuf read(Reader input, CharBuf charBuf, final int bufSize) {
-        if (charBuf == null) {
-            charBuf = CharBuf.create(bufSize);
-        } else {
-            charBuf.readForRecycle();
-        }
-
-        try {
-            char[] buffer = charBuf.toCharArray();
-            int size = input.read(buffer);
-            if (size != -1) {
-                charBuf._len(size);
-            }
-            if (size < 0) {
-                return charBuf;
-            }
-
-            copy(input, charBuf);
-        } catch (IOException e) {
-            Exceptions.handle(e);
-        } finally {
-            try {
-                input.close();
-            } catch (IOException e) {
-                Exceptions.handle(e);
-            }
-        }
-
-        return charBuf;
-    }
-
-    public static int copy(Reader input, Writer output) {
-        long count = copyLarge(input, output);
-        if (count > Integer.MAX_VALUE) {
-            return -1;
-        }
-        return (int) count;
-    }
-
-    public static long copyLarge(Reader reader, Writer writer) {
-        return copyLarge(reader, writer, new char[DEFAULT_BUFFER_SIZE]);
-    }
-
-    public static long copyLarge(Reader reader, Writer writer, char[] buffer) {
-        long count = 0;
-        int n;
-
-        try {
-            while (EOF != (n = reader.read(buffer))) {
-                writer.write(buffer, 0, n);
-                count += n;
-            }
-        } catch (IOException e) {
-            Exceptions.handle(e);
-        }
-        return count;
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
deleted file mode 100644
index a2dfb1e..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This works in index overlay mode or chop mode.
- * Chop mode reduces possibility of memory leak but causes a few more buffer copies as it chops up the buffer.
- *
- * @author Rick Hightower
- */
-public class JsonFastParser extends JsonParserCharArray {
-
-    private final boolean useValues;
-    private final boolean chop;
-    private final boolean lazyChop;
-    private final boolean checkDates;
-
-    public JsonFastParser() {
-        this(true);
-    }
-
-    public JsonFastParser(boolean useValues) {
-        this(useValues, false);
-    }
-
-    public JsonFastParser(boolean useValues, boolean chop) {
-        this(useValues, chop, !chop);
-    }
-
-    public JsonFastParser(boolean useValues, boolean chop, boolean lazyChop) {
-        this(useValues, chop, lazyChop, true);
-    }
-
-    public JsonFastParser(boolean useValues, boolean chop, boolean lazyChop, boolean checkDates) {
-        this.useValues = useValues;
-        this.chop = chop;
-        this.lazyChop = lazyChop;
-        this.checkDates = checkDates;
-    }
-
-    protected final Value decodeJsonObjectLazyFinalParse() {
-        char[] array = charArray;
-
-        if (__currentChar == '{')
-            __index++;
-
-        ValueMap map = useValues ? new ValueMapImpl() : new LazyValueMap(lazyChop);
-        Value value = new ValueContainer(map);
-
-        objectLoop:
-        for (; __index < array.length; __index++) {
-            skipWhiteSpace();
-            switch (__currentChar) {
-
-                case '"':
-                    Value key = decodeStringOverlay();
-                    skipWhiteSpace();
-
-                    if (__currentChar != ':') {
-
-                        complain("expecting current character to be " + charDescription(__currentChar) + "\n");
-                    }
-                    __index++;
-
-                    Value item = decodeValueOverlay();
-
-                    skipWhiteSpace();
-
-                    MapItemValue miv = new MapItemValue(key, item);
-
-                    map.add(miv);
-            }
-
-            switch (__currentChar) {
-                case '}':
-                    __index++;
-                    break objectLoop;
-
-                case ',':
-                    continue;
-
-                default:
-
-                    complain(
-                            "expecting '}' or ',' but got current char " + charDescription(__currentChar));
-            }
-        }
-        return value;
-    }
-
-    protected Value decodeValue() {
-        return decodeValueOverlay();
-    }
-
-    private Value decodeValueOverlay() {
-        skipWhiteSpace();
-
-        switch (__currentChar) {
-            case '"':
-                return decodeStringOverlay();
-
-            case '{':
-                return decodeJsonObjectLazyFinalParse();
-
-            case 't':
-                return decodeTrue() ? ValueContainer.TRUE : ValueContainer.FALSE;
-
-            case 'f':
-                return !decodeFalse() ? ValueContainer.FALSE : ValueContainer.TRUE;
-
-            case 'n':
-                return decodeNull() == null ? ValueContainer.NULL : ValueContainer.NULL;
-
-            case '[':
-                return decodeJsonArrayOverlay();
-
-            case '1':
-            case '2':
-            case '3':
-            case '4':
-            case '5':
-            case '6':
-            case '7':
-            case '8':
-            case '9':
-            case '0':
-                return decodeNumberOverlay(false);
-
-            case '-':
-                return decodeNumberOverlay(true);
-
-            default:
-                complain("Unable to determine the " +
-                        "current character, it is not a string, number, array, or object");
-                return null;
-        }
-    }
-
-    private Value decodeNumberOverlay(final boolean minus) {
-        char[] array = charArray;
-
-        final int startIndex = __index;
-        int index = __index;
-        char currentChar;
-        boolean doubleFloat = false;
-        boolean foundDot = false;
-        boolean foundSign = false;
-        boolean foundExp = false;
-
-        if (minus && index + 1 < array.length) {
-            index++;
-        }
-
-        while (true) {
-            currentChar = array[index];
-            if (isNumberDigit(currentChar)) {
-                //noop
-            } else if (currentChar <= 32) { //white
-                break;
-            } else if (isDelimiter(currentChar)) {
-                break;
-            } else if (isDecimalChar(currentChar)) {
-                switch (currentChar) {
-                    case DECIMAL_POINT:
-                        if (foundDot || foundExp) { complain("unexpected character " + currentChar); }
-                        foundDot = true;
-                        break;
-                    case LETTER_E:
-                    case LETTER_BIG_E:
-                        if (foundExp) { complain("unexpected character " + currentChar); }
-                        foundExp = true;
-                        break;
-                    case MINUS:
-                    case PLUS:
-                        if (foundSign || !foundExp) { complain("unexpected character " + currentChar); }
-                        if (foundExp && array[index - 1] != LETTER_E && array[index - 1] != LETTER_BIG_E) {
-                            complain("unexpected character " + currentChar);
-                        }
-                        foundSign = true;
-                        break;
-                }
-                doubleFloat = true;
-            } else {
-                complain("unexpected character " + currentChar);
-            }
-            index++;
-            if (index >= array.length) break;
-        }
-
-        // Handle the case where the exponential number ends without the actual exponent
-        if (foundExp) {
-            char prevChar = array[index - 1];
-            if (prevChar == LETTER_E || prevChar == LETTER_BIG_E || prevChar == MINUS || prevChar == PLUS) {
-                complain("unexpected character " + currentChar);
-            }
-        }
-
-        __index = index;
-        __currentChar = currentChar;
-
-        Type type = doubleFloat ? Type.DOUBLE : Type.INTEGER;
-
-        return new NumberValue(chop, type, startIndex, __index, this.charArray);
-    }
-
-    private Value decodeStringOverlay() {
-        char[] array = charArray;
-        int index = __index;
-        char currentChar = charArray[index];
-
-        if (index < array.length && currentChar == '"') {
-            index++;
-        }
-
-        final int startIndex = index;
-
-        boolean encoded = hasEscapeChar(array, index, indexHolder);
-        index = indexHolder[0];
-
-        if (encoded) {
-            index = findEndQuote(array, index);
-        }
-
-        Value value = new CharSequenceValue(chop, Type.STRING, startIndex, index, array, encoded, checkDates);
-
-        if (index < array.length) {
-            index++;
-        }
-
-        __index = index;
-        return value;
-    }
-
-    private Value decodeJsonArrayOverlay() {
-        char[] array = charArray;
-        if (__currentChar == '[') {
-            __index++;
-        }
-
-        skipWhiteSpace();
-
-        /* the list might be empty  */
-        if (__currentChar == ']') {
-            __index++;
-            return new ValueContainer(new ArrayList());
-        }
-
-        List<Object> list;
-
-        if (useValues) {
-            list = new ArrayList<Object>();
-        } else {
-            list = new ValueList(lazyChop);
-        }
-
-        Value value = new ValueContainer(list);
-
-        Value item;
-        char c;
-        int lastIndex;
-        boolean foundEnd = false;
-
-        arrayLoop:
-        for (; __index < array.length; __index++) {
-            item = decodeValueOverlay();
-
-            list.add(item);
-            c = currentChar();
-            switch (c) {
-                case ',':
-                    continue;
-                case ']':
-                    __index++;
-                    foundEnd = true;
-                    break arrayLoop;
-            }
-
-            lastIndex = __index;
-            skipWhiteSpace();
-            c = currentChar();
-
-            switch (c) {
-                case ',':
-                    continue;
-                case ']':
-                    if (__index == lastIndex) {
-                        complain("missing ]");
-                    }
-                    foundEnd = true;
-                    __index++;
-                    break arrayLoop;
-                default:
-                    complain(
-                            String.format("expecting a ',' or a ']', " +
-                                    " but got \nthe current character of  %s " +
-                                    " on array size of %s \n", charDescription(__currentChar), list.size())
-                    );
-            }
-        }
-
-        if (!foundEnd) {
-            complain("Did not find end of Json Array");
-        }
-        return value;
-    }
-
-    protected final Object decodeFromChars(char[] cs) {
-        Value value = ((Value) super.decodeFromChars(cs));
-        if (value.isContainer()) {
-            return value.toValue();
-        } else {
-            return value;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java
deleted file mode 100644
index 85120d1..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Converts an input JSON String into Java objects works with String or char array
- * as input. Produces an Object which can be any of the basic JSON types mapped
- * to Java.
- * <p/>
- *
- * @author Rick Hightower
- */
-public class JsonParserCharArray extends BaseJsonParser {
-
-    protected char[] charArray;
-    protected int __index;
-    protected char __currentChar;
-
-    private int lastIndex;
-
-    protected Object decodeFromChars(char[] cs) {
-        __index = 0;
-        charArray = cs;
-        lastIndex = cs.length - 1;
-        return decodeValue();
-    }
-
-    protected final boolean hasMore() {
-        return __index < lastIndex;
-    }
-
-    protected final boolean hasCurrent() {
-        return __index <= lastIndex;
-    }
-
-    protected final void skipWhiteSpace() {
-        int ix = __index;
-
-        if (hasCurrent()) {
-            this.__currentChar = this.charArray[ix];
-        }
-
-        if (__currentChar <= 32) {
-            ix = skipWhiteSpaceFast(this.charArray, ix);
-            this.__currentChar = this.charArray[ix];
-            __index = ix;
-        }
-    }
-
-    protected final char nextChar() {
-        try {
-            if (hasMore()) {
-                __index++;
-                return __currentChar = charArray[__index];
-            } else {
-                // TODO move unicode 0 to separate file to avoid doc parsing issues
-                return '\u0000';
-            }
-        } catch (Exception ex) {
-            throw new JsonException(exceptionDetails("unable to advance character"), ex);
-        }
-    }
-
-    protected String exceptionDetails(String message) {
-        return CharScanner.errorDetails(message, charArray, __index, __currentChar);
-    }
-
-    private static int skipWhiteSpaceFast(char[] array, int index) {
-        char c;
-        for (; index < array.length; index++) {
-            c = array[index];
-            if (c > 32) {
-                return index;
-            }
-        }
-        return index - 1;
-    }
-
-    protected final Object decodeJsonObject() {
-        if (__currentChar == '{') {
-            __index++;
-        }
-
-        LazyMap map = new LazyMap();
-
-        for (; __index < this.charArray.length; __index++) {
-            skipWhiteSpace();
-
-            if (__currentChar == '"') {
-                String key = decodeString();
-
-                if (internKeys) {
-                    String keyPrime = internedKeysCache.get(key);
-                    if (keyPrime == null) {
-                        key = key.intern();
-                        internedKeysCache.put(key, key);
-                    } else {
-                        key = keyPrime;
-                    }
-                }
-
-                skipWhiteSpace();
-
-                if (__currentChar != ':') {
-                    complain("expecting current character to be " + charDescription(__currentChar) + "\n");
-                }
-                __index++;
-
-                skipWhiteSpace();
-
-                Object value = decodeValueInternal();
-
-                skipWhiteSpace();
-                map.put(key, value);
-            }
-
-            if (__currentChar == '}') {
-                __index++;
-                break;
-            } else if (__currentChar == ',') {
-                continue;
-            } else {
-                complain(
-                        "expecting '}' or ',' but got current char " + charDescription(__currentChar));
-            }
-        }
-
-        return map;
-    }
-
-    protected final void complain(String complaint) {
-        throw new JsonException(exceptionDetails(complaint));
-    }
-
-    protected Object decodeValue() {
-        return decodeValueInternal();
-    }
-
-    private Object decodeValueInternal() {
-        Object value = null;
-        skipWhiteSpace();
-
-        switch (__currentChar) {
-            case '"':
-                value = decodeString();
-                break;
-
-            case 't':
-                value = decodeTrue();
-                break;
-
-            case 'f':
-                value = decodeFalse();
-                break;
-
-            case 'n':
-                value = decodeNull();
-                break;
-
-            case '[':
-                value = decodeJsonArray();
-                break;
-
-            case '{':
-                value = decodeJsonObject();
-                break;
-
-            case '0':
-            case '1':
-            case '2':
-            case '3':
-            case '4':
-            case '5':
-            case '6':
-            case '7':
-            case '8':
-            case '9':
-                value = decodeNumber();
-                break;
-            case '-':
-                value = decodeNumber();
-                break;
-
-            default:
-                throw new JsonException(exceptionDetails("Unable to determine the " +
-                        "current character, it is not a string, number, array, or object"));
-        }
-
-        return value;
-    }
-
-    int[] endIndex = new int[1];
-
-    private Object decodeNumber() {
-        Number num = CharScanner.parseJsonNumber(charArray, __index, charArray.length, endIndex);
-        __index = endIndex[0];
-
-        return num;
-    }
-
-    protected static final char[] NULL = Chr.chars("null");
-
-    protected final Object decodeNull() {
-        if (__index + NULL.length <= charArray.length) {
-            if (charArray[__index] == 'n' &&
-                    charArray[++__index] == 'u' &&
-                    charArray[++__index] == 'l' &&
-                    charArray[++__index] == 'l') {
-                __index++;
-                return null;
-            }
-        }
-        throw new JsonException(exceptionDetails("null not parse properly"));
-    }
-
-    protected static final char[] TRUE = Chr.chars("true");
-
-    protected final boolean decodeTrue() {
-        if (__index + TRUE.length <= charArray.length) {
-            if (charArray[__index] == 't' &&
-                    charArray[++__index] == 'r' &&
-                    charArray[++__index] == 'u' &&
-                    charArray[++__index] == 'e') {
-
-                __index++;
-                return true;
-            }
-        }
-
-        throw new JsonException(exceptionDetails("true not parsed properly"));
-    }
-
-    protected static char[] FALSE = Chr.chars("false");
-
-    protected final boolean decodeFalse() {
-        if (__index + FALSE.length <= charArray.length) {
-            if (charArray[__index] == 'f' &&
-                    charArray[++__index] == 'a' &&
-                    charArray[++__index] == 'l' &&
-                    charArray[++__index] == 's' &&
-                    charArray[++__index] == 'e') {
-                __index++;
-                return false;
-            }
-        }
-        throw new JsonException(exceptionDetails("false not parsed properly"));
-    }
-
-    private CharBuf builder = CharBuf.create(20);
-
-    private String decodeString() {
-        char[] array = charArray;
-        int index = __index;
-        char currentChar = array[index];
-
-        if (index < array.length && currentChar == '"') {
-            index++;
-        }
-
-        final int startIndex = index;
-
-        boolean encoded = hasEscapeChar(array, index, indexHolder);
-        index = indexHolder[0];
-
-        String value = null;
-        if (encoded) {
-            index = findEndQuote(array, index);
-            value = builder.decodeJsonString(array, startIndex, index).toString();
-            builder.recycle();
-        } else {
-            value = new String(array, startIndex, (index - startIndex));
-        }
-
-        if (index < charArray.length) {
-            index++;
-        }
-        __index = index;
-        return value;
-    }
-
-    protected final List decodeJsonArray() {
-        ArrayList<Object> list = null;
-
-        boolean foundEnd = false;
-        char[] charArray = this.charArray;
-
-        try {
-            if (__currentChar == '[') {
-                __index++;
-            }
-
-            int lastIndex;
-
-            skipWhiteSpace();
-
-        /* the list might be empty  */
-            if (__currentChar == ']') {
-                __index++;
-                return new ArrayList();
-            }
-
-            list = new ArrayList();
-
-            while (this.hasMore()) {
-                Object arrayItem = decodeValueInternal();
-
-                list.add(arrayItem);
-
-                char c = charArray[__index];
-
-                if (c == ',') {
-                    __index++;
-                    continue;
-                } else if (c == ']') {
-                    __index++;
-                    foundEnd = true;
-                    break;
-                }
-
-                lastIndex = __index;
-                skipWhiteSpace();
-
-                c = charArray[__index];
-
-                if (c == ',') {
-                    __index++;
-                    continue;
-                } else if (c == ']' && lastIndex != __index) {
-                    __index++;
-                    foundEnd = true;
-                    break;
-                } else {
-                    String charString = charDescription(c);
-
-                    complain(
-                            String.format("expecting a ',' or a ']', " +
-                                    " but got \nthe current character of  %s " +
-                                    " on array index of %s \n", charString, list.size())
-                    );
-                }
-            }
-        } catch (Exception ex) {
-            if (ex instanceof JsonException) {
-                throw (JsonException) ex;
-            }
-            throw new JsonException(exceptionDetails("issue parsing JSON array"), ex);
-        }
-        if (!foundEnd) {
-            complain("Did not find end of Json Array");
-        }
-        return list;
-    }
-
-    protected final char currentChar() {
-        if (__index > lastIndex) {
-            return 0;
-        } else {
-            return charArray[__index];
-        }
-    }
-
-    public Object parse(char[] chars) {
-        return this.decodeFromChars(chars);
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
deleted file mode 100644
index cde56b9..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author Richard Hightower
- */
-public class JsonParserLax extends JsonParserCharArray {
-
-    private final boolean useValues;
-    private final boolean chop;
-    private final boolean lazyChop;
-    private final boolean defaultCheckDates;
-
-    public JsonParserLax() {
-        this(true);
-    }
-
-    public JsonParserLax(boolean useValues) {
-        this(useValues, false);
-    }
-
-    public JsonParserLax(boolean useValues, boolean chop) {
-        this(useValues, chop, !chop);
-    }
-
-    public JsonParserLax(boolean useValues, boolean chop, boolean lazyChop) {
-        this(useValues, chop, lazyChop, true);
-    }
-
-    public JsonParserLax(boolean useValues, boolean chop, boolean lazyChop, boolean defaultCheckDates) {
-        this.useValues = useValues;
-        this.chop = chop;
-        this.lazyChop = lazyChop;
-        this.defaultCheckDates = defaultCheckDates;
-    }
-
-    private Value decodeJsonObjectLax() {
-        if (__currentChar == '{')
-            this.nextChar();
-
-        ValueMap map = useValues ? new ValueMapImpl() : new LazyValueMap(lazyChop);
-        Value value = new ValueContainer(map);
-
-        skipWhiteSpace();
-        int startIndexOfKey = __index;
-        Value key;
-        MapItemValue miv;
-        Value item;
-
-        done:
-        for (; __index < this.charArray.length; __index++) {
-            skipWhiteSpace();
-
-            switch (__currentChar) {
-                case ':':
-                    char startChar = charArray[startIndexOfKey];
-                    if (startChar == ',') {
-                        startIndexOfKey++;
-                    }
-
-                    key = extractLaxString(startIndexOfKey, __index - 1, false, false);
-                    __index++; //skip :
-
-                    item = decodeValueInternal();
-                    skipWhiteSpace();
-
-                    miv = new MapItemValue(key, item);
-
-                    map.add(miv);
-
-                    startIndexOfKey = __index;
-                    if (__currentChar == '}') {
-                        __index++;
-                        break done;
-                    }
-
-                    break;
-
-                case '\'':
-                    key = decodeStringSingle();
-
-                    //puts ("key with quote", key);
-
-                    skipWhiteSpace();
-
-                    if (__currentChar != ':') {
-                        complain("expecting current character to be ':' but got " + charDescription(__currentChar) + "\n");
-                    }
-                    __index++;
-                    item = decodeValueInternal();
-
-                    //puts ("key", "#" + key + "#", value);
-
-                    skipWhiteSpace();
-
-                    miv = new MapItemValue(key, item);
-
-                    map.add(miv);
-                    startIndexOfKey = __index;
-                    if (__currentChar == '}') {
-                        __index++;
-                        break done;
-                    }
-
-                    break;
-
-                case '"':
-                    key = decodeStringDouble();
-
-                    //puts ("key with quote", key);
-
-                    skipWhiteSpace();
-
-                    if (__currentChar != ':') {
-                        complain("expecting current character to be ':' but got " + charDescription(__currentChar) + "\n");
-                    }
-                    __index++;
-                    item = decodeValueInternal();
-
-                    //puts ("key", "#" + key + "#", value);
-
-                    skipWhiteSpace();
-
-                    miv = new MapItemValue(key, item);
-
-                    map.add(miv);
-                    startIndexOfKey = __index;
-                    if (__currentChar == '}') {
-                        __index++;
-                        break done;
-                    }
-
-                    break;
-            }
-
-            switch (__currentChar) {
-                case '}':
-                    __index++;
-                    break done;
-
-                case '/': /* */ //
-                    handleComment();
-                    startIndexOfKey = __index;
-                    break;
-
-                case '#':
-                    handleBashComment();
-                    startIndexOfKey = __index;
-                    break;
-            }
-        }
-
-        return value;
-    }
-
-    private Value extractLaxString(int startIndexOfKey, int end, boolean encoded, boolean checkDate) {
-        char startChar;
-        startIndexLookup:
-        for (; startIndexOfKey < __index && startIndexOfKey < charArray.length; startIndexOfKey++) {
-            startChar = charArray[startIndexOfKey];
-            switch (startChar) {
-                case ' ':
-                case '\n':
-                case '\t':
-                    continue;
-
-                default:
-                    break startIndexLookup;
-            }
-        }
-
-        char endChar;
-        int endIndex = end >= charArray.length ? charArray.length - 1 : end;
-        endIndexLookup:
-        for (; endIndex >= startIndexOfKey + 1 && endIndex >= 0; endIndex--) {
-            endChar = charArray[endIndex];
-            switch (endChar) {
-                case ' ':
-                case '\n':
-                case '\t':
-                case '}':
-                    continue;
-                case ',':
-                case ';':
-                    continue;
-
-                case ']':
-                    continue;
-                default:
-                    break endIndexLookup;
-            }
-        }
-        return new CharSequenceValue(chop, Type.STRING, startIndexOfKey, endIndex + 1, this.charArray, encoded, checkDate);
-    }
-
-    protected final Object decodeValue() {
-        return this.decodeValueInternal();
-    }
-
-    private Value decodeValueInternal() {
-        Value value = null;
-
-        for (; __index < charArray.length; __index++) {
-            skipWhiteSpace();
-
-            switch (__currentChar) {
-                case '\n':
-                    break;
-
-                case '\r':
-                    break;
-
-                case ' ':
-                    break;
-
-                case '\t':
-                    break;
-
-                case '\b':
-                    break;
-
-                case '\f':
-                    break;
-
-                case '/': /* */ //
-                    handleComment();
-                    break;
-
-                case '#':
-                    handleBashComment();
-                    break;
-
-                case '"':
-                    value = decodeStringDouble();
-                    break;
-
-                case '\'':
-                    value = decodeStringSingle();
-                    break;
-
-                case 't':
-                    if (isTrue()) {
-                        return decodeTrue() ? ValueContainer.TRUE : ValueContainer.FALSE;
-                    } else {
-                        value = decodeStringLax();
-                    }
-                    break;
-
-                case 'f':
-                    if (isFalse()) {
-                        return !decodeFalse() ? ValueContainer.FALSE : ValueContainer.TRUE;
-                    } else {
-                        value = decodeStringLax();
-                    }
-                    break;
-
-                case 'n':
-                    if (isNull()) {
-                        return decodeNull() == null ? ValueContainer.NULL : ValueContainer.NULL;
-                    } else {
-                        value = decodeStringLax();
-                    }
-
-                    break;
-
-                case '[':
-                    value = decodeJsonArrayLax();
-                    break;
-
-                case '{':
-                    value = decodeJsonObjectLax();
-                    break;
-
-                case '1':
-                case '2':
-                case '3':
-                case '4':
-                case '5':
-                case '6':
-                case '7':
-                case '8':
-                case '9':
-                case '0':
-                    return decodeNumberLax(false);
-
-                case '-':
-                    return decodeNumberLax(true);
-
-                default:
-                    value = decodeStringLax();
-            }
-
-            if (value != null) {
-                return value;
-            }
-        }
-
-        return null;
-    }
-
-    private void handleBashComment() {
-        for (; __index < charArray.length; __index++) {
-            __currentChar = charArray[__index];
-
-            if (__currentChar == '\n') {
-                __index++;
-                return;
-            }
-        }
-    }
-
-    private void handleComment() {
-        if (hasMore()) {
-            __index++;
-            __currentChar = charArray[__index];
-
-            switch (__currentChar) {
-                case '*':
-                    for (; __index < charArray.length; __index++) {
-                        __currentChar = charArray[__index];
-
-                        if (__currentChar == '*') {
-                            if (hasMore()) {
-                                __index++;
-                                __currentChar = charArray[__index];
-                                if (__currentChar == '/') {
-                                    if (hasMore()) {
-                                        __index++;
-                                        return;
-                                    }
-                                }
-                            } else {
-                                complain("missing close of comment");
-                            }
-                        }
-                    }
-
-                case '/':
-                    for (; __index < charArray.length; __index++) {
-                        __currentChar = charArray[__index];
-
-                        if (__currentChar == '\n') {
-                            if (hasMore()) {
-                                __index++;
-                                return;
-                            } else {
-                                return;
-                            }
-                        }
-                    }
-            }
-        }
-    }
-
-    /**
-     * Decodes a number from a JSON value.  If at any point it is determined that
-     * the value is not a valid number the value is treated as a {@code String}.
-     *
-     * @param minus indicate whether the number is negative
-     * @return a number, or {@code String} if not a valid number
-     */
-    protected final Value decodeNumberLax(boolean minus) {
-        char[] array = charArray;
-
-        final int startIndex = __index;
-        int index = __index;
-        char currentChar;
-        boolean doubleFloat = false;
-        boolean foundDot = false;
-        boolean foundSign = false;
-        boolean foundExp = false;
-
-        if (minus && index + 1 < array.length) {
-            index++;
-        }
-
-        while (true) {
-            currentChar = array[index];
-            if (isNumberDigit(currentChar)) {
-                //noop
-            } else if (currentChar <= 32) { //white
-                break;
-            } else if (isDelimiter(currentChar)) {
-                break;
-            } else if (isDecimalChar(currentChar)) {
-                switch (currentChar) {
-                    case DECIMAL_POINT:
-                        if (foundDot || foundExp) { return decodeStringLax(); }
-                        foundDot = true;
-                        break;
-                    case LETTER_E:
-                    case LETTER_BIG_E:
-                        if (foundExp) { return decodeStringLax(); }
-                        foundExp = true;
-                        break;
-                    case MINUS:
-                    case PLUS:
-                        if (foundSign || !foundExp) { return decodeStringLax(); }
-                        if (foundExp && array[index - 1] != LETTER_E && array[index - 1] != LETTER_BIG_E) {
-                            return decodeStringLax();
-                        }
-                        foundSign = true;
-                        break;
-                }
-                doubleFloat = true;
-            } else {
-                return decodeStringLax();
-            }
-            index++;
-            if (index >= array.length) break;
-        }
-
-        // Handle the case where the exponential number ends without the actual exponent
-        if (foundExp) {
-            char prevChar = array[index - 1];
-            if (prevChar == LETTER_E || prevChar == LETTER_BIG_E || prevChar == MINUS || prevChar == PLUS) {
-                return decodeStringLax();
-            }
-        }
-
-        __index = index;
-        __currentChar = currentChar;
-
-        Type type = doubleFloat ? Type.DOUBLE : Type.INTEGER;
-
-        return new NumberValue(chop, type, startIndex, __index, this.charArray);
-    }
-
-    private boolean isNull() {
-        if (__index + NULL.length <= charArray.length) {
-            if (charArray[__index] == 'n' &&
-                    charArray[__index + 1] == 'u' &&
-                    charArray[__index + 2] == 'l' &&
-                    charArray[__index + 3] == 'l') {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean isTrue() {
-        if (__index + TRUE.length <= charArray.length) {
-            if (charArray[__index] == 't' &&
-                    charArray[__index + 1] == 'r' &&
-                    charArray[__index + 2] == 'u' &&
-                    charArray[__index + 3] == 'e') {
-                return true;
-
-            }
-        }
-        return false;
-    }
-
-    private boolean isFalse() {
-        if (__index + FALSE.length <= charArray.length) {
-            if (charArray[__index] == 'f' &&
-                    charArray[__index + 1] == 'a' &&
-                    charArray[__index + 2] == 'l' &&
-                    charArray[__index + 3] == 's' &&
-                    charArray[__index + 4] == 'e') {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private Value decodeStringLax() {
-        int index = __index;
-        char currentChar = charArray[__index];
-        final int startIndex = __index;
-        boolean encoded = false;
-        char[] charArray = this.charArray;
-
-        for (; index < charArray.length; index++) {
-            currentChar = charArray[index];
-
-            if (isDelimiter(currentChar)) break;
-            else if (currentChar == '\\') break;
-        }
-
-        Value value = this.extractLaxString(startIndex, index, encoded, defaultCheckDates);
-
-        __index = index;
-        return value;
-    }
-
-    private Value decodeStringDouble() {
-        __currentChar = charArray[__index];
-
-        if (__index < charArray.length && __currentChar == '"') {
-            __index++;
-        }
-
-        final int startIndex = __index;
-
-        boolean escape = false;
-        boolean encoded = false;
-
-        done:
-        for (; __index < this.charArray.length; __index++) {
-            __currentChar = charArray[__index];
-            switch (__currentChar) {
-
-                case '"':
-                    if (!escape) {
-                        break done;
-                    } else {
-                        escape = false;
-                        continue;
-                    }
-
-                case '\\':
-                    escape = !escape;
-                    encoded = true;
-                    continue;
-            }
-            escape = false;
-        }
-
-        Value value = new CharSequenceValue(chop, Type.STRING, startIndex, __index, this.charArray, encoded, defaultCheckDates);
-
-        if (__index < charArray.length) {
-            __index++;
-        }
-
-        return value;
-    }
-
-    private Value decodeStringSingle() {
-        __currentChar = charArray[__index];
-
-        if (__index < charArray.length && __currentChar == '\'') {
-            __index++;
-        }
-
-        final int startIndex = __index;
-
-        boolean escape = false;
-        boolean encoded = false;
-        int minusCount = 0;
-        int colonCount = 0;
-
-        done:
-        for (; __index < this.charArray.length; __index++) {
-            __currentChar = charArray[__index];
-            switch (__currentChar) {
-                case '\'':
-                    if (!escape) {
-                        break done;
-                    } else {
-                        escape = false;
-                        continue;
-                    }
-
-                case '\\':
-                    encoded = true;
-                    escape = true;
-                    continue;
-
-                case '-':
-                    minusCount++;
-                    break;
-
-                case ':':
-                    colonCount++;
-                    break;
-            }
-            escape = false;
-        }
-
-        boolean checkDates = defaultCheckDates && !encoded && minusCount >= 2 && colonCount >= 2;
-
-        Value value = new CharSequenceValue(chop, Type.STRING, startIndex, __index, this.charArray, encoded, checkDates);
-
-        if (__index < charArray.length) {
-            __index++;
-        }
-
-        return value;
-    }
-
-    private Value decodeJsonArrayLax() {
-        if (__currentChar == '[') {
-            __index++;
-        }
-
-        skipWhiteSpace();
-
-        if (__currentChar == ']') {
-            __index++;
-            return new ValueContainer(new ArrayList());
-        }
-
-        List<Object> list;
-
-        if (useValues) {
-            list = new ArrayList<Object>();
-        } else {
-            list = new ValueList(lazyChop);
-        }
-
-        Value value = new ValueContainer(list);
-
-        do {
-            skipWhiteSpace();
-
-            Object arrayItem = decodeValueInternal();
-
-            list.add(arrayItem);
-
-            boolean doStop = false;
-
-            done:
-            do { // Find either next array element or end of array while ignoring comments
-                skipWhiteSpace();
-
-                switch (__currentChar) {
-                    case '/':
-                        handleComment();
-                        continue;
-                    case '#':
-                        handleBashComment();
-                        continue;
-                    case ',':
-                        __index++;
-                        break done;
-                    case ']':
-                        __index++;
-                        doStop = true;
-                        break done;
-                    default:
-                        String charString = charDescription(__currentChar);
-
-                        complain(
-                                String.format("expecting a ',' or a ']', " +
-                                        " but got \nthe current character of  %s " +
-                                        " on array index of %s \n", charString, list.size())
-                        );
-                }
-            } while (this.hasMore());
-
-            if (doStop) break;
-
-        } while (this.hasMore());
-
-        return value;
-    }
-
-    protected final Object decodeFromChars(char[] cs) {
-        Value value = ((Value) super.decodeFromChars(cs));
-        if (value.isContainer()) {
-            return value.toValue();
-        } else {
-            return value;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java
deleted file mode 100644
index 47a470f..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Converts an input JSON String into Java objects works with String or char array
- * as input. Produces an Object which can be any of the basic JSON types mapped
- * to Java.
- * <p/>
- *
- * @author Rick Hightower
- */
-public class JsonParserUsingCharacterSource extends BaseJsonParser {
-
-    private CharacterSource characterSource;
-
-    protected String exceptionDetails(String message) {
-        return characterSource.errorDetails(message);
-    }
-
-    protected final Object decodeJsonObject() {
-        LazyMap map = new LazyMap();
-
-        try {
-            CharacterSource characterSource = this.characterSource;
-
-            if (characterSource.currentChar() == '{') {
-                characterSource.nextChar();
-            }
-
-            while (characterSource.hasChar()) {
-                characterSource.skipWhiteSpace();
-
-                if (characterSource.currentChar() == DOUBLE_QUOTE) {
-                    String key = decodeString();
-                    //puts ("key", key);
-
-                    if (internKeys) {
-                        String keyPrime = internedKeysCache.get(key);
-                        if (keyPrime == null) {
-                            key = key.intern();
-                            internedKeysCache.put(key, key);
-                        } else {
-                            key = keyPrime;
-                        }
-                    }
-
-                    characterSource.skipWhiteSpace();
-                    if (characterSource.currentChar() != COLON) {
-                        complain("expecting current character to be : but was " + charDescription(characterSource.currentChar()) + "\n");
-                    }
-
-                    characterSource.nextChar();
-                    characterSource.skipWhiteSpace();
-
-                    Object value = decodeValue();
-
-                    //puts ("key", key, "value", value);
-
-                    characterSource.skipWhiteSpace();
-
-                    map.put(key, value);
-                }
-
-                int ch = characterSource.currentChar();
-                if (ch == '}') {
-                    characterSource.nextChar();
-                    break;
-                } else if (ch == ',') {
-                    characterSource.nextChar();
-                    continue;
-                } else {
-                    complain(
-                            "expecting '}' or ',' but got current char " + charDescription(ch));
-                }
-            }
-        } catch (Exception ex) {
-            throw new JsonException(exceptionDetails("Unable to parse JSON object"), ex);
-        }
-
-        return map;
-    }
-
-    protected final void complain(String complaint) {
-        throw new JsonException(exceptionDetails(complaint));
-    }
-
-    private Object decodeValue() {
-        CharacterSource characterSource = this.characterSource;
-        Object value = null;
-        characterSource.skipWhiteSpace();
-
-        switch (characterSource.currentChar()) {
-            case '"':
-                value = decodeString();
-                break;
-
-            case 't':
-                value = decodeTrue();
-                break;
-
-            case 'f':
-                value = decodeFalse();
-                break;
-
-            case 'n':
-                value = decodeNull();
-                break;
-
-            case '[':
-                value = decodeJsonArray();
-                break;
-
-            case '{':
-                value = decodeJsonObject();
-                break;
-
-            case '0':
-            case '1':
-            case '2':
-            case '3':
-            case '4':
-            case '5':
-            case '6':
-            case '7':
-            case '8':
-            case '9':
-                value = decodeNumber(false);
-                break;
-
-            case '-':
-                value = decodeNumber(true);
-                break;
-
-            default:
-                throw new JsonException(exceptionDetails("Unable to determine the " +
-                        "current character, it is not a string, number, array, or object"));
-        }
-
-        return value;
-    }
-
-    private Object decodeNumber(boolean negative) {
-        char[] chars = characterSource.readNumber();
-        Object value = null;
-
-        if (CharScanner.hasDecimalChar(chars, negative)) {
-            value = CharScanner.parseBigDecimal(chars);
-        } else if (CharScanner.isInteger(chars)) {
-            value = CharScanner.parseInt(chars);
-        } else if (CharScanner.isLong(chars)) {
-            value = CharScanner.parseLong(chars);
-        }
-
-        return value;
-    }
-
-    protected static final char[] NULL = Chr.chars("null");
-
-    protected final Object decodeNull() {
-        if (!characterSource.consumeIfMatch(NULL)) {
-            throw new JsonException(exceptionDetails("null not parse properly"));
-        }
-        return null;
-    }
-
-    protected static final char[] TRUE = Chr.chars("true");
-
-    protected final boolean decodeTrue() {
-        if (characterSource.consumeIfMatch(TRUE)) {
-            return true;
-        } else {
-            throw new JsonException(exceptionDetails("true not parsed properly"));
-        }
-    }
-
-    protected static char[] FALSE = Chr.chars("false");
-
-    protected final boolean decodeFalse() {
-        if (characterSource.consumeIfMatch(FALSE)) {
-            return false;
-        } else {
-            throw new JsonException(exceptionDetails("false not parsed properly"));
-        }
-    }
-
-    private CharBuf builder = CharBuf.create(20);
-
-    private String decodeString() {
-        CharacterSource characterSource = this.characterSource;
-
-        characterSource.nextChar();
-
-        char[] chars = characterSource.findNextChar('"', '\\');
-
-        String value = null;
-        if (characterSource.hadEscape()) {
-            value = builder.decodeJsonString(chars).toString();
-            builder.recycle();
-        } else {
-            value = new String(chars);
-        }
-
-        return value;
-    }
-
-    protected final List decodeJsonArray() {
-        ArrayList<Object> list = null;
-
-        boolean foundEnd = false;
-        try {
-            CharacterSource characterSource = this.characterSource;
-
-            if (this.characterSource.currentChar() == '[') {
-                characterSource.nextChar();
-            }
-
-            characterSource.skipWhiteSpace();
-
-        /* the list might be empty  */
-            if (this.characterSource.currentChar() == ']') {
-                characterSource.nextChar();
-                return new ArrayList();
-            }
-
-            list = new ArrayList();
-
-            do {
-                characterSource.skipWhiteSpace();
-
-                Object arrayItem = decodeValue();
-
-                list.add(arrayItem);
-
-                characterSource.skipWhiteSpace();
-
-                int c = characterSource.currentChar();
-
-                if (c == COMMA) {
-                    characterSource.nextChar();
-                    continue;
-                } else if (c == CLOSED_BRACKET) {
-                    foundEnd = true;
-                    characterSource.nextChar();
-                    break;
-                } else {
-                    String charString = charDescription(c);
-
-                    complain(
-                            String.format("expecting a ',' or a ']', " +
-                                    " but got \nthe current character of  %s " +
-                                    " on array index of %s \n", charString, list.size())
-                    );
-
-                }
-            } while (characterSource.hasChar());
-        } catch (Exception ex) {
-            throw new JsonException(exceptionDetails("Unexpected issue"), ex);
-        }
-
-        if (!foundEnd) {
-            throw new JsonException(exceptionDetails("Could not find end of JSON array"));
-        }
-        return list;
-    }
-
-    public Object parse(Reader reader) {
-        characterSource = new ReaderCharacterSource(reader);
-        return this.decodeValue();
-    }
-
-    public Object parse(char[] chars) {
-        return parse(new StringReader(new String(chars)));
-    }
-}


[3/7] groovy git commit: GROOVY-8379: Rework groovy-json FastStringUtils (closes #667)

Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonFastParser.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonFastParser.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonFastParser.java
new file mode 100644
index 0000000..4cc219c
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonFastParser.java
@@ -0,0 +1,334 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This works in index overlay mode or chop mode.
+ * Chop mode reduces possibility of memory leak but causes a few more buffer copies as it chops up the buffer.
+ *
+ * @author Rick Hightower
+ */
+public class JsonFastParser extends JsonParserCharArray {
+
+    private final boolean useValues;
+    private final boolean chop;
+    private final boolean lazyChop;
+    private final boolean checkDates;
+
+    public JsonFastParser() {
+        this(true);
+    }
+
+    public JsonFastParser(boolean useValues) {
+        this(useValues, false);
+    }
+
+    public JsonFastParser(boolean useValues, boolean chop) {
+        this(useValues, chop, !chop);
+    }
+
+    public JsonFastParser(boolean useValues, boolean chop, boolean lazyChop) {
+        this(useValues, chop, lazyChop, true);
+    }
+
+    public JsonFastParser(boolean useValues, boolean chop, boolean lazyChop, boolean checkDates) {
+        this.useValues = useValues;
+        this.chop = chop;
+        this.lazyChop = lazyChop;
+        this.checkDates = checkDates;
+    }
+
+    protected final Value decodeJsonObjectLazyFinalParse() {
+        char[] array = charArray;
+
+        if (__currentChar == '{')
+            __index++;
+
+        ValueMap map = useValues ? new ValueMapImpl() : new LazyValueMap(lazyChop);
+        Value value = new ValueContainer(map);
+
+        objectLoop:
+        for (; __index < array.length; __index++) {
+            skipWhiteSpace();
+            switch (__currentChar) {
+
+                case '"':
+                    Value key = decodeStringOverlay();
+                    skipWhiteSpace();
+
+                    if (__currentChar != ':') {
+
+                        complain("expecting current character to be " + charDescription(__currentChar) + "\n");
+                    }
+                    __index++;
+
+                    Value item = decodeValueOverlay();
+
+                    skipWhiteSpace();
+
+                    MapItemValue miv = new MapItemValue(key, item);
+
+                    map.add(miv);
+            }
+
+            switch (__currentChar) {
+                case '}':
+                    __index++;
+                    break objectLoop;
+
+                case ',':
+                    continue;
+
+                default:
+
+                    complain(
+                            "expecting '}' or ',' but got current char " + charDescription(__currentChar));
+            }
+        }
+        return value;
+    }
+
+    protected Value decodeValue() {
+        return decodeValueOverlay();
+    }
+
+    private Value decodeValueOverlay() {
+        skipWhiteSpace();
+
+        switch (__currentChar) {
+            case '"':
+                return decodeStringOverlay();
+
+            case '{':
+                return decodeJsonObjectLazyFinalParse();
+
+            case 't':
+                return decodeTrue() ? ValueContainer.TRUE : ValueContainer.FALSE;
+
+            case 'f':
+                return !decodeFalse() ? ValueContainer.FALSE : ValueContainer.TRUE;
+
+            case 'n':
+                return decodeNull() == null ? ValueContainer.NULL : ValueContainer.NULL;
+
+            case '[':
+                return decodeJsonArrayOverlay();
+
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case '0':
+                return decodeNumberOverlay(false);
+
+            case '-':
+                return decodeNumberOverlay(true);
+
+            default:
+                complain("Unable to determine the " +
+                        "current character, it is not a string, number, array, or object");
+                return null;
+        }
+    }
+
+    private Value decodeNumberOverlay(final boolean minus) {
+        char[] array = charArray;
+
+        final int startIndex = __index;
+        int index = __index;
+        char currentChar;
+        boolean doubleFloat = false;
+        boolean foundDot = false;
+        boolean foundSign = false;
+        boolean foundExp = false;
+
+        if (minus && index + 1 < array.length) {
+            index++;
+        }
+
+        while (true) {
+            currentChar = array[index];
+            if (isNumberDigit(currentChar)) {
+                //noop
+            } else if (currentChar <= 32) { //white
+                break;
+            } else if (isDelimiter(currentChar)) {
+                break;
+            } else if (isDecimalChar(currentChar)) {
+                switch (currentChar) {
+                    case DECIMAL_POINT:
+                        if (foundDot || foundExp) { complain("unexpected character " + currentChar); }
+                        foundDot = true;
+                        break;
+                    case LETTER_E:
+                    case LETTER_BIG_E:
+                        if (foundExp) { complain("unexpected character " + currentChar); }
+                        foundExp = true;
+                        break;
+                    case MINUS:
+                    case PLUS:
+                        if (foundSign || !foundExp) { complain("unexpected character " + currentChar); }
+                        if (foundExp && array[index - 1] != LETTER_E && array[index - 1] != LETTER_BIG_E) {
+                            complain("unexpected character " + currentChar);
+                        }
+                        foundSign = true;
+                        break;
+                }
+                doubleFloat = true;
+            } else {
+                complain("unexpected character " + currentChar);
+            }
+            index++;
+            if (index >= array.length) break;
+        }
+
+        // Handle the case where the exponential number ends without the actual exponent
+        if (foundExp) {
+            char prevChar = array[index - 1];
+            if (prevChar == LETTER_E || prevChar == LETTER_BIG_E || prevChar == MINUS || prevChar == PLUS) {
+                complain("unexpected character " + currentChar);
+            }
+        }
+
+        __index = index;
+        __currentChar = currentChar;
+
+        Type type = doubleFloat ? Type.DOUBLE : Type.INTEGER;
+
+        return new NumberValue(chop, type, startIndex, __index, this.charArray);
+    }
+
+    private Value decodeStringOverlay() {
+        char[] array = charArray;
+        int index = __index;
+        char currentChar = charArray[index];
+
+        if (index < array.length && currentChar == '"') {
+            index++;
+        }
+
+        final int startIndex = index;
+
+        boolean encoded = hasEscapeChar(array, index, indexHolder);
+        index = indexHolder[0];
+
+        if (encoded) {
+            index = findEndQuote(array, index);
+        }
+
+        Value value = new CharSequenceValue(chop, Type.STRING, startIndex, index, array, encoded, checkDates);
+
+        if (index < array.length) {
+            index++;
+        }
+
+        __index = index;
+        return value;
+    }
+
+    private Value decodeJsonArrayOverlay() {
+        char[] array = charArray;
+        if (__currentChar == '[') {
+            __index++;
+        }
+
+        skipWhiteSpace();
+
+        /* the list might be empty  */
+        if (__currentChar == ']') {
+            __index++;
+            return new ValueContainer(new ArrayList());
+        }
+
+        List<Object> list;
+
+        if (useValues) {
+            list = new ArrayList<Object>();
+        } else {
+            list = new ValueList(lazyChop);
+        }
+
+        Value value = new ValueContainer(list);
+
+        Value item;
+        char c;
+        int lastIndex;
+        boolean foundEnd = false;
+
+        arrayLoop:
+        for (; __index < array.length; __index++) {
+            item = decodeValueOverlay();
+
+            list.add(item);
+            c = currentChar();
+            switch (c) {
+                case ',':
+                    continue;
+                case ']':
+                    __index++;
+                    foundEnd = true;
+                    break arrayLoop;
+            }
+
+            lastIndex = __index;
+            skipWhiteSpace();
+            c = currentChar();
+
+            switch (c) {
+                case ',':
+                    continue;
+                case ']':
+                    if (__index == lastIndex) {
+                        complain("missing ]");
+                    }
+                    foundEnd = true;
+                    __index++;
+                    break arrayLoop;
+                default:
+                    complain(
+                            String.format("expecting a ',' or a ']', " +
+                                    " but got \nthe current character of  %s " +
+                                    " on array size of %s \n", charDescription(__currentChar), list.size())
+                    );
+            }
+        }
+
+        if (!foundEnd) {
+            complain("Did not find end of Json Array");
+        }
+        return value;
+    }
+
+    protected final Object decodeFromChars(char[] cs) {
+        Value value = ((Value) super.decodeFromChars(cs));
+        if (value.isContainer()) {
+            return value.toValue();
+        } else {
+            return value;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserCharArray.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserCharArray.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserCharArray.java
new file mode 100644
index 0000000..6fb6f4c
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserCharArray.java
@@ -0,0 +1,386 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Converts an input JSON String into Java objects works with String or char array
+ * as input. Produces an Object which can be any of the basic JSON types mapped
+ * to Java.
+ * <p/>
+ *
+ * @author Rick Hightower
+ */
+public class JsonParserCharArray extends BaseJsonParser {
+
+    protected char[] charArray;
+    protected int __index;
+    protected char __currentChar;
+
+    private int lastIndex;
+
+    protected Object decodeFromChars(char[] cs) {
+        __index = 0;
+        charArray = cs;
+        lastIndex = cs.length - 1;
+        return decodeValue();
+    }
+
+    protected final boolean hasMore() {
+        return __index < lastIndex;
+    }
+
+    protected final boolean hasCurrent() {
+        return __index <= lastIndex;
+    }
+
+    protected final void skipWhiteSpace() {
+        int ix = __index;
+
+        if (hasCurrent()) {
+            this.__currentChar = this.charArray[ix];
+        }
+
+        if (__currentChar <= 32) {
+            ix = skipWhiteSpaceFast(this.charArray, ix);
+            this.__currentChar = this.charArray[ix];
+            __index = ix;
+        }
+    }
+
+    protected final char nextChar() {
+        try {
+            if (hasMore()) {
+                __index++;
+                return __currentChar = charArray[__index];
+            } else {
+                // TODO move unicode 0 to separate file to avoid doc parsing issues
+                return '\u0000';
+            }
+        } catch (Exception ex) {
+            throw new JsonException(exceptionDetails("unable to advance character"), ex);
+        }
+    }
+
+    protected String exceptionDetails(String message) {
+        return CharScanner.errorDetails(message, charArray, __index, __currentChar);
+    }
+
+    private static int skipWhiteSpaceFast(char[] array, int index) {
+        char c;
+        for (; index < array.length; index++) {
+            c = array[index];
+            if (c > 32) {
+                return index;
+            }
+        }
+        return index - 1;
+    }
+
+    protected final Object decodeJsonObject() {
+        if (__currentChar == '{') {
+            __index++;
+        }
+
+        LazyMap map = new LazyMap();
+
+        for (; __index < this.charArray.length; __index++) {
+            skipWhiteSpace();
+
+            if (__currentChar == '"') {
+                String key = decodeString();
+
+                if (internKeys) {
+                    String keyPrime = internedKeysCache.get(key);
+                    if (keyPrime == null) {
+                        key = key.intern();
+                        internedKeysCache.put(key, key);
+                    } else {
+                        key = keyPrime;
+                    }
+                }
+
+                skipWhiteSpace();
+
+                if (__currentChar != ':') {
+                    complain("expecting current character to be " + charDescription(__currentChar) + "\n");
+                }
+                __index++;
+
+                skipWhiteSpace();
+
+                Object value = decodeValueInternal();
+
+                skipWhiteSpace();
+                map.put(key, value);
+            }
+
+            if (__currentChar == '}') {
+                __index++;
+                break;
+            } else if (__currentChar == ',') {
+                continue;
+            } else {
+                complain(
+                        "expecting '}' or ',' but got current char " + charDescription(__currentChar));
+            }
+        }
+
+        return map;
+    }
+
+    protected final void complain(String complaint) {
+        throw new JsonException(exceptionDetails(complaint));
+    }
+
+    protected Object decodeValue() {
+        return decodeValueInternal();
+    }
+
+    private Object decodeValueInternal() {
+        Object value = null;
+        skipWhiteSpace();
+
+        switch (__currentChar) {
+            case '"':
+                value = decodeString();
+                break;
+
+            case 't':
+                value = decodeTrue();
+                break;
+
+            case 'f':
+                value = decodeFalse();
+                break;
+
+            case 'n':
+                value = decodeNull();
+                break;
+
+            case '[':
+                value = decodeJsonArray();
+                break;
+
+            case '{':
+                value = decodeJsonObject();
+                break;
+
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                value = decodeNumber();
+                break;
+            case '-':
+                value = decodeNumber();
+                break;
+
+            default:
+                throw new JsonException(exceptionDetails("Unable to determine the " +
+                        "current character, it is not a string, number, array, or object"));
+        }
+
+        return value;
+    }
+
+    int[] endIndex = new int[1];
+
+    private Object decodeNumber() {
+        Number num = CharScanner.parseJsonNumber(charArray, __index, charArray.length, endIndex);
+        __index = endIndex[0];
+
+        return num;
+    }
+
+    protected static final char[] NULL = Chr.chars("null");
+
+    protected final Object decodeNull() {
+        if (__index + NULL.length <= charArray.length) {
+            if (charArray[__index] == 'n' &&
+                    charArray[++__index] == 'u' &&
+                    charArray[++__index] == 'l' &&
+                    charArray[++__index] == 'l') {
+                __index++;
+                return null;
+            }
+        }
+        throw new JsonException(exceptionDetails("null not parse properly"));
+    }
+
+    protected static final char[] TRUE = Chr.chars("true");
+
+    protected final boolean decodeTrue() {
+        if (__index + TRUE.length <= charArray.length) {
+            if (charArray[__index] == 't' &&
+                    charArray[++__index] == 'r' &&
+                    charArray[++__index] == 'u' &&
+                    charArray[++__index] == 'e') {
+
+                __index++;
+                return true;
+            }
+        }
+
+        throw new JsonException(exceptionDetails("true not parsed properly"));
+    }
+
+    protected static char[] FALSE = Chr.chars("false");
+
+    protected final boolean decodeFalse() {
+        if (__index + FALSE.length <= charArray.length) {
+            if (charArray[__index] == 'f' &&
+                    charArray[++__index] == 'a' &&
+                    charArray[++__index] == 'l' &&
+                    charArray[++__index] == 's' &&
+                    charArray[++__index] == 'e') {
+                __index++;
+                return false;
+            }
+        }
+        throw new JsonException(exceptionDetails("false not parsed properly"));
+    }
+
+    private CharBuf builder = CharBuf.create(20);
+
+    private String decodeString() {
+        char[] array = charArray;
+        int index = __index;
+        char currentChar = array[index];
+
+        if (index < array.length && currentChar == '"') {
+            index++;
+        }
+
+        final int startIndex = index;
+
+        boolean encoded = hasEscapeChar(array, index, indexHolder);
+        index = indexHolder[0];
+
+        String value = null;
+        if (encoded) {
+            index = findEndQuote(array, index);
+            value = builder.decodeJsonString(array, startIndex, index).toString();
+            builder.recycle();
+        } else {
+            value = new String(array, startIndex, (index - startIndex));
+        }
+
+        if (index < charArray.length) {
+            index++;
+        }
+        __index = index;
+        return value;
+    }
+
+    protected final List decodeJsonArray() {
+        ArrayList<Object> list = null;
+
+        boolean foundEnd = false;
+        char[] charArray = this.charArray;
+
+        try {
+            if (__currentChar == '[') {
+                __index++;
+            }
+
+            int lastIndex;
+
+            skipWhiteSpace();
+
+        /* the list might be empty  */
+            if (__currentChar == ']') {
+                __index++;
+                return new ArrayList();
+            }
+
+            list = new ArrayList();
+
+            while (this.hasMore()) {
+                Object arrayItem = decodeValueInternal();
+
+                list.add(arrayItem);
+
+                char c = charArray[__index];
+
+                if (c == ',') {
+                    __index++;
+                    continue;
+                } else if (c == ']') {
+                    __index++;
+                    foundEnd = true;
+                    break;
+                }
+
+                lastIndex = __index;
+                skipWhiteSpace();
+
+                c = charArray[__index];
+
+                if (c == ',') {
+                    __index++;
+                    continue;
+                } else if (c == ']' && lastIndex != __index) {
+                    __index++;
+                    foundEnd = true;
+                    break;
+                } else {
+                    String charString = charDescription(c);
+
+                    complain(
+                            String.format("expecting a ',' or a ']', " +
+                                    " but got \nthe current character of  %s " +
+                                    " on array index of %s \n", charString, list.size())
+                    );
+                }
+            }
+        } catch (Exception ex) {
+            if (ex instanceof JsonException) {
+                throw (JsonException) ex;
+            }
+            throw new JsonException(exceptionDetails("issue parsing JSON array"), ex);
+        }
+        if (!foundEnd) {
+            complain("Did not find end of Json Array");
+        }
+        return list;
+    }
+
+    protected final char currentChar() {
+        if (__index > lastIndex) {
+            return 0;
+        } else {
+            return charArray[__index];
+        }
+    }
+
+    public Object parse(char[] chars) {
+        return this.decodeFromChars(chars);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserLax.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserLax.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserLax.java
new file mode 100644
index 0000000..89e1fa4
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserLax.java
@@ -0,0 +1,677 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Richard Hightower
+ */
+public class JsonParserLax extends JsonParserCharArray {
+
+    private final boolean useValues;
+    private final boolean chop;
+    private final boolean lazyChop;
+    private final boolean defaultCheckDates;
+
+    public JsonParserLax() {
+        this(true);
+    }
+
+    public JsonParserLax(boolean useValues) {
+        this(useValues, false);
+    }
+
+    public JsonParserLax(boolean useValues, boolean chop) {
+        this(useValues, chop, !chop);
+    }
+
+    public JsonParserLax(boolean useValues, boolean chop, boolean lazyChop) {
+        this(useValues, chop, lazyChop, true);
+    }
+
+    public JsonParserLax(boolean useValues, boolean chop, boolean lazyChop, boolean defaultCheckDates) {
+        this.useValues = useValues;
+        this.chop = chop;
+        this.lazyChop = lazyChop;
+        this.defaultCheckDates = defaultCheckDates;
+    }
+
+    private Value decodeJsonObjectLax() {
+        if (__currentChar == '{')
+            this.nextChar();
+
+        ValueMap map = useValues ? new ValueMapImpl() : new LazyValueMap(lazyChop);
+        Value value = new ValueContainer(map);
+
+        skipWhiteSpace();
+        int startIndexOfKey = __index;
+        Value key;
+        MapItemValue miv;
+        Value item;
+
+        done:
+        for (; __index < this.charArray.length; __index++) {
+            skipWhiteSpace();
+
+            switch (__currentChar) {
+                case ':':
+                    char startChar = charArray[startIndexOfKey];
+                    if (startChar == ',') {
+                        startIndexOfKey++;
+                    }
+
+                    key = extractLaxString(startIndexOfKey, __index - 1, false, false);
+                    __index++; //skip :
+
+                    item = decodeValueInternal();
+                    skipWhiteSpace();
+
+                    miv = new MapItemValue(key, item);
+
+                    map.add(miv);
+
+                    startIndexOfKey = __index;
+                    if (__currentChar == '}') {
+                        __index++;
+                        break done;
+                    }
+
+                    break;
+
+                case '\'':
+                    key = decodeStringSingle();
+
+                    //puts ("key with quote", key);
+
+                    skipWhiteSpace();
+
+                    if (__currentChar != ':') {
+                        complain("expecting current character to be ':' but got " + charDescription(__currentChar) + "\n");
+                    }
+                    __index++;
+                    item = decodeValueInternal();
+
+                    //puts ("key", "#" + key + "#", value);
+
+                    skipWhiteSpace();
+
+                    miv = new MapItemValue(key, item);
+
+                    map.add(miv);
+                    startIndexOfKey = __index;
+                    if (__currentChar == '}') {
+                        __index++;
+                        break done;
+                    }
+
+                    break;
+
+                case '"':
+                    key = decodeStringDouble();
+
+                    //puts ("key with quote", key);
+
+                    skipWhiteSpace();
+
+                    if (__currentChar != ':') {
+                        complain("expecting current character to be ':' but got " + charDescription(__currentChar) + "\n");
+                    }
+                    __index++;
+                    item = decodeValueInternal();
+
+                    //puts ("key", "#" + key + "#", value);
+
+                    skipWhiteSpace();
+
+                    miv = new MapItemValue(key, item);
+
+                    map.add(miv);
+                    startIndexOfKey = __index;
+                    if (__currentChar == '}') {
+                        __index++;
+                        break done;
+                    }
+
+                    break;
+            }
+
+            switch (__currentChar) {
+                case '}':
+                    __index++;
+                    break done;
+
+                case '/': /* */ //
+                    handleComment();
+                    startIndexOfKey = __index;
+                    break;
+
+                case '#':
+                    handleBashComment();
+                    startIndexOfKey = __index;
+                    break;
+            }
+        }
+
+        return value;
+    }
+
+    private Value extractLaxString(int startIndexOfKey, int end, boolean encoded, boolean checkDate) {
+        char startChar;
+        startIndexLookup:
+        for (; startIndexOfKey < __index && startIndexOfKey < charArray.length; startIndexOfKey++) {
+            startChar = charArray[startIndexOfKey];
+            switch (startChar) {
+                case ' ':
+                case '\n':
+                case '\t':
+                    continue;
+
+                default:
+                    break startIndexLookup;
+            }
+        }
+
+        char endChar;
+        int endIndex = end >= charArray.length ? charArray.length - 1 : end;
+        endIndexLookup:
+        for (; endIndex >= startIndexOfKey + 1 && endIndex >= 0; endIndex--) {
+            endChar = charArray[endIndex];
+            switch (endChar) {
+                case ' ':
+                case '\n':
+                case '\t':
+                case '}':
+                    continue;
+                case ',':
+                case ';':
+                    continue;
+
+                case ']':
+                    continue;
+                default:
+                    break endIndexLookup;
+            }
+        }
+        return new CharSequenceValue(chop, Type.STRING, startIndexOfKey, endIndex + 1, this.charArray, encoded, checkDate);
+    }
+
+    protected final Object decodeValue() {
+        return this.decodeValueInternal();
+    }
+
+    private Value decodeValueInternal() {
+        Value value = null;
+
+        for (; __index < charArray.length; __index++) {
+            skipWhiteSpace();
+
+            switch (__currentChar) {
+                case '\n':
+                    break;
+
+                case '\r':
+                    break;
+
+                case ' ':
+                    break;
+
+                case '\t':
+                    break;
+
+                case '\b':
+                    break;
+
+                case '\f':
+                    break;
+
+                case '/': /* */ //
+                    handleComment();
+                    break;
+
+                case '#':
+                    handleBashComment();
+                    break;
+
+                case '"':
+                    value = decodeStringDouble();
+                    break;
+
+                case '\'':
+                    value = decodeStringSingle();
+                    break;
+
+                case 't':
+                    if (isTrue()) {
+                        return decodeTrue() ? ValueContainer.TRUE : ValueContainer.FALSE;
+                    } else {
+                        value = decodeStringLax();
+                    }
+                    break;
+
+                case 'f':
+                    if (isFalse()) {
+                        return !decodeFalse() ? ValueContainer.FALSE : ValueContainer.TRUE;
+                    } else {
+                        value = decodeStringLax();
+                    }
+                    break;
+
+                case 'n':
+                    if (isNull()) {
+                        return decodeNull() == null ? ValueContainer.NULL : ValueContainer.NULL;
+                    } else {
+                        value = decodeStringLax();
+                    }
+
+                    break;
+
+                case '[':
+                    value = decodeJsonArrayLax();
+                    break;
+
+                case '{':
+                    value = decodeJsonObjectLax();
+                    break;
+
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                case '0':
+                    return decodeNumberLax(false);
+
+                case '-':
+                    return decodeNumberLax(true);
+
+                default:
+                    value = decodeStringLax();
+            }
+
+            if (value != null) {
+                return value;
+            }
+        }
+
+        return null;
+    }
+
+    private void handleBashComment() {
+        for (; __index < charArray.length; __index++) {
+            __currentChar = charArray[__index];
+
+            if (__currentChar == '\n') {
+                __index++;
+                return;
+            }
+        }
+    }
+
+    private void handleComment() {
+        if (hasMore()) {
+            __index++;
+            __currentChar = charArray[__index];
+
+            switch (__currentChar) {
+                case '*':
+                    for (; __index < charArray.length; __index++) {
+                        __currentChar = charArray[__index];
+
+                        if (__currentChar == '*') {
+                            if (hasMore()) {
+                                __index++;
+                                __currentChar = charArray[__index];
+                                if (__currentChar == '/') {
+                                    if (hasMore()) {
+                                        __index++;
+                                        return;
+                                    }
+                                }
+                            } else {
+                                complain("missing close of comment");
+                            }
+                        }
+                    }
+
+                case '/':
+                    for (; __index < charArray.length; __index++) {
+                        __currentChar = charArray[__index];
+
+                        if (__currentChar == '\n') {
+                            if (hasMore()) {
+                                __index++;
+                                return;
+                            } else {
+                                return;
+                            }
+                        }
+                    }
+            }
+        }
+    }
+
+    /**
+     * Decodes a number from a JSON value.  If at any point it is determined that
+     * the value is not a valid number the value is treated as a {@code String}.
+     *
+     * @param minus indicate whether the number is negative
+     * @return a number, or {@code String} if not a valid number
+     */
+    protected final Value decodeNumberLax(boolean minus) {
+        char[] array = charArray;
+
+        final int startIndex = __index;
+        int index = __index;
+        char currentChar;
+        boolean doubleFloat = false;
+        boolean foundDot = false;
+        boolean foundSign = false;
+        boolean foundExp = false;
+
+        if (minus && index + 1 < array.length) {
+            index++;
+        }
+
+        while (true) {
+            currentChar = array[index];
+            if (isNumberDigit(currentChar)) {
+                //noop
+            } else if (currentChar <= 32) { //white
+                break;
+            } else if (isDelimiter(currentChar)) {
+                break;
+            } else if (isDecimalChar(currentChar)) {
+                switch (currentChar) {
+                    case DECIMAL_POINT:
+                        if (foundDot || foundExp) { return decodeStringLax(); }
+                        foundDot = true;
+                        break;
+                    case LETTER_E:
+                    case LETTER_BIG_E:
+                        if (foundExp) { return decodeStringLax(); }
+                        foundExp = true;
+                        break;
+                    case MINUS:
+                    case PLUS:
+                        if (foundSign || !foundExp) { return decodeStringLax(); }
+                        if (foundExp && array[index - 1] != LETTER_E && array[index - 1] != LETTER_BIG_E) {
+                            return decodeStringLax();
+                        }
+                        foundSign = true;
+                        break;
+                }
+                doubleFloat = true;
+            } else {
+                return decodeStringLax();
+            }
+            index++;
+            if (index >= array.length) break;
+        }
+
+        // Handle the case where the exponential number ends without the actual exponent
+        if (foundExp) {
+            char prevChar = array[index - 1];
+            if (prevChar == LETTER_E || prevChar == LETTER_BIG_E || prevChar == MINUS || prevChar == PLUS) {
+                return decodeStringLax();
+            }
+        }
+
+        __index = index;
+        __currentChar = currentChar;
+
+        Type type = doubleFloat ? Type.DOUBLE : Type.INTEGER;
+
+        return new NumberValue(chop, type, startIndex, __index, this.charArray);
+    }
+
+    private boolean isNull() {
+        if (__index + NULL.length <= charArray.length) {
+            if (charArray[__index] == 'n' &&
+                    charArray[__index + 1] == 'u' &&
+                    charArray[__index + 2] == 'l' &&
+                    charArray[__index + 3] == 'l') {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isTrue() {
+        if (__index + TRUE.length <= charArray.length) {
+            if (charArray[__index] == 't' &&
+                    charArray[__index + 1] == 'r' &&
+                    charArray[__index + 2] == 'u' &&
+                    charArray[__index + 3] == 'e') {
+                return true;
+
+            }
+        }
+        return false;
+    }
+
+    private boolean isFalse() {
+        if (__index + FALSE.length <= charArray.length) {
+            if (charArray[__index] == 'f' &&
+                    charArray[__index + 1] == 'a' &&
+                    charArray[__index + 2] == 'l' &&
+                    charArray[__index + 3] == 's' &&
+                    charArray[__index + 4] == 'e') {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private Value decodeStringLax() {
+        int index = __index;
+        char currentChar = charArray[__index];
+        final int startIndex = __index;
+        boolean encoded = false;
+        char[] charArray = this.charArray;
+
+        for (; index < charArray.length; index++) {
+            currentChar = charArray[index];
+
+            if (isDelimiter(currentChar)) break;
+            else if (currentChar == '\\') break;
+        }
+
+        Value value = this.extractLaxString(startIndex, index, encoded, defaultCheckDates);
+
+        __index = index;
+        return value;
+    }
+
+    private Value decodeStringDouble() {
+        __currentChar = charArray[__index];
+
+        if (__index < charArray.length && __currentChar == '"') {
+            __index++;
+        }
+
+        final int startIndex = __index;
+
+        boolean escape = false;
+        boolean encoded = false;
+
+        done:
+        for (; __index < this.charArray.length; __index++) {
+            __currentChar = charArray[__index];
+            switch (__currentChar) {
+
+                case '"':
+                    if (!escape) {
+                        break done;
+                    } else {
+                        escape = false;
+                        continue;
+                    }
+
+                case '\\':
+                    escape = !escape;
+                    encoded = true;
+                    continue;
+            }
+            escape = false;
+        }
+
+        Value value = new CharSequenceValue(chop, Type.STRING, startIndex, __index, this.charArray, encoded, defaultCheckDates);
+
+        if (__index < charArray.length) {
+            __index++;
+        }
+
+        return value;
+    }
+
+    private Value decodeStringSingle() {
+        __currentChar = charArray[__index];
+
+        if (__index < charArray.length && __currentChar == '\'') {
+            __index++;
+        }
+
+        final int startIndex = __index;
+
+        boolean escape = false;
+        boolean encoded = false;
+        int minusCount = 0;
+        int colonCount = 0;
+
+        done:
+        for (; __index < this.charArray.length; __index++) {
+            __currentChar = charArray[__index];
+            switch (__currentChar) {
+                case '\'':
+                    if (!escape) {
+                        break done;
+                    } else {
+                        escape = false;
+                        continue;
+                    }
+
+                case '\\':
+                    encoded = true;
+                    escape = true;
+                    continue;
+
+                case '-':
+                    minusCount++;
+                    break;
+
+                case ':':
+                    colonCount++;
+                    break;
+            }
+            escape = false;
+        }
+
+        boolean checkDates = defaultCheckDates && !encoded && minusCount >= 2 && colonCount >= 2;
+
+        Value value = new CharSequenceValue(chop, Type.STRING, startIndex, __index, this.charArray, encoded, checkDates);
+
+        if (__index < charArray.length) {
+            __index++;
+        }
+
+        return value;
+    }
+
+    private Value decodeJsonArrayLax() {
+        if (__currentChar == '[') {
+            __index++;
+        }
+
+        skipWhiteSpace();
+
+        if (__currentChar == ']') {
+            __index++;
+            return new ValueContainer(new ArrayList());
+        }
+
+        List<Object> list;
+
+        if (useValues) {
+            list = new ArrayList<Object>();
+        } else {
+            list = new ValueList(lazyChop);
+        }
+
+        Value value = new ValueContainer(list);
+
+        do {
+            skipWhiteSpace();
+
+            Object arrayItem = decodeValueInternal();
+
+            list.add(arrayItem);
+
+            boolean doStop = false;
+
+            done:
+            do { // Find either next array element or end of array while ignoring comments
+                skipWhiteSpace();
+
+                switch (__currentChar) {
+                    case '/':
+                        handleComment();
+                        continue;
+                    case '#':
+                        handleBashComment();
+                        continue;
+                    case ',':
+                        __index++;
+                        break done;
+                    case ']':
+                        __index++;
+                        doStop = true;
+                        break done;
+                    default:
+                        String charString = charDescription(__currentChar);
+
+                        complain(
+                                String.format("expecting a ',' or a ']', " +
+                                        " but got \nthe current character of  %s " +
+                                        " on array index of %s \n", charString, list.size())
+                        );
+                }
+            } while (this.hasMore());
+
+            if (doStop) break;
+
+        } while (this.hasMore());
+
+        return value;
+    }
+
+    protected final Object decodeFromChars(char[] cs) {
+        Value value = ((Value) super.decodeFromChars(cs));
+        if (value.isContainer()) {
+            return value.toValue();
+        } else {
+            return value;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserUsingCharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserUsingCharacterSource.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserUsingCharacterSource.java
new file mode 100644
index 0000000..8b7d969
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserUsingCharacterSource.java
@@ -0,0 +1,298 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Converts an input JSON String into Java objects works with String or char array
+ * as input. Produces an Object which can be any of the basic JSON types mapped
+ * to Java.
+ * <p/>
+ *
+ * @author Rick Hightower
+ */
+public class JsonParserUsingCharacterSource extends BaseJsonParser {
+
+    private CharacterSource characterSource;
+
+    protected String exceptionDetails(String message) {
+        return characterSource.errorDetails(message);
+    }
+
+    protected final Object decodeJsonObject() {
+        LazyMap map = new LazyMap();
+
+        try {
+            CharacterSource characterSource = this.characterSource;
+
+            if (characterSource.currentChar() == '{') {
+                characterSource.nextChar();
+            }
+
+            while (characterSource.hasChar()) {
+                characterSource.skipWhiteSpace();
+
+                if (characterSource.currentChar() == DOUBLE_QUOTE) {
+                    String key = decodeString();
+                    //puts ("key", key);
+
+                    if (internKeys) {
+                        String keyPrime = internedKeysCache.get(key);
+                        if (keyPrime == null) {
+                            key = key.intern();
+                            internedKeysCache.put(key, key);
+                        } else {
+                            key = keyPrime;
+                        }
+                    }
+
+                    characterSource.skipWhiteSpace();
+                    if (characterSource.currentChar() != COLON) {
+                        complain("expecting current character to be : but was " + charDescription(characterSource.currentChar()) + "\n");
+                    }
+
+                    characterSource.nextChar();
+                    characterSource.skipWhiteSpace();
+
+                    Object value = decodeValue();
+
+                    //puts ("key", key, "value", value);
+
+                    characterSource.skipWhiteSpace();
+
+                    map.put(key, value);
+                }
+
+                int ch = characterSource.currentChar();
+                if (ch == '}') {
+                    characterSource.nextChar();
+                    break;
+                } else if (ch == ',') {
+                    characterSource.nextChar();
+                    continue;
+                } else {
+                    complain(
+                            "expecting '}' or ',' but got current char " + charDescription(ch));
+                }
+            }
+        } catch (Exception ex) {
+            throw new JsonException(exceptionDetails("Unable to parse JSON object"), ex);
+        }
+
+        return map;
+    }
+
+    protected final void complain(String complaint) {
+        throw new JsonException(exceptionDetails(complaint));
+    }
+
+    private Object decodeValue() {
+        CharacterSource characterSource = this.characterSource;
+        Object value = null;
+        characterSource.skipWhiteSpace();
+
+        switch (characterSource.currentChar()) {
+            case '"':
+                value = decodeString();
+                break;
+
+            case 't':
+                value = decodeTrue();
+                break;
+
+            case 'f':
+                value = decodeFalse();
+                break;
+
+            case 'n':
+                value = decodeNull();
+                break;
+
+            case '[':
+                value = decodeJsonArray();
+                break;
+
+            case '{':
+                value = decodeJsonObject();
+                break;
+
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                value = decodeNumber(false);
+                break;
+
+            case '-':
+                value = decodeNumber(true);
+                break;
+
+            default:
+                throw new JsonException(exceptionDetails("Unable to determine the " +
+                        "current character, it is not a string, number, array, or object"));
+        }
+
+        return value;
+    }
+
+    private Object decodeNumber(boolean negative) {
+        char[] chars = characterSource.readNumber();
+        Object value = null;
+
+        if (CharScanner.hasDecimalChar(chars, negative)) {
+            value = CharScanner.parseBigDecimal(chars);
+        } else if (CharScanner.isInteger(chars)) {
+            value = CharScanner.parseInt(chars);
+        } else if (CharScanner.isLong(chars)) {
+            value = CharScanner.parseLong(chars);
+        }
+
+        return value;
+    }
+
+    protected static final char[] NULL = Chr.chars("null");
+
+    protected final Object decodeNull() {
+        if (!characterSource.consumeIfMatch(NULL)) {
+            throw new JsonException(exceptionDetails("null not parse properly"));
+        }
+        return null;
+    }
+
+    protected static final char[] TRUE = Chr.chars("true");
+
+    protected final boolean decodeTrue() {
+        if (characterSource.consumeIfMatch(TRUE)) {
+            return true;
+        } else {
+            throw new JsonException(exceptionDetails("true not parsed properly"));
+        }
+    }
+
+    protected static char[] FALSE = Chr.chars("false");
+
+    protected final boolean decodeFalse() {
+        if (characterSource.consumeIfMatch(FALSE)) {
+            return false;
+        } else {
+            throw new JsonException(exceptionDetails("false not parsed properly"));
+        }
+    }
+
+    private CharBuf builder = CharBuf.create(20);
+
+    private String decodeString() {
+        CharacterSource characterSource = this.characterSource;
+
+        characterSource.nextChar();
+
+        char[] chars = characterSource.findNextChar('"', '\\');
+
+        String value = null;
+        if (characterSource.hadEscape()) {
+            value = builder.decodeJsonString(chars).toString();
+            builder.recycle();
+        } else {
+            value = new String(chars);
+        }
+
+        return value;
+    }
+
+    protected final List decodeJsonArray() {
+        ArrayList<Object> list = null;
+
+        boolean foundEnd = false;
+        try {
+            CharacterSource characterSource = this.characterSource;
+
+            if (this.characterSource.currentChar() == '[') {
+                characterSource.nextChar();
+            }
+
+            characterSource.skipWhiteSpace();
+
+        /* the list might be empty  */
+            if (this.characterSource.currentChar() == ']') {
+                characterSource.nextChar();
+                return new ArrayList();
+            }
+
+            list = new ArrayList();
+
+            do {
+                characterSource.skipWhiteSpace();
+
+                Object arrayItem = decodeValue();
+
+                list.add(arrayItem);
+
+                characterSource.skipWhiteSpace();
+
+                int c = characterSource.currentChar();
+
+                if (c == COMMA) {
+                    characterSource.nextChar();
+                    continue;
+                } else if (c == CLOSED_BRACKET) {
+                    foundEnd = true;
+                    characterSource.nextChar();
+                    break;
+                } else {
+                    String charString = charDescription(c);
+
+                    complain(
+                            String.format("expecting a ',' or a ']', " +
+                                    " but got \nthe current character of  %s " +
+                                    " on array index of %s \n", charString, list.size())
+                    );
+
+                }
+            } while (characterSource.hasChar());
+        } catch (Exception ex) {
+            throw new JsonException(exceptionDetails("Unexpected issue"), ex);
+        }
+
+        if (!foundEnd) {
+            throw new JsonException(exceptionDetails("Could not find end of JSON array"));
+        }
+        return list;
+    }
+
+    public Object parse(Reader reader) {
+        characterSource = new ReaderCharacterSource(reader);
+        return this.decodeValue();
+    }
+
+    public Object parse(char[] chars) {
+        return parse(new StringReader(new String(chars)));
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonStringDecoder.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonStringDecoder.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonStringDecoder.java
new file mode 100644
index 0000000..a53c9fa
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonStringDecoder.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Richard Hightower
+ */
+public class JsonStringDecoder {
+
+    public static String decode(char[] chars, int start, int to) {
+        if (!Chr.contains(chars, '\\', start, to - start)) {
+            return new String(chars, start, to - start);
+        }
+        return decodeForSure(chars, start, to);
+    }
+
+    public static String decodeForSure(char[] chars, int start, int to) {
+        CharBuf builder = CharBuf.create(to - start);
+        builder.decodeJsonString(chars, start, to);
+        return builder.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyMap.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyMap.java
new file mode 100644
index 0000000..81da4d3
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyMap.java
@@ -0,0 +1,205 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.lang.reflect.Array;
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * This maps only builds once you ask for a key for the first time.
+ * It is designed to not incur the overhead of creating a map unless needed.
+ *
+ * @author Rick Hightower
+ */
+public class LazyMap extends AbstractMap<String, Object> {
+
+    static final String JDK_MAP_ALTHASHING_SYSPROP = System.getProperty("jdk.map.althashing.threshold");
+
+    /* Holds the actual map that will be lazily created. */
+    private Map<String, Object> map;
+    /* The size of the map. */
+    private int size;
+    /* The keys  stored in the map. */
+    private String[] keys;
+    /* The values stored in the map. */
+    private Object[] values;
+
+    public LazyMap() {
+        keys = new String[5];
+        values = new Object[5];
+    }
+
+    public LazyMap(int initialSize) {
+        keys = new String[initialSize];
+        values = new Object[initialSize];
+    }
+
+    public Object put(String key, Object value) {
+        if (map == null) {
+            for (int i = 0; i < size; i++) {
+                String curKey = keys[i];
+                if ((key == null && curKey == null)
+                     || (key != null && key.equals(curKey))) {
+                    Object val = values[i];
+                    keys[i] = key;
+                    values[i] = value;
+                    return val;
+                }
+            }
+            keys[size] = key;
+            values[size] = value;
+            size++;
+            if (size == keys.length) {
+                keys = grow(keys);
+                values = grow(values);
+            }
+            return null;
+        } else {
+            return map.put(key, value);
+        }
+    }
+
+    public Set<Entry<String, Object>> entrySet() {
+        buildIfNeeded();
+        return map.entrySet();
+    }
+
+    public int size() {
+        if (map == null) {
+            return size;
+        } else {
+            return map.size();
+        }
+    }
+
+    public boolean isEmpty() {
+        if (map == null) {
+            return size == 0;
+        } else {
+            return map.isEmpty();
+        }
+    }
+
+    public boolean containsValue(Object value) {
+        buildIfNeeded();
+        return map.containsValue(value);
+    }
+
+    public boolean containsKey(Object key) {
+        buildIfNeeded();
+        return map.containsKey(key);
+    }
+
+    public Object get(Object key) {
+        buildIfNeeded();
+        return map.get(key);
+    }
+
+    private void buildIfNeeded() {
+        if (map == null) {
+            // added to avoid hash collision attack
+            if (Sys.is1_8OrLater() || (Sys.is1_7() && JDK_MAP_ALTHASHING_SYSPROP != null)) {
+                map = new LinkedHashMap<String, Object>(size, 0.01f);
+            } else {
+                map = new TreeMap<String, Object>();
+            }
+
+            for (int index = 0; index < size; index++) {
+                map.put(keys[index], values[index]);
+            }
+            this.keys = null;
+            this.values = null;
+        }
+    }
+
+    public Object remove(Object key) {
+        buildIfNeeded();
+        return map.remove(key);
+    }
+
+    public void putAll(Map m) {
+        buildIfNeeded();
+        map.putAll(m);
+    }
+
+    public void clear() {
+        if (map == null) {
+            size = 0;
+        } else {
+            map.clear();
+        }
+    }
+
+    public Set<String> keySet() {
+        buildIfNeeded();
+        return map.keySet();
+    }
+
+    public Collection<Object> values() {
+        buildIfNeeded();
+        return map.values();
+    }
+
+    public boolean equals(Object o) {
+        buildIfNeeded();
+        return map.equals(o);
+    }
+
+    public int hashCode() {
+        buildIfNeeded();
+        return map.hashCode();
+    }
+
+    public String toString() {
+        buildIfNeeded();
+        return map.toString();
+    }
+
+    protected Object clone() throws CloneNotSupportedException {
+        if (map == null) {
+            return null;
+        } else {
+            if (map instanceof LinkedHashMap) {
+                return ((LinkedHashMap) map).clone();
+            } else {
+                return new LinkedHashMap(this);
+            }
+        }
+    }
+
+    public LazyMap clearAndCopy() {
+        LazyMap map = new LazyMap();
+        for (int index = 0; index < size; index++) {
+            map.put(keys[index], values[index]);
+        }
+        size = 0;
+        return map;
+    }
+
+    public static <V> V[] grow(V[] array) {
+        Object newArray = Array.newInstance(array.getClass().getComponentType(), array.length * 2);
+        System.arraycopy(array, 0, newArray, 0, array.length);
+        return (V[]) newArray;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyValueMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyValueMap.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyValueMap.java
new file mode 100644
index 0000000..7692388
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyValueMap.java
@@ -0,0 +1,247 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+
+/**
+ * This class is important to the performance of the parser.
+ * It stores Value objects in a map where they are evaluated lazily.
+ * This is great for JSONPath types of application, and Object Serialization but not for maps that are going to be stored in a cache.
+ * <p/>
+ * This is because the Value construct is a type of index overlay that merely tracks where the token is located in the buffer,
+ * and what if any thing we noted about it (like can be converted to a decimal number, etc.).
+ * <p/>
+ * To mitigate memory leaks this class along with CharSequenceValue implement two constructs, namely,
+ * chop,  and lazyChop.
+ * <p/>
+ * A chop is when we convert backing buffer of a Value object into a smaller buffer.
+ * A lazyChop is when we do a chop but only when a get operation is called.
+ * <p/>
+ * The lazyChop is performed on the tree that is touched by the JSONPath expression or its ilk.
+ * <p/>
+ * The chop operation can be done during parsing or lazily by storing the values in this construct.
+ *
+ * @author Rick Hightower (insane chipmonk)
+ */
+public class LazyValueMap extends AbstractMap<String, Object> implements ValueMap<String, Object> {
+
+    /**
+     * holds the map that gets lazily created on first access.
+     */
+    private Map<String, Object> map = null;
+    /**
+     * holds the list of items that we are managing.
+     */
+    private Entry<String, Value>[] items;
+    /**
+     * Holds the current number mapping managed by this map.
+     */
+    private int len = 0;
+    /**
+     * Holds whether or not we ae in lazy chop mode or not.
+     */
+    private final boolean lazyChop;
+
+    /**
+     * Keep track if this map has already been chopped so we don't waste time trying to chop it again.
+     */
+    boolean mapChopped = false;
+
+    public LazyValueMap(boolean lazyChop) {
+        this.items = new Entry[5];
+        this.lazyChop = lazyChop;
+    }
+
+    public LazyValueMap(boolean lazyChop, int initialSize) {
+        this.items = new Entry[initialSize];
+        this.lazyChop = lazyChop;
+    }
+
+    /**
+     * Adds a new MapItemValue to the mapping.
+     *
+     * @param miv miv we are adding.
+     */
+    public final void add(MapItemValue miv) {
+        if (len >= items.length) {
+            items = LazyMap.grow(items);
+        }
+        items[len] = miv;
+        len++;
+    }
+
+    /**
+     * Gets the item by key from the mapping.
+     *
+     * @param key to lookup
+     * @return the item for the given key
+     */
+    public final Object get(Object key) {
+        Object object = null;
+
+        /* if the map is null, then we create it. */
+        if (map == null) {
+            buildMap();
+        }
+        object = map.get(key);
+
+        lazyChopIfNeeded(object);
+        return object;
+    }
+
+    /**
+     * If in lazy chop mode, and the object is a Lazy Value Map or a ValueList
+     * then we force a chop operation for each of its items.
+     */
+    private void lazyChopIfNeeded(Object object) {
+        if (lazyChop) {
+            if (object instanceof LazyValueMap) {
+                LazyValueMap m = (LazyValueMap) object;
+                m.chopMap();
+            } else if (object instanceof ValueList) {
+                ValueList list = (ValueList) object;
+                list.chopList();
+            }
+        }
+    }
+
+    /**
+     * Chop this map.
+     */
+    public final void chopMap() {
+        /* if it has been chopped then you have to return. */
+        if (mapChopped) {
+            return;
+        }
+        mapChopped = true;
+
+        /* If the internal map was not create yet, don't. We can chop the value w/o creating the internal map.*/
+        if (this.map == null) {
+            for (int index = 0; index < len; index++) {
+                MapItemValue entry = (MapItemValue) items[index];
+
+                Value value = entry.getValue();
+                if (value == null) continue;
+                if (value.isContainer()) {
+                    chopContainer(value);
+                } else {
+                    value.chop();
+                }
+            }
+        } else {
+            /* Iterate through the map and do the same thing. Make sure children and children of children are chopped.  */
+            for (Map.Entry<String, Object> entry : map.entrySet()) {
+
+                Object object = entry.getValue();
+                if (object instanceof Value) {
+                    Value value = (Value) object;
+                    if (value.isContainer()) {
+                        chopContainer(value);
+                    } else {
+                        value.chop();
+                    }
+                } else if (object instanceof LazyValueMap) {
+                    LazyValueMap m = (LazyValueMap) object;
+                    m.chopMap();
+                } else if (object instanceof ValueList) {
+                    ValueList list = (ValueList) object;
+                    list.chopList();
+                }
+            }
+        }
+    }
+
+    /* We need to chop up this child container. */
+    private static void chopContainer(Value value) {
+        Object obj = value.toValue();
+        if (obj instanceof LazyValueMap) {
+            LazyValueMap map = (LazyValueMap) obj;
+            map.chopMap();
+        } else if (obj instanceof ValueList) {
+            ValueList list = (ValueList) obj;
+            list.chopList();
+        }
+    }
+
+    public Value put(String key, Object value) {
+        die("Not that kind of map");
+        return null;
+    }
+
+    public Set<Entry<String, Object>> entrySet() {
+        if (map == null) {
+            buildMap();
+        }
+        return map.entrySet();
+    }
+
+    private void buildMap() {
+        // added to avoid hash collision attack
+        if (Sys.is1_8OrLater() || (Sys.is1_7() && LazyMap.JDK_MAP_ALTHASHING_SYSPROP != null)) {
+            map = new HashMap<String, Object>(items.length);
+        } else {
+            map = new TreeMap<String, Object>();
+        }
+
+        for (Entry<String, Value> miv : items) {
+            if (miv == null) {
+                break;
+            }
+            map.put(miv.getKey(), miv.getValue().toValue());
+        }
+
+        len = 0;
+        items = null;
+    }
+
+    public Collection<Object> values() {
+        if (map == null) buildMap();
+        return map.values();
+    }
+
+    public int size() {
+        if (map == null) buildMap();
+        return map.size();
+    }
+
+    public String toString() {
+        if (map == null) buildMap();
+        return map.toString();
+    }
+
+    public int len() {
+        return len;
+    }
+
+    public boolean hydrated() {
+        return map != null;
+    }
+
+    public Entry<String, Value>[] items() {
+        return items;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/MapItemValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/MapItemValue.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/MapItemValue.java
new file mode 100644
index 0000000..8a10c59
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/MapItemValue.java
@@ -0,0 +1,80 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+
+/**
+ * This holds a mapping from value key to value value to maximize laziness.
+ *
+ * @author Rick Hightower
+ */
+public class MapItemValue implements Map.Entry<String, Value> {
+
+    final Value name;
+    final Value value;
+
+    private String key = null;
+
+    private static final boolean internKeys = Boolean.parseBoolean(System.getProperty("groovy.json.implementation.internKeys", "false"));
+
+    protected static ConcurrentHashMap<String, String> internedKeysCache;
+
+    static {
+        if (internKeys) {
+            internedKeysCache = new ConcurrentHashMap<String, String>();
+        }
+    }
+
+    public MapItemValue(Value name, Value value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    public String getKey() {
+        if (key == null) {
+            if (internKeys) {
+                key = name.toString();
+
+                String keyPrime = internedKeysCache.get(key);
+                if (keyPrime == null) {
+                    key = key.intern();
+                    internedKeysCache.put(key, key);
+                } else {
+                    key = keyPrime;
+                }
+            } else {
+                key = name.toString();
+            }
+        }
+        return key;
+    }
+
+    public Value getValue() {
+        return value;
+    }
+
+    public Value setValue(Value value) {
+        Exceptions.die("not that kind of Entry");
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/NumberValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/NumberValue.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/NumberValue.java
new file mode 100644
index 0000000..525010e
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/NumberValue.java
@@ -0,0 +1,219 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Date;
+
+import static java.lang.Boolean.parseBoolean;
+import static org.apache.groovy.json.internal.CharScanner.isInteger;
+import static org.apache.groovy.json.internal.CharScanner.parseDouble;
+import static org.apache.groovy.json.internal.CharScanner.parseFloat;
+import static org.apache.groovy.json.internal.CharScanner.parseIntFromTo;
+import static org.apache.groovy.json.internal.CharScanner.parseLongFromTo;
+import static org.apache.groovy.json.internal.Exceptions.die;
+import static org.apache.groovy.json.internal.Exceptions.sputs;
+
+/**
+ * @author Rick Hightower
+ */
+public class NumberValue extends java.lang.Number implements Value {
+
+    private char[] buffer;
+    private boolean chopped;
+    private int startIndex;
+    private int endIndex;
+    private final Type type;
+    private Object value;
+
+    public NumberValue(Type type) {
+        this.type = type;
+    }
+
+    public NumberValue() {
+        this.type = null;
+    }
+
+    public NumberValue(boolean chop, Type type, int startIndex, int endIndex, char[] buffer) {
+        this.type = type;
+
+        try {
+            if (chop) {
+                this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
+                this.startIndex = 0;
+                this.endIndex = this.buffer.length;
+                chopped = true;
+            } else {
+                this.startIndex = startIndex;
+                this.endIndex = endIndex;
+                this.buffer = buffer;
+            }
+        } catch (Exception ex) {
+            Exceptions.handle(sputs("exception", ex, "start", startIndex, "end", endIndex), ex);
+        }
+
+        // Check for a single minus now, rather than finding out later during lazy parsing.
+        if (this.endIndex - this.startIndex == 1 && this.buffer[this.startIndex] == '-') {
+            die("A single minus is not a valid number");
+        }
+
+    }
+
+    public String toString() {
+        if (startIndex == 0 && endIndex == buffer.length) {
+            return FastStringUtils.noCopyStringFromChars(buffer);
+        } else {
+            return new String(buffer, startIndex, (endIndex - startIndex));
+        }
+    }
+
+    public final Object toValue() {
+        return value != null ? value : (value = doToValue());
+    }
+
+    public <T extends Enum> T toEnum(Class<T> cls) {
+        return toEnum(cls, intValue());
+    }
+
+    public static <T extends Enum> T toEnum(Class<T> cls, int value) {
+        T[] enumConstants = cls.getEnumConstants();
+        for (T e : enumConstants) {
+            if (e.ordinal() == value) {
+                return e;
+            }
+        }
+        die("Can't convert ordinal value " + value + " into enum of type " + cls);
+        return null;
+    }
+
+    public boolean isContainer() {
+        return false;
+    }
+
+    private Object doToValue() {
+        switch (type) {
+            case DOUBLE:
+                return bigDecimalValue();
+            case INTEGER:
+                if (isInteger(buffer, startIndex, endIndex - startIndex)) {
+                    return intValue();
+                } else {
+                    return longValue();
+                }
+        }
+        die();
+        return null;
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof Value)) return false;
+
+        NumberValue value1 = (NumberValue) o;
+
+        if (endIndex != value1.endIndex) return false;
+        if (startIndex != value1.startIndex) return false;
+        if (!Arrays.equals(buffer, value1.buffer)) return false;
+        if (type != value1.type) return false;
+        return value != null ? value.equals(value1.value) : value1.value == null;
+
+    }
+
+    public int hashCode() {
+        int result = type != null ? type.hashCode() : 0;
+        result = 31 * result + (buffer != null ? Arrays.hashCode(buffer) : 0);
+        result = 31 * result + startIndex;
+        result = 31 * result + endIndex;
+        result = 31 * result + (value != null ? value.hashCode() : 0);
+        return result;
+    }
+
+    public BigDecimal bigDecimalValue() {
+        try {
+            return new BigDecimal(buffer, startIndex, endIndex - startIndex);
+        } catch (NumberFormatException e) {
+            throw new JsonException("unable to parse " + new String(buffer, startIndex, endIndex - startIndex), e);
+        }
+    }
+
+    public BigInteger bigIntegerValue() {
+        return new BigInteger(toString());
+    }
+
+    public String stringValue() {
+        return toString();
+    }
+
+    public String stringValueEncoded() {
+        return toString();
+    }
+
+    public Date dateValue() {
+        return new Date(Dates.utc(longValue()));
+    }
+
+    public int intValue() {
+        return parseIntFromTo(buffer, startIndex, endIndex);
+    }
+
+    public long longValue() {
+        if (isInteger(buffer, startIndex, endIndex - startIndex)) {
+            return parseIntFromTo(buffer, startIndex, endIndex);
+        } else {
+            return parseLongFromTo(buffer, startIndex, endIndex);
+        }
+    }
+
+    public byte byteValue() {
+        return (byte) intValue();
+    }
+
+    public short shortValue() {
+        return (short) intValue();
+    }
+
+    public double doubleValue() {
+        return parseDouble(this.buffer, startIndex, endIndex);
+    }
+
+    public boolean booleanValue() {
+        return parseBoolean(toString());
+    }
+
+    public float floatValue() {
+        return parseFloat(this.buffer, startIndex, endIndex);
+    }
+
+    public final void chop() {
+        if (!chopped) {
+            this.chopped = true;
+            this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
+            this.startIndex = 0;
+            this.endIndex = this.buffer.length;
+        }
+    }
+
+    public char charValue() {
+        return buffer[startIndex];
+    }
+}