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/02/28 11:37:51 UTC

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

http://git-wip-us.apache.org/repos/asf/groovy/blob/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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/5a3f9996/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
+    }
+}