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 2021/12/16 03:52:07 UTC

[groovy] branch master updated: GROOVY-10412: Refactor: split formatting methods out of InvokerHelper

This is an automated email from the ASF dual-hosted git repository.

paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new dafd139  GROOVY-10412: Refactor: split formatting methods out of InvokerHelper
dafd139 is described below

commit dafd1396621757958043799ed25d658dc1bb3d86
Author: Paul King <pa...@asert.com.au>
AuthorDate: Tue Dec 14 21:58:31 2021 +1000

    GROOVY-10412: Refactor: split formatting methods out of InvokerHelper
---
 src/main/java/groovy/inspect/Inspector.java        |   5 +-
 src/main/java/groovy/io/GroovyPrintStream.java     |   6 +-
 src/main/java/groovy/io/GroovyPrintWriter.java     |   6 +-
 src/main/java/groovy/lang/EmptyRange.java          |   4 +-
 .../lang/IncorrectClosureArgumentsException.java   |   6 +-
 src/main/java/groovy/lang/MetaClassImpl.java       |  13 +-
 src/main/java/groovy/lang/MetaMethod.java          |   8 +-
 .../java/groovy/lang/MissingMethodException.java   |   6 +-
 src/main/java/groovy/lang/NumberRange.java         |   4 +-
 src/main/java/groovy/lang/ObjectRange.java         |   5 +-
 src/main/java/groovy/util/ConfigObject.java        |  16 +-
 src/main/java/groovy/util/NodePrinter.java         |   6 +-
 .../groovy/reflection/CachedConstructor.java       |   4 +-
 .../groovy/runtime/DefaultGroovyMethods.java       |  50 +-
 .../org/codehaus/groovy/runtime/FormatHelper.java  | 477 ++++++++++++++++++
 .../org/codehaus/groovy/runtime/GStringUtil.java   |   4 +-
 .../codehaus/groovy/runtime/IOGroovyMethods.java   |   4 +-
 .../org/codehaus/groovy/runtime/InvokerHelper.java | 544 +++++----------------
 .../codehaus/groovy/runtime/MetaClassHelper.java   |   2 +-
 .../groovy/runtime/ResourceGroovyMethods.java      |   6 +-
 .../groovy/runtime/StringGroovyMethods.java        |  10 +-
 .../runtime/powerassert/AssertionRenderer.java     |   4 +-
 .../typehandling/DefaultTypeTransformation.java    |   3 +-
 .../groovy/tools/javac/JavaStubGenerator.java      |   4 +-
 src/test/groovy/lang/GStringTest.java              |   6 +-
 .../groovy/runtime/DefaultGroovyMethodsTest.groovy |   2 +-
 .../groovy/runtime/InvokeConstructorTest.java      |   2 +-
 .../codehaus/groovy/runtime/InvokeMethodTest.java  |   2 +-
 .../runtime/InvokerHelperFormattingTest.groovy     | 156 +++---
 .../src/test/groovy/groovy/ant/SpoofTask.java      |   4 +-
 .../groovy/console/ui/OutputTransforms.groovy      |   4 +-
 .../org/apache/groovy/groovysh/Groovysh.groovy     |   4 +-
 .../org/apache/groovy/groovysh/Interpreter.groovy  |   4 +-
 .../groovy/org/apache/groovy/groovysh/Shell.groovy |   4 +-
 .../groovy/groovysh/commands/RecordCommand.groovy  |   4 +-
 .../groovy/groovysh/commands/ShowCommand.groovy    |   4 +-
 .../groovy/groovysh/util/SimpleCompleter.groovy    |   4 +-
 .../groovy/nio/extensions/NioExtensions.java       |   5 +-
 .../main/groovy/groovy/text/XmlTemplateEngine.java |   3 +-
 .../src/main/java/groovy/test/GroovyTestCase.java  |   3 +-
 .../src/main/java/groovy/xml/XmlNodePrinter.java   |   6 +-
 41 files changed, 786 insertions(+), 628 deletions(-)

diff --git a/src/main/java/groovy/inspect/Inspector.java b/src/main/java/groovy/inspect/Inspector.java
index 25b17f2..6f5304c 100644
--- a/src/main/java/groovy/inspect/Inspector.java
+++ b/src/main/java/groovy/inspect/Inspector.java
@@ -23,6 +23,7 @@ import groovy.lang.MetaClass;
 import groovy.lang.MetaMethod;
 import groovy.lang.PropertyValue;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.InvokerHelper;
 
 import java.io.PrintStream;
@@ -187,7 +188,7 @@ public class Inspector {
         result[MEMBER_TYPE_IDX] = shortName(field.getType());
         result[MEMBER_NAME_IDX] = field.getName();
         try {
-            result[MEMBER_VALUE_IDX] = InvokerHelper.inspect(field.get(objectUnderInspection));
+            result[MEMBER_VALUE_IDX] = FormatHelper.inspect(field.get(objectUnderInspection));
         } catch (IllegalAccessException e) {
             result[MEMBER_VALUE_IDX] = NOT_APPLICABLE;
         }
@@ -202,7 +203,7 @@ public class Inspector {
         result[MEMBER_TYPE_IDX] = shortName(pv.getType());
         result[MEMBER_NAME_IDX] = pv.getName();
         try {
-            result[MEMBER_VALUE_IDX] = InvokerHelper.inspect(pv.getValue());
+            result[MEMBER_VALUE_IDX] = FormatHelper.inspect(pv.getValue());
         } catch (Exception e) {
             result[MEMBER_VALUE_IDX] = NOT_APPLICABLE;
         }
diff --git a/src/main/java/groovy/io/GroovyPrintStream.java b/src/main/java/groovy/io/GroovyPrintStream.java
index cd6818f..b3eac26 100644
--- a/src/main/java/groovy/io/GroovyPrintStream.java
+++ b/src/main/java/groovy/io/GroovyPrintStream.java
@@ -18,7 +18,7 @@
  */
 package groovy.io;
 
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -111,7 +111,7 @@ public class GroovyPrintStream extends PrintStream {
      */
     @Override
     public void print(Object obj) {
-        print(InvokerHelper.toString(obj));
+        print(FormatHelper.toString(obj));
     }
 
     /**
@@ -121,7 +121,7 @@ public class GroovyPrintStream extends PrintStream {
      */
     @Override
     public void println(Object obj) {
-        println(InvokerHelper.toString(obj));
+        println(FormatHelper.toString(obj));
     }
 
 }
diff --git a/src/main/java/groovy/io/GroovyPrintWriter.java b/src/main/java/groovy/io/GroovyPrintWriter.java
index a3fdb66..aca1011 100644
--- a/src/main/java/groovy/io/GroovyPrintWriter.java
+++ b/src/main/java/groovy/io/GroovyPrintWriter.java
@@ -18,7 +18,7 @@
  */
 package groovy.io;
 
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -71,7 +71,7 @@ public class GroovyPrintWriter extends PrintWriter {
 
     @Override
     public void print(Object x) {
-        write(InvokerHelper.toString(x));
+        write(FormatHelper.toString(x));
     }
 
     @Override
@@ -80,6 +80,6 @@ public class GroovyPrintWriter extends PrintWriter {
         // String.valueOf(x) rather than call print(x).
         // Probably to improve performance by doing the conversion outside the lock.
         // This will do the same thing for us, and we don't have to have access to the lock.
-        println(InvokerHelper.toString(x));
+        println(FormatHelper.toString(x));
     }
 }
diff --git a/src/main/java/groovy/lang/EmptyRange.java b/src/main/java/groovy/lang/EmptyRange.java
index a6df966..a6867d7 100644
--- a/src/main/java/groovy/lang/EmptyRange.java
+++ b/src/main/java/groovy/lang/EmptyRange.java
@@ -18,7 +18,7 @@
  */
 package groovy.lang;
 
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 
 import java.util.AbstractList;
 import java.util.ArrayList;
@@ -85,7 +85,7 @@ public class EmptyRange<T extends Comparable> extends AbstractList<T> implements
      */
     @Override
     public String inspect() {
-        return InvokerHelper.inspect(at) + "..<" + InvokerHelper.inspect(at);
+        return FormatHelper.inspect(at) + "..<" + FormatHelper.inspect(at);
     }
 
     /**
diff --git a/src/main/java/groovy/lang/IncorrectClosureArgumentsException.java b/src/main/java/groovy/lang/IncorrectClosureArgumentsException.java
index a65e71e..9877000 100644
--- a/src/main/java/groovy/lang/IncorrectClosureArgumentsException.java
+++ b/src/main/java/groovy/lang/IncorrectClosureArgumentsException.java
@@ -18,7 +18,7 @@
  */
 package groovy.lang;
 
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 
 /**
  * An exception occurred when invoking a Closure with the wrong number and/or
@@ -36,9 +36,9 @@ public class IncorrectClosureArgumentsException extends GroovyRuntimeException {
             "Incorrect arguments to closure: "
                 + closure
                 + ". Expected: "
-                + InvokerHelper.toString(expected)
+                + FormatHelper.toString(expected)
                 + ", actual: "
-                + InvokerHelper.toString(arguments));
+                + FormatHelper.toString(arguments));
         this.closure = closure;
         this.arguments = arguments;
         this.expected = expected;
diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java
index 9e6199c..93f78ee 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -43,6 +43,7 @@ import org.codehaus.groovy.runtime.ArrayUtil;
 import org.codehaus.groovy.runtime.ConvertedClosure;
 import org.codehaus.groovy.runtime.CurriedClosure;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.GeneratedClosure;
 import org.codehaus.groovy.runtime.GroovyCategorySupport;
 import org.codehaus.groovy.runtime.GroovyCategorySupport.CategoryMethod;
@@ -1757,7 +1758,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
             throw new GroovyRuntimeException(
                     "Could not find matching constructor for: "
                             + theClass.getName()
-                            + "(" + InvokerHelper.toTypeString(arguments) + ")");
+                            + "(" + FormatHelper.toTypeString(arguments) + ")");
         }
         return constructor;
     }
@@ -1896,14 +1897,14 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         // chooseMethod allows fuzzy matching implicit null case but we don't want that here
         // code here handles inner class case but we currently don't do fuzzy matching for inner classes
         if (res instanceof ParameterTypes && ((ParameterTypes) res).getParameterTypes().length == origArgTypes.length) {
-            String prettyOrigArgs = InvokerHelper.toTypeString(origArgs);
+            String prettyOrigArgs = FormatHelper.toTypeString(origArgs);
             if (prettyOrigArgs.endsWith("LinkedHashMap")) {
                 prettyOrigArgs = prettyOrigArgs.replaceFirst("LinkedHashMap$", "Map");
             }
             throw new GroovyRuntimeException(
                     "Could not find named-arg compatible constructor. Expecting one of:\n"
                             + theClass.getName() + "(" + prettyOrigArgs + ")\n"
-                            + theClass.getName() + "(" + InvokerHelper.toTypeString(args) + ")"
+                            + theClass.getName() + "(" + FormatHelper.toTypeString(args) + ")"
             );
         }
         return res;
@@ -1935,7 +1936,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         throw new GroovyRuntimeException(
                 "Could not find matching constructor for: "
                         + theClass.getName()
-                        + "(" + InvokerHelper.toTypeString(arguments) + ")");
+                        + "(" + FormatHelper.toTypeString(arguments) + ")");
     }
 
     /**
@@ -3429,11 +3430,11 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         StringBuilder msg = new StringBuilder("Ambiguous method overloading for method ");
         msg.append(theClassName).append("#").append(name)
                 .append(".\nCannot resolve which method to invoke for ")
-                .append(InvokerHelper.toString(arguments))
+                .append(FormatHelper.toString(arguments))
                 .append(" due to overlapping prototypes between:");
         for (final Object match : matches) {
             CachedClass[] types = ((ParameterTypes) match).getParameterTypes();
-            msg.append("\n\t").append(InvokerHelper.toString(types));
+            msg.append("\n\t").append(FormatHelper.toString(types));
         }
         return msg.toString();
     }
diff --git a/src/main/java/groovy/lang/MetaMethod.java b/src/main/java/groovy/lang/MetaMethod.java
index e6d96da..be98d4b 100644
--- a/src/main/java/groovy/lang/MetaMethod.java
+++ b/src/main/java/groovy/lang/MetaMethod.java
@@ -21,7 +21,7 @@ package groovy.lang;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.reflection.CachedClass;
 import org.codehaus.groovy.reflection.ParameterTypes;
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.MetaClassHelper;
 
 import java.lang.reflect.Modifier;
@@ -100,9 +100,9 @@ public abstract class MetaMethod extends ParameterTypes implements Cloneable {
                     "Parameters to method: "
                     + getName()
                     + " do not match types: "
-                    + InvokerHelper.toString(getParameterTypes())
+                    + FormatHelper.toString(getParameterTypes())
                     + " for arguments: "
-                    + InvokerHelper.toString(arguments));
+                    + FormatHelper.toString(arguments));
         }
     }
 
@@ -152,7 +152,7 @@ public abstract class MetaMethod extends ParameterTypes implements Cloneable {
             + "[name: "
             + getName()
             + " params: "
-            + InvokerHelper.toString(getParameterTypes())
+            + FormatHelper.toString(getParameterTypes())
             + " returns: "
             + getReturnType()
             + " owner: "
diff --git a/src/main/java/groovy/lang/MissingMethodException.java b/src/main/java/groovy/lang/MissingMethodException.java
index 6a9a857..43848f0 100644
--- a/src/main/java/groovy/lang/MissingMethodException.java
+++ b/src/main/java/groovy/lang/MissingMethodException.java
@@ -18,7 +18,7 @@
  */
 package groovy.lang;
 
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.MethodRankHelper;
 
 /**
@@ -60,9 +60,9 @@ public class MissingMethodException extends GroovyRuntimeException {
                 + "."
                 + method
                 + "() is applicable for argument types: ("
-                + InvokerHelper.toTypeString(arguments, 60)
+                + FormatHelper.toTypeString(arguments, 60)
                 + ") values: "
-                + InvokerHelper.toArrayString(arguments, 60, true)
+                + FormatHelper.toArrayString(arguments, 60, true)
                 + (type != null ? MethodRankHelper.getMethodSuggestionString(method, type, arguments) : "");
     }
 
diff --git a/src/main/java/groovy/lang/NumberRange.java b/src/main/java/groovy/lang/NumberRange.java
index fd266db..8335023 100644
--- a/src/main/java/groovy/lang/NumberRange.java
+++ b/src/main/java/groovy/lang/NumberRange.java
@@ -18,7 +18,7 @@
  */
 package groovy.lang;
 
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.IteratorClosureAdapter;
 import org.codehaus.groovy.runtime.RangeInfo;
 import org.codehaus.groovy.runtime.typehandling.NumberMath;
@@ -548,7 +548,7 @@ public class NumberRange extends AbstractList<Comparable> implements Range<Compa
 
     @Override
     public String inspect() {
-        return getToString(InvokerHelper.inspect(to), InvokerHelper.inspect(from));
+        return getToString(FormatHelper.inspect(to), FormatHelper.inspect(from));
     }
 
     private String getToString(String toText, String fromText) {
diff --git a/src/main/java/groovy/lang/ObjectRange.java b/src/main/java/groovy/lang/ObjectRange.java
index c430aa4..5ce3509 100644
--- a/src/main/java/groovy/lang/ObjectRange.java
+++ b/src/main/java/groovy/lang/ObjectRange.java
@@ -19,6 +19,7 @@
 package groovy.lang;
 
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.runtime.IteratorClosureAdapter;
 import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
@@ -372,8 +373,8 @@ public class ObjectRange extends AbstractList<Comparable> implements Range<Compa
 
     @Override
     public String inspect() {
-        final String toText = InvokerHelper.inspect(to);
-        final String fromText = InvokerHelper.inspect(from);
+        final String toText = FormatHelper.inspect(to);
+        final String fromText = FormatHelper.inspect(from);
         return reverse ? "" + toText + ".." + fromText : "" + fromText + ".." + toText;
     }
 
diff --git a/src/main/java/groovy/util/ConfigObject.java b/src/main/java/groovy/util/ConfigObject.java
index 12835f3..5fcf95a 100644
--- a/src/main/java/groovy/util/ConfigObject.java
+++ b/src/main/java/groovy/util/ConfigObject.java
@@ -23,7 +23,7 @@ import groovy.lang.GroovyRuntimeException;
 import groovy.lang.Writable;
 import org.apache.groovy.io.StringBuilderWriter;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.StringGroovyMethods;
 import org.codehaus.groovy.syntax.Types;
 
@@ -232,7 +232,7 @@ public class ConfigObject extends GroovyObjectSupport implements Writable, Map,
 
                     if (configSize == 1 || DefaultGroovyMethods.asBoolean(dotsInKeys)) {
                         if (firstSize == 1 && firstValue instanceof ConfigObject) {
-                            key = KEYWORDS.contains(key) ? InvokerHelper.inspect(key) : key;
+                            key = KEYWORDS.contains(key) ? FormatHelper.inspect(key) : key;
                             String writePrefix = prefix + key + "." + firstKey + ".";
                             writeConfig(writePrefix, (ConfigObject) firstValue, out, tab, true);
                         } else if (!DefaultGroovyMethods.asBoolean(dotsInKeys) && firstValue instanceof ConfigObject) {
@@ -240,9 +240,9 @@ public class ConfigObject extends GroovyObjectSupport implements Writable, Map,
                         } else {
                             for (Object j : value.keySet()) {
                                 Object v2 = value.get(j);
-                                Object k2 = ((String) j).indexOf('.') > -1 ? InvokerHelper.inspect(j) : j;
+                                Object k2 = ((String) j).indexOf('.') > -1 ? FormatHelper.inspect(j) : j;
                                 if (v2 instanceof ConfigObject) {
-                                    key = KEYWORDS.contains(key) ? InvokerHelper.inspect(key) : key;
+                                    key = KEYWORDS.contains(key) ? FormatHelper.inspect(key) : key;
                                     writeConfig(prefix + key, (ConfigObject) v2, out, tab, false);
                                 } else {
                                     writeValue(key + "." + k2, space, prefix, v2, out);
@@ -262,15 +262,15 @@ public class ConfigObject extends GroovyObjectSupport implements Writable, Map,
     private static void writeValue(String key, String space, String prefix, Object value, BufferedWriter out) throws IOException {
 //        key = key.indexOf('.') > -1 ? InvokerHelper.inspect(key) : key;
         boolean isKeyword = KEYWORDS.contains(key);
-        key = isKeyword ? InvokerHelper.inspect(key) : key;
+        key = isKeyword ? FormatHelper.inspect(key) : key;
 
         if (!StringGroovyMethods.asBoolean(prefix) && isKeyword) prefix = "this.";
-        out.append(space).append(prefix).append(key).append('=').append(InvokerHelper.inspect(value));
+        out.append(space).append(prefix).append(key).append('=').append(FormatHelper.inspect(value));
         out.newLine();
     }
 
     private void writeNode(String key, String space, int tab, ConfigObject value, BufferedWriter out) throws IOException {
-        key = KEYWORDS.contains(key) ? InvokerHelper.inspect(key) : key;
+        key = KEYWORDS.contains(key) ? FormatHelper.inspect(key) : key;
         out.append(space).append(key).append(" {");
         out.newLine();
         writeConfig("", value, out, tab + 1, true);
@@ -427,7 +427,7 @@ public class ConfigObject extends GroovyObjectSupport implements Writable, Map,
     public String toString() {
         Writer sw = new StringBuilderWriter();
         try {
-            InvokerHelper.write(sw, this);
+            FormatHelper.write(sw, this);
         } catch (IOException e) {
             throw new GroovyRuntimeException(e);
         }
diff --git a/src/main/java/groovy/util/NodePrinter.java b/src/main/java/groovy/util/NodePrinter.java
index 27dd774..b513977 100644
--- a/src/main/java/groovy/util/NodePrinter.java
+++ b/src/main/java/groovy/util/NodePrinter.java
@@ -18,7 +18,7 @@
  */
 package groovy.util;
 
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
@@ -93,7 +93,7 @@ public class NodePrinter {
                     print((Node) value);
                 } else {
                     out.printIndent();
-                    out.println(InvokerHelper.toString(value));
+                    out.println(FormatHelper.toString(value));
                 }
             }
             out.decrementIndent();
@@ -118,7 +118,7 @@ public class NodePrinter {
             if (entry.getValue() instanceof String) {
                 out.print("'" + entry.getValue() + "'");
             } else {
-                out.print(InvokerHelper.toString(entry.getValue()));
+                out.print(FormatHelper.toString(entry.getValue()));
             }
         }
         out.print(")");
diff --git a/src/main/java/org/codehaus/groovy/reflection/CachedConstructor.java b/src/main/java/org/codehaus/groovy/reflection/CachedConstructor.java
index 1546bd4..c4261f3 100644
--- a/src/main/java/org/codehaus/groovy/reflection/CachedConstructor.java
+++ b/src/main/java/org/codehaus/groovy/reflection/CachedConstructor.java
@@ -19,7 +19,7 @@
 package org.codehaus.groovy.reflection;
 
 import groovy.lang.GroovyRuntimeException;
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.InvokerInvocationException;
 
 import java.lang.reflect.Constructor;
@@ -90,7 +90,7 @@ public class CachedConstructor extends ParameterTypes {
                 init
                         + constructor
                         + " with arguments: "
-                        + InvokerHelper.toString(argumentArray)
+                        + FormatHelper.toString(argumentArray)
                         + " reason: "
                         + e,
                 setReason ? e : null);
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index 6a3dd4a..610ac20 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -469,7 +469,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
                     buffer.append(field.getName());
                     buffer.append("=");
                     try {
-                        buffer.append(InvokerHelper.toString(field.get(self)));
+                        buffer.append(FormatHelper.toString(field.get(self)));
                     } catch (Exception e) {
                         buffer.append(e);
                     }
@@ -696,7 +696,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.0
      */
     public static String inspect(Object self) {
-        return InvokerHelper.inspect(self);
+        return FormatHelper.inspect(self);
     }
 
     /**
@@ -728,12 +728,12 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         // we won't get here if we are a PrintWriter
         if (self instanceof Writer) {
             try {
-                ((Writer) self).write(InvokerHelper.toString(value));
+                ((Writer) self).write(FormatHelper.toString(value));
             } catch (IOException e) {
                 // TODO: Should we have some unified function like PrintWriter.checkError()?
             }
         } else {
-            System.out.print(InvokerHelper.toString(value));
+            System.out.print(FormatHelper.toString(value));
         }
     }
 
@@ -745,7 +745,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.0
      */
     public static void print(PrintWriter self, Object value) {
-        self.print(InvokerHelper.toString(value));
+        self.print(FormatHelper.toString(value));
     }
 
     /**
@@ -756,7 +756,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static void print(PrintStream self, Object value) {
-        self.print(InvokerHelper.toString(value));
+        self.print(FormatHelper.toString(value));
     }
 
     /**
@@ -783,7 +783,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         if (out == null) {
             out = new PrintWriter(System.out);
         }
-        out.print(InvokerHelper.toString(self));
+        out.print(FormatHelper.toString(self));
     }
 
     /**
@@ -828,7 +828,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
             final PrintWriter pw = new GroovyPrintWriter((Writer) self);
             pw.println(value);
         } else {
-            System.out.println(InvokerHelper.toString(value));
+            System.out.println(FormatHelper.toString(value));
         }
     }
 
@@ -840,7 +840,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.0
      */
     public static void println(PrintWriter self, Object value) {
-        self.println(InvokerHelper.toString(value));
+        self.println(FormatHelper.toString(value));
     }
 
     /**
@@ -851,7 +851,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static void println(PrintStream self, Object value) {
-        self.println(InvokerHelper.toString(value));
+        self.println(FormatHelper.toString(value));
     }
 
     /**
@@ -878,7 +878,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         if (out == null) {
             out = new PrintWriter(System.out);
         }
-        out.println(InvokerHelper.toString(self));
+        out.println(FormatHelper.toString(self));
     }
 
     /**
@@ -6735,7 +6735,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
             } else {
                 buffer.append(separator);
             }
-            buffer.append(InvokerHelper.toString(value));
+            buffer.append(FormatHelper.toString(value));
         }
         return buffer.toString();
     }
@@ -15097,7 +15097,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static String toString(boolean[] self) {
-        return InvokerHelper.toString(self);
+        return FormatHelper.toString(self);
     }
 
     /**
@@ -15108,7 +15108,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static String toString(byte[] self) {
-        return InvokerHelper.toString(self);
+        return FormatHelper.toString(self);
     }
 
     /**
@@ -15119,7 +15119,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static String toString(char[] self) {
-        return InvokerHelper.toString(self);
+        return FormatHelper.toString(self);
     }
 
     /**
@@ -15130,7 +15130,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static String toString(short[] self) {
-        return InvokerHelper.toString(self);
+        return FormatHelper.toString(self);
     }
 
     /**
@@ -15141,7 +15141,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static String toString(int[] self) {
-        return InvokerHelper.toString(self);
+        return FormatHelper.toString(self);
     }
 
     /**
@@ -15152,7 +15152,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static String toString(long[] self) {
-        return InvokerHelper.toString(self);
+        return FormatHelper.toString(self);
     }
 
     /**
@@ -15163,7 +15163,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static String toString(float[] self) {
-        return InvokerHelper.toString(self);
+        return FormatHelper.toString(self);
     }
 
     /**
@@ -15174,7 +15174,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static String toString(double[] self) {
-        return InvokerHelper.toString(self);
+        return FormatHelper.toString(self);
     }
 
     /**
@@ -15211,7 +15211,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.0
      */
     public static String toMapString(Map self, int maxSize) {
-        return (self == null) ? "null" : InvokerHelper.toMapString(self, maxSize);
+        return (self == null) ? "null" : FormatHelper.toMapString(self, maxSize);
     }
 
     /**
@@ -15252,7 +15252,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.7.3
      */
     public static String toListString(Collection self, int maxSize) {
-        return (self == null) ? "null" : InvokerHelper.toListString(self, maxSize);
+        return (self == null) ? "null" : FormatHelper.toListString(self, maxSize);
     }
 
     /**
@@ -15277,7 +15277,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.0
      */
     public static String toArrayString(Object[] self) {
-        return (self == null) ? "null" : InvokerHelper.toArrayString(self);
+        return (self == null) ? "null" : FormatHelper.toArrayString(self);
     }
 
     /**
@@ -15287,7 +15287,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.0
      */
     public static String toString(Object value) {
-        return InvokerHelper.toString(value);
+        return FormatHelper.toString(value);
     }
 
     //-------------------------------------------------------------------------
@@ -17496,7 +17496,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     @SuppressWarnings("unchecked")
     public static <T> T asType(Object obj, Class<T> type) {
         if (String.class == type) {
-            return (T) InvokerHelper.toString(obj);
+            return (T) FormatHelper.toString(obj);
         }
 
         // fall back to cast
diff --git a/src/main/java/org/codehaus/groovy/runtime/FormatHelper.java b/src/main/java/org/codehaus/groovy/runtime/FormatHelper.java
new file mode 100644
index 0000000..7283509
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/FormatHelper.java
@@ -0,0 +1,477 @@
+/*
+ *  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.codehaus.groovy.runtime;
+
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.GroovySystem;
+import groovy.lang.MetaClassRegistry;
+import groovy.lang.Range;
+import groovy.lang.Writable;
+import groovy.transform.NamedParam;
+import groovy.transform.NamedParams;
+import org.apache.groovy.io.StringBuilderWriter;
+import org.codehaus.groovy.control.ResolveVisitor;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static java.lang.Math.max;
+
+/**
+ * Formatting methods
+ */
+public class FormatHelper {
+    private FormatHelper() {}
+
+    private static final Object[] EMPTY_ARGS = {};
+
+    // heuristic size to pre-alocate stringbuffers for collections of items
+    private static final int ITEM_ALLOCATE_SIZE = 5;
+
+    public static final MetaClassRegistry metaRegistry = GroovySystem.getMetaClassRegistry();
+    private static final String XMLUTIL_CLASS_FULL_NAME = "groovy.xml.XmlUtil";
+    private static final String SERIALIZE_METHOD_NAME = "serialize";
+
+    static final Set<String> DEFAULT_IMPORT_PKGS = new HashSet<>();
+    static final Set<String> DEFAULT_IMPORT_CLASSES = new HashSet<>();
+
+    static {
+        for (String pkgName : ResolveVisitor.DEFAULT_IMPORTS) {
+            FormatHelper.DEFAULT_IMPORT_PKGS.add(pkgName.substring(0, pkgName.length() - 1));
+        }
+        FormatHelper.DEFAULT_IMPORT_CLASSES.add("java.math.BigDecimal");
+        FormatHelper.DEFAULT_IMPORT_CLASSES.add("java.math.BigInteger");
+    }
+
+    public static String toString(Object arguments) {
+        return format(arguments, false, -1, false);
+    }
+
+    public static String inspect(Object self) {
+        return format(self, true);
+    }
+
+    public static String format(Object arguments, boolean verbose) {
+        return format(arguments, verbose, -1);
+    }
+
+    public static String format(Object arguments, boolean verbose, int maxSize) {
+        return format(arguments, verbose, maxSize, false);
+    }
+
+    public static String toString(@NamedParams({
+            @NamedParam(value = "safe", type = Boolean.class),
+            @NamedParam(value = "maxSize", type = Integer.class),
+            @NamedParam(value = "verbose", type = Boolean.class)
+    }) Map<String, Object> options, Object arguments) {
+        Object safe = options.get("safe");
+        if (!(safe instanceof Boolean)) safe = false;
+        Object maxSize = options.get("maxSize");
+        if (!(maxSize instanceof Integer)) maxSize = -1;
+        Object verbose = options.get("verbose");
+        if (!(verbose instanceof Boolean)) verbose = false;
+        return format(arguments, (boolean) verbose, (int) maxSize, (boolean) safe);
+    }
+
+    public static String format(Object arguments, boolean verbose, int maxSize, boolean safe) {
+        if (arguments == null) {
+            final NullObject nullObject = NullObject.getNullObject();
+            return (String) nullObject.getMetaClass().invokeMethod(nullObject, "toString", EMPTY_ARGS);
+        }
+        if (arguments.getClass().isArray()) {
+            if (arguments instanceof Object[]) {
+                return toArrayString((Object[]) arguments, verbose, maxSize, safe);
+            }
+            if (arguments instanceof char[]) {
+                return new String((char[]) arguments);
+            }
+            // other primitives
+            return formatCollection(DefaultTypeTransformation.arrayAsCollection(arguments), verbose, maxSize, safe);
+        }
+        if (arguments instanceof Range) {
+            Range range = (Range) arguments;
+            try {
+                if (verbose) {
+                    return range.inspect();
+                } else {
+                    return range.toString();
+                }
+            } catch (RuntimeException ex) {
+                if (!safe) throw ex;
+                return handleFormattingException(arguments, ex);
+            } catch (Exception ex) {
+                if (!safe) throw new GroovyRuntimeException(ex);
+                return handleFormattingException(arguments, ex);
+            }
+        }
+        if (arguments instanceof Collection) {
+            return formatCollection((Collection) arguments, verbose, maxSize, safe);
+        }
+        if (arguments instanceof Map) {
+            return formatMap((Map) arguments, verbose, maxSize, safe);
+        }
+        if (arguments instanceof Element) {
+            try {
+                Method serialize = Class.forName(XMLUTIL_CLASS_FULL_NAME).getMethod(SERIALIZE_METHOD_NAME, Element.class);
+                return (String) serialize.invoke(null, arguments);
+            } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        if (arguments instanceof String) {
+            if (verbose) {
+                String arg = escapeBackslashes((String) arguments)
+                        .replace("'", "\\'");    // single quotation mark
+                return "'" + arg + "'";
+            } else {
+                return (String) arguments;
+            }
+        }
+        try {
+            // TODO: For GROOVY-2599 do we need something like below but it breaks other things
+//            return (String) invokeMethod(arguments, "toString", EMPTY_ARGS);
+            return arguments.toString();
+        } catch (RuntimeException ex) {
+            if (!safe) throw ex;
+            return handleFormattingException(arguments, ex);
+        } catch (Exception ex) {
+            if (!safe) throw new GroovyRuntimeException(ex);
+            return handleFormattingException(arguments, ex);
+        }
+    }
+
+    public static String escapeBackslashes(String orig) {
+        // must replace backslashes first, as the other replacements add backslashes not to be escaped
+        return orig
+                .replace("\\", "\\\\")           // backslash
+                .replace("\n", "\\n")            // line feed
+                .replace("\r", "\\r")            // carriage return
+                .replace("\t", "\\t")            // tab
+                .replace("\f", "\\f");           // form feed
+    }
+
+    private static String handleFormattingException(Object item, Exception ex) {
+
+        String hash;
+        try {
+            hash = Integer.toHexString(item.hashCode());
+        } catch (Exception ignored) {
+            hash = "????";
+        }
+        return "<" + typeName(item) + "@" + hash + ">";
+    }
+
+    private static String formatMap(Map map, boolean verbose, int maxSize, boolean safe) {
+        if (map.isEmpty()) {
+            return "[:]";
+        }
+        StringBuilder buffer = new StringBuilder(ITEM_ALLOCATE_SIZE * map.size() * 2);
+        buffer.append('[');
+        boolean first = true;
+        for (Object o : map.entrySet()) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(", ");
+            }
+            if (maxSize != -1 && buffer.length() > maxSize) {
+                buffer.append("...");
+                break;
+            }
+            Map.Entry entry = (Map.Entry) o;
+            if (entry.getKey() == map) {
+                buffer.append("(this Map)");
+            } else {
+                buffer.append(format(entry.getKey(), verbose, sizeLeft(maxSize, buffer), safe));
+            }
+            buffer.append(":");
+            if (entry.getValue() == map) {
+                buffer.append("(this Map)");
+            } else {
+                buffer.append(format(entry.getValue(), verbose, sizeLeft(maxSize, buffer), safe));
+            }
+        }
+        buffer.append(']');
+        return buffer.toString();
+    }
+
+    private static int sizeLeft(int maxSize, StringBuilder buffer) {
+        return maxSize == -1 ? maxSize : max(0, maxSize - buffer.length());
+    }
+
+    private static String formatCollection(Collection collection, boolean verbose, int maxSize, boolean safe) {
+        StringBuilder buffer = new StringBuilder(ITEM_ALLOCATE_SIZE * collection.size());
+        buffer.append('[');
+        boolean first = true;
+        for (Object item : collection) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(", ");
+            }
+            if (maxSize != -1 && buffer.length() > maxSize) {
+                buffer.append("...");
+                break;
+            }
+            if (item == collection) {
+                buffer.append("(this Collection)");
+            } else {
+                buffer.append(format(item, verbose, sizeLeft(maxSize, buffer), safe));
+            }
+        }
+        buffer.append(']');
+        return buffer.toString();
+    }
+
+    /**
+     * A helper method to format the arguments types as a comma-separated list.
+     *
+     * @param arguments the type to process
+     * @return the string representation of the type
+     */
+    public static String toTypeString(Object[] arguments) {
+        return toTypeString(arguments, -1);
+    }
+
+    /**
+     * A helper method to format the arguments types as a comma-separated list.
+     *
+     * @param arguments the type to process
+     * @param maxSize   stop after approximately this many characters and append '...', -1 means don't stop
+     * @return the string representation of the type
+     */
+    public static String toTypeString(Object[] arguments, int maxSize) {
+        if (arguments == null) {
+            return "null";
+        }
+        StringBuilder argBuf = new StringBuilder();
+        for (int i = 0; i < arguments.length; i++) {
+            if (maxSize != -1 && argBuf.length() > maxSize) {
+                argBuf.append("...");
+                break;
+            } else {
+                if (i > 0) {
+                    argBuf.append(", ");
+                }
+                argBuf.append(arguments[i] != null ? typeName(arguments[i]) : "null");
+            }
+        }
+        return argBuf.toString();
+    }
+
+    /**
+     * Gets the type name
+     *
+     * @param argument the object to find the type for
+     * @return the type name (slightly pretty format taking into account default imports)
+     */
+    static String typeName(Object argument) {
+        Class<?> aClass = argument.getClass();
+        String pkgName = aClass.getPackage() == null ? "" : aClass.getPackage().getName();
+        boolean useShort = DEFAULT_IMPORT_PKGS.contains(pkgName) || DEFAULT_IMPORT_CLASSES.contains(aClass.getName());
+        return useShort ? aClass.getSimpleName() : aClass.getName();
+    }
+
+    /**
+     * A helper method to return the string representation of a map with bracket boundaries "[" and "]".
+     *
+     * @param arg the map to process
+     * @return the string representation of the map
+     */
+    public static String toMapString(Map arg) {
+        return toMapString(arg, -1);
+    }
+
+    /**
+     * A helper method to return the string representation of a map with bracket boundaries "[" and "]".
+     *
+     * @param arg     the map to process
+     * @param maxSize stop after approximately this many characters and append '...', -1 means don't stop
+     * @return the string representation of the map
+     */
+    public static String toMapString(Map arg, int maxSize) {
+        return formatMap(arg, false, maxSize, false);
+    }
+
+    /**
+     * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
+     *
+     * @param arg the collection to process
+     * @return the string representation of the collection
+     */
+    public static String toListString(Collection arg) {
+        return toListString(arg, -1);
+    }
+
+    /**
+     * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
+     *
+     * @param arg     the collection to process
+     * @param maxSize stop after approximately this many characters and append '...'
+     * @return the string representation of the collection
+     */
+    public static String toListString(Collection arg, int maxSize) {
+        return toListString(arg, maxSize, false);
+    }
+
+    /**
+     * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
+     *
+     * @param arg     the collection to process
+     * @param maxSize stop after approximately this many characters and append '...', -1 means don't stop
+     * @param safe    whether to use a default object representation for any item in the collection if an exception occurs when generating its toString
+     * @return the string representation of the collection
+     */
+    public static String toListString(Collection arg, int maxSize, boolean safe) {
+        return formatCollection(arg, false, maxSize, safe);
+    }
+
+    /**
+     * A helper method to return the string representation of an array of objects
+     * with brace boundaries "[" and "]".
+     *
+     * @param arguments the array to process
+     * @return the string representation of the array
+     */
+    public static String toArrayString(Object[] arguments) {
+        return toArrayString(arguments, false, -1, false);
+    }
+
+    private static String toArrayString(Object[] array, boolean verbose, int maxSize, boolean safe) {
+        if (array == null) {
+            return "null";
+        }
+        boolean first = true;
+        StringBuilder argBuf = new StringBuilder(array.length);
+        argBuf.append('[');
+
+        for (Object item : array) {
+            if (first) {
+                first = false;
+            } else {
+                argBuf.append(", ");
+            }
+            if (maxSize != -1 && argBuf.length() > maxSize) {
+                argBuf.append("...");
+                break;
+            }
+            if (item == array) {
+                argBuf.append("(this array)");
+            } else {
+                argBuf.append(format(item, verbose, sizeLeft(maxSize, argBuf), safe));
+            }
+        }
+        argBuf.append(']');
+        return argBuf.toString();
+    }
+
+    /**
+     * A helper method to return the string representation of an array of objects
+     * with brace boundaries "[" and "]".
+     *
+     * @param arguments the array to process
+     * @param maxSize   stop after approximately this many characters and append '...'
+     * @param safe      whether to use a default object representation for any item in the array if an exception occurs when generating its toString
+     * @return the string representation of the array
+     */
+    public static String toArrayString(Object[] arguments, int maxSize, boolean safe) {
+        return toArrayString(arguments, false, maxSize, safe);
+    }
+
+    /**
+     * Writes an object to a Writer using Groovy's default representation for the object.
+     */
+    public static void write(Writer out, Object object) throws IOException {
+        if (object instanceof String) {
+            out.write((String) object);
+        } else if (object instanceof Object[]) {
+            out.write(toArrayString((Object[]) object));
+        } else if (object instanceof Map) {
+            out.write(toMapString((Map) object));
+        } else if (object instanceof Collection) {
+            out.write(toListString((Collection) object));
+        } else if (object instanceof Writable) {
+            Writable writable = (Writable) object;
+            writable.writeTo(out);
+        } else if (object instanceof InputStream || object instanceof Reader) {
+            // Copy stream to stream
+            Reader reader;
+            if (object instanceof InputStream) {
+                reader = new InputStreamReader((InputStream) object);
+            } else {
+                reader = (Reader) object;
+            }
+
+            try (Reader r = reader) {
+                char[] chars = new char[8192];
+                for (int i; (i = r.read(chars)) != -1; ) {
+                    out.write(chars, 0, i);
+                }
+            }
+        } else {
+            out.write(toString(object));
+        }
+    }
+
+    /**
+     * Appends an object to an Appendable using Groovy's default representation for the object.
+     */
+    public static void append(Appendable out, Object object) throws IOException {
+        if (object instanceof String) {
+            out.append((String) object);
+        } else if (object instanceof Object[]) {
+            out.append(toArrayString((Object[]) object));
+        } else if (object instanceof Map) {
+            out.append(toMapString((Map) object));
+        } else if (object instanceof Collection) {
+            out.append(toListString((Collection) object));
+        } else if (object instanceof Writable) {
+            Writable writable = (Writable) object;
+            Writer stringWriter = new StringBuilderWriter();
+            writable.writeTo(stringWriter);
+            out.append(stringWriter.toString());
+        } else if (object instanceof InputStream || object instanceof Reader) {
+            // Copy stream to stream
+            try (Reader reader =
+                         object instanceof InputStream
+                                 ? new InputStreamReader((InputStream) object)
+                                 : (Reader) object) {
+                char[] chars = new char[8192];
+                for (int i; (i = reader.read(chars)) != -1; ) {
+                    for (int j = 0; j < i; j++) {
+                        out.append(chars[j]);
+                    }
+                }
+            }
+        } else {
+            out.append(toString(object));
+        }
+    }
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/GStringUtil.java b/src/main/java/org/codehaus/groovy/runtime/GStringUtil.java
index a9a80a2..6742d83 100644
--- a/src/main/java/org/codehaus/groovy/runtime/GStringUtil.java
+++ b/src/main/java/org/codehaus/groovy/runtime/GStringUtil.java
@@ -86,7 +86,7 @@ public final class GStringUtil {
                     int maximumNumberOfParameters = c.getMaximumNumberOfParameters();
 
                     if (maximumNumberOfParameters == 0) {
-                        InvokerHelper.write(out, c.call());
+                        FormatHelper.write(out, c.call());
                     } else if (maximumNumberOfParameters == 1) {
                         c.call(out);
                     } else {
@@ -94,7 +94,7 @@ public final class GStringUtil {
                                 + maximumNumberOfParameters + " parameters");
                     }
                 } else {
-                    InvokerHelper.write(out, value);
+                    FormatHelper.write(out, value);
                 }
             }
         }
diff --git a/src/main/java/org/codehaus/groovy/runtime/IOGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/IOGroovyMethods.java
index 76e9d41..4f7633f 100644
--- a/src/main/java/org/codehaus/groovy/runtime/IOGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/IOGroovyMethods.java
@@ -89,7 +89,7 @@ public class IOGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.0
      */
     public static Writer leftShift(Writer self, Object value) throws IOException {
-        InvokerHelper.write(self, value);
+        FormatHelper.write(self, value);
         return self;
     }
 
@@ -104,7 +104,7 @@ public class IOGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.1.0
      */
     public static Appendable leftShift(Appendable self, Object value) throws IOException {
-        InvokerHelper.append(self, value);
+        FormatHelper.append(self, value);
         return self;
     }
 
diff --git a/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
index 7620b9b..42c760b 100644
--- a/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
+++ b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
@@ -29,31 +29,21 @@ import groovy.lang.MetaClass;
 import groovy.lang.MetaClassRegistry;
 import groovy.lang.MissingMethodException;
 import groovy.lang.MissingPropertyException;
-import groovy.lang.Range;
 import groovy.lang.Script;
 import groovy.lang.SpreadMap;
 import groovy.lang.SpreadMapEvaluatingException;
 import groovy.lang.Tuple;
-import groovy.lang.Writable;
-import org.apache.groovy.io.StringBuilderWriter;
-import org.codehaus.groovy.control.ResolveVisitor;
 import org.codehaus.groovy.reflection.ClassInfo;
 import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
 import org.codehaus.groovy.runtime.metaclass.MissingMethodExecutionFailed;
 import org.codehaus.groovy.runtime.powerassert.PowerAssertionError;
-import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
 import org.codehaus.groovy.runtime.wrappers.PojoWrapper;
-import org.w3c.dom.Element;
 
 import java.beans.Introspector;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
 import java.io.Writer;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.ArrayList;
@@ -61,17 +51,13 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import static java.lang.Math.max;
-
 /**
  * A static helper class to make bytecode generation easier and act as a facade over the Invoker
  */
@@ -80,13 +66,8 @@ public class InvokerHelper {
     protected static final Object[] EMPTY_ARGUMENTS = EMPTY_ARGS;
     protected static final Class[] EMPTY_TYPES = {};
 
-    // heuristic size to pre-alocate stringbuffers for collections of items
-    private static final int ITEM_ALLOCATE_SIZE = 5;
-
     public static final MetaClassRegistry metaRegistry = GroovySystem.getMetaClassRegistry();
     public static final String MAIN_METHOD_NAME = "main";
-    private static final String XMLUTIL_CLASS_FULL_NAME = "groovy.xml.XmlUtil";
-    private static final String SERIALIZE_METHOD_NAME = "serialize";
 
     public static void removeClass(Class clazz) {
         metaRegistry.removeMetaClass(clazz);
@@ -146,14 +127,6 @@ public class InvokerHelper {
         return Collections.singletonList(value);
     }
 
-    public static String toString(Object arguments) {
-        return format(arguments, false, -1, false);
-    }
-
-    public static String inspect(Object self) {
-        return format(self, true);
-    }
-
     public static Object getAttribute(Object object, String attribute) {
         if (object == null) {
             object = NullObject.getNullObject();
@@ -335,7 +308,7 @@ public class InvokerHelper {
         if (left instanceof String) {
             stringToCompare = (String) left;
         } else {
-            stringToCompare = toString(left);
+            stringToCompare = FormatHelper.toString(left);
         }
         String regexToCompareTo;
         if (right instanceof String) {
@@ -344,7 +317,7 @@ public class InvokerHelper {
             Pattern pattern = (Pattern) right;
             return pattern.matcher(stringToCompare);
         } else {
-            regexToCompareTo = toString(right);
+            regexToCompareTo = FormatHelper.toString(right);
         }
         return Pattern.compile(regexToCompareTo).matcher(stringToCompare);
     }
@@ -361,9 +334,9 @@ public class InvokerHelper {
         if (right instanceof Pattern) {
             pattern = (Pattern) right;
         } else {
-            pattern = Pattern.compile(toString(right));
+            pattern = Pattern.compile(FormatHelper.toString(right));
         }
-        String stringToCompare = toString(left);
+        String stringToCompare = FormatHelper.toString(left);
         Matcher matcher = pattern.matcher(stringToCompare);
         RegexSupport.setLastMatcher(matcher);
         return matcher.matches();
@@ -383,7 +356,7 @@ public class InvokerHelper {
             }
             return new SpreadMap(values);
         }
-        throw new SpreadMapEvaluatingException("Cannot spread the map " + typeName(value) + ", value " + value);
+        throw new SpreadMapEvaluatingException("Cannot spread the map " + FormatHelper.typeName(value) + ", value " + value);
     }
 
     public static List createList(Object[] values) {
@@ -441,12 +414,20 @@ public class InvokerHelper {
     }
 
     static class NullScript extends Script {
-        public NullScript() { this(new Binding()); }
-        public NullScript(Binding context) { super(context); }
+
+        public NullScript() {
+            this(new Binding());
+        }
+        public NullScript(Binding context) {
+            super(context);
+        }
+
         @Override
-        public Object run() { return null; }
-    }
+        public Object run() {
+            return null;
+        }
 
+    }
     public static Script createScript(Class scriptClass, Binding context) {
         Script script;
 
@@ -475,7 +456,7 @@ public class InvokerHelper {
                     };
 
                     MetaClass smc = getMetaClass(scriptClass);
-                    ((Map<?,?>) context.getVariables()).forEach((key, value) -> {
+                    ((Map<?, ?>) context.getVariables()).forEach((key, value) -> {
                         String name = key.toString();
                         if (!name.startsWith("_")) { // assume underscore variables are for the wrapper
                             setPropertySafe(scriptClass, smc, name, value);
@@ -527,403 +508,6 @@ public class InvokerHelper {
         }
     }
 
-    /**
-     * Writes an object to a Writer using Groovy's default representation for the object.
-     */
-    public static void write(Writer out, Object object) throws IOException {
-        if (object instanceof String) {
-            out.write((String) object);
-        } else if (object instanceof Object[]) {
-            out.write(toArrayString((Object[]) object));
-        } else if (object instanceof Map) {
-            out.write(toMapString((Map) object));
-        } else if (object instanceof Collection) {
-            out.write(toListString((Collection) object));
-        } else if (object instanceof Writable) {
-            Writable writable = (Writable) object;
-            writable.writeTo(out);
-        } else if (object instanceof InputStream || object instanceof Reader) {
-            // Copy stream to stream
-            Reader reader;
-            if (object instanceof InputStream) {
-                reader = new InputStreamReader((InputStream) object);
-            } else {
-                reader = (Reader) object;
-            }
-
-            try (Reader r = reader) {
-                char[] chars = new char[8192];
-                for (int i; (i = r.read(chars)) != -1; ) {
-                    out.write(chars, 0, i);
-                }
-            }
-        } else {
-            out.write(toString(object));
-        }
-    }
-
-    /**
-     * Appends an object to an Appendable using Groovy's default representation for the object.
-     */
-    public static void append(Appendable out, Object object) throws IOException {
-        if (object instanceof String) {
-            out.append((String) object);
-        } else if (object instanceof Object[]) {
-            out.append(toArrayString((Object[]) object));
-        } else if (object instanceof Map) {
-            out.append(toMapString((Map) object));
-        } else if (object instanceof Collection) {
-            out.append(toListString((Collection) object));
-        } else if (object instanceof Writable) {
-            Writable writable = (Writable) object;
-            Writer stringWriter = new StringBuilderWriter();
-            writable.writeTo(stringWriter);
-            out.append(stringWriter.toString());
-        } else if (object instanceof InputStream || object instanceof Reader) {
-            // Copy stream to stream
-            try (Reader reader =
-                         object instanceof InputStream
-                                 ? new InputStreamReader((InputStream) object)
-                                 : (Reader) object) {
-                char[] chars = new char[8192];
-                for (int i; (i = reader.read(chars)) != -1; ) {
-                    for (int j = 0; j < i; j++) {
-                        out.append(chars[j]);
-                    }
-                }
-            }
-        } else {
-            out.append(toString(object));
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    public static Iterator<Object> asIterator(Object o) {
-        return (Iterator) invokeMethod(o, "iterator", EMPTY_ARGS);
-    }
-
-    protected static String format(Object arguments, boolean verbose) {
-        return format(arguments, verbose, -1);
-    }
-
-    public static String format(Object arguments, boolean verbose, int maxSize) {
-        return format(arguments, verbose, maxSize, false);
-    }
-
-    public static String format(Object arguments, boolean verbose, int maxSize, boolean safe) {
-        if (arguments == null) {
-            final NullObject nullObject = NullObject.getNullObject();
-            return (String) nullObject.getMetaClass().invokeMethod(nullObject, "toString", EMPTY_ARGS);
-        }
-        if (arguments.getClass().isArray()) {
-            if (arguments instanceof Object[]) {
-                return toArrayString((Object[]) arguments, verbose, maxSize, safe);
-            }
-            if (arguments instanceof char[]) {
-                return new String((char[]) arguments);
-            }
-            // other primitives
-            return formatCollection(DefaultTypeTransformation.arrayAsCollection(arguments), verbose, maxSize, safe);
-        }
-        if (arguments instanceof Range) {
-            Range range = (Range) arguments;
-            try {
-                if (verbose) {
-                    return range.inspect();
-                } else {
-                    return range.toString();
-                }
-            } catch (RuntimeException ex) {
-                if (!safe) throw ex;
-                return handleFormattingException(arguments, ex);
-            } catch (Exception ex) {
-                if (!safe) throw new GroovyRuntimeException(ex);
-                return handleFormattingException(arguments, ex);
-            }
-        }
-        if (arguments instanceof Collection) {
-            return formatCollection((Collection) arguments, verbose, maxSize, safe);
-        }
-        if (arguments instanceof Map) {
-            return formatMap((Map) arguments, verbose, maxSize, safe);
-        }
-        if (arguments instanceof Element) {
-            try {
-                Method serialize = Class.forName(XMLUTIL_CLASS_FULL_NAME).getMethod(SERIALIZE_METHOD_NAME, Element.class);
-                return (String) serialize.invoke(null, arguments);
-            } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
-                throw new RuntimeException(e);
-            }
-        }
-        if (arguments instanceof String) {
-            if (verbose) {
-                String arg = escapeBackslashes((String) arguments)
-                        .replace("'", "\\'");    // single quotation mark
-                return "'" + arg + "'";
-            } else {
-                return (String) arguments;
-            }
-        }
-        try {
-            // TODO: For GROOVY-2599 do we need something like below but it breaks other things
-//            return (String) invokeMethod(arguments, "toString", EMPTY_ARGS);
-            return arguments.toString();
-        } catch (RuntimeException ex) {
-            if (!safe) throw ex;
-            return handleFormattingException(arguments, ex);
-        } catch (Exception ex) {
-            if (!safe) throw new GroovyRuntimeException(ex);
-            return handleFormattingException(arguments, ex);
-        }
-    }
-
-    public static String escapeBackslashes(String orig) {
-        // must replace backslashes first, as the other replacements add backslashes not to be escaped
-        return orig
-                .replace("\\", "\\\\")           // backslash
-                .replace("\n", "\\n")            // line feed
-                .replace("\r", "\\r")            // carriage return
-                .replace("\t", "\\t")            // tab
-                .replace("\f", "\\f");           // form feed
-    }
-
-    private static String handleFormattingException(Object item, Exception ex) {
-
-        String hash;
-        try {
-            hash = Integer.toHexString(item.hashCode());
-        } catch (Exception ignored) {
-            hash = "????";
-        }
-        return "<" + typeName(item) + "@" + hash + ">";
-    }
-
-    private static String formatMap(Map map, boolean verbose, int maxSize, boolean safe) {
-        if (map.isEmpty()) {
-            return "[:]";
-        }
-        StringBuilder buffer = new StringBuilder(ITEM_ALLOCATE_SIZE * map.size() * 2);
-        buffer.append('[');
-        boolean first = true;
-        for (Object o : map.entrySet()) {
-            if (first) {
-                first = false;
-            } else {
-                buffer.append(", ");
-            }
-            if (maxSize != -1 && buffer.length() > maxSize) {
-                buffer.append("...");
-                break;
-            }
-            Map.Entry entry = (Map.Entry) o;
-            if (entry.getKey() == map) {
-                buffer.append("(this Map)");
-            } else {
-                buffer.append(format(entry.getKey(), verbose, sizeLeft(maxSize, buffer), safe));
-            }
-            buffer.append(":");
-            if (entry.getValue() == map) {
-                buffer.append("(this Map)");
-            } else {
-                buffer.append(format(entry.getValue(), verbose, sizeLeft(maxSize, buffer), safe));
-            }
-        }
-        buffer.append(']');
-        return buffer.toString();
-    }
-
-    private static int sizeLeft(int maxSize, StringBuilder buffer) {
-        return maxSize == -1 ? maxSize : max(0, maxSize - buffer.length());
-    }
-
-    private static String formatCollection(Collection collection, boolean verbose, int maxSize, boolean safe) {
-        StringBuilder buffer = new StringBuilder(ITEM_ALLOCATE_SIZE * collection.size());
-        buffer.append('[');
-        boolean first = true;
-        for (Object item : collection) {
-            if (first) {
-                first = false;
-            } else {
-                buffer.append(", ");
-            }
-            if (maxSize != -1 && buffer.length() > maxSize) {
-                buffer.append("...");
-                break;
-            }
-            if (item == collection) {
-                buffer.append("(this Collection)");
-            } else {
-                buffer.append(format(item, verbose, sizeLeft(maxSize, buffer), safe));
-            }
-        }
-        buffer.append(']');
-        return buffer.toString();
-    }
-
-    /**
-     * A helper method to format the arguments types as a comma-separated list.
-     *
-     * @param arguments the type to process
-     * @return the string representation of the type
-     */
-    public static String toTypeString(Object[] arguments) {
-        return toTypeString(arguments, -1);
-    }
-
-    /**
-     * A helper method to format the arguments types as a comma-separated list.
-     *
-     * @param arguments the type to process
-     * @param maxSize   stop after approximately this many characters and append '...', -1 means don't stop
-     * @return the string representation of the type
-     */
-    public static String toTypeString(Object[] arguments, int maxSize) {
-        if (arguments == null) {
-            return "null";
-        }
-        StringBuilder argBuf = new StringBuilder();
-        for (int i = 0; i < arguments.length; i++) {
-            if (maxSize != -1 && argBuf.length() > maxSize) {
-                argBuf.append("...");
-                break;
-            } else {
-                if (i > 0) {
-                    argBuf.append(", ");
-                }
-                argBuf.append(arguments[i] != null ? typeName(arguments[i]) : "null");
-            }
-        }
-        return argBuf.toString();
-    }
-
-    private static final Set<String> DEFAULT_IMPORT_PKGS = new HashSet<String>();
-    private static final Set<String> DEFAULT_IMPORT_CLASSES = new HashSet<String>();
-    static {
-        for (String pkgName : ResolveVisitor.DEFAULT_IMPORTS) {
-            DEFAULT_IMPORT_PKGS.add(pkgName.substring(0, pkgName.length() - 1));
-        }
-        DEFAULT_IMPORT_CLASSES.add("java.math.BigDecimal");
-        DEFAULT_IMPORT_CLASSES.add("java.math.BigInteger");
-    }
-    /**
-     * Gets the type name
-     *
-     * @param argument the object to find the type for
-     * @return the type name (slightly pretty format taking into account default imports)
-     */
-    private static String typeName(Object argument) {
-        Class<?> aClass = argument.getClass();
-        String pkgName = aClass.getPackage() == null ? "" : aClass.getPackage().getName();
-        boolean useShort = DEFAULT_IMPORT_PKGS.contains(pkgName) || DEFAULT_IMPORT_CLASSES.contains(aClass.getName());
-        return useShort ? aClass.getSimpleName() : aClass.getName();
-    }
-
-    /**
-     * A helper method to return the string representation of a map with bracket boundaries "[" and "]".
-     *
-     * @param arg the map to process
-     * @return the string representation of the map
-     */
-    public static String toMapString(Map arg) {
-        return toMapString(arg, -1);
-    }
-
-    /**
-     * A helper method to return the string representation of a map with bracket boundaries "[" and "]".
-     *
-     * @param arg     the map to process
-     * @param maxSize stop after approximately this many characters and append '...', -1 means don't stop
-     * @return the string representation of the map
-     */
-    public static String toMapString(Map arg, int maxSize) {
-        return formatMap(arg, false, maxSize, false);
-    }
-
-    /**
-     * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
-     *
-     * @param arg the collection to process
-     * @return the string representation of the collection
-     */
-    public static String toListString(Collection arg) {
-        return toListString(arg, -1);
-    }
-
-    /**
-     * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
-     *
-     * @param arg     the collection to process
-     * @param maxSize stop after approximately this many characters and append '...'
-     * @return the string representation of the collection
-     */
-    public static String toListString(Collection arg, int maxSize) {
-        return toListString(arg, maxSize, false);
-    }
-
-    /**
-     * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
-     *
-     * @param arg     the collection to process
-     * @param maxSize stop after approximately this many characters and append '...', -1 means don't stop
-     * @param safe    whether to use a default object representation for any item in the collection if an exception occurs when generating its toString
-     * @return the string representation of the collection
-     */
-    public static String toListString(Collection arg, int maxSize, boolean safe) {
-        return formatCollection(arg, false, maxSize, safe);
-    }
-
-    /**
-     * A helper method to return the string representation of an array of objects
-     * with brace boundaries "[" and "]".
-     *
-     * @param arguments the array to process
-     * @return the string representation of the array
-     */
-    public static String toArrayString(Object[] arguments) {
-        return toArrayString(arguments, false, -1, false);
-    }
-
-    private static String toArrayString(Object[] array, boolean verbose, int maxSize, boolean safe) {
-        if (array == null) {
-            return "null";
-        }
-        boolean first = true;
-        StringBuilder argBuf = new StringBuilder(array.length);
-        argBuf.append('[');
-
-        for (Object item : array) {
-            if (first) {
-                first = false;
-            } else {
-                argBuf.append(", ");
-            }
-            if (maxSize != -1 && argBuf.length() > maxSize) {
-                argBuf.append("...");
-                break;
-            }
-            if (item == array) {
-                argBuf.append("(this array)");
-            } else {
-                argBuf.append(format(item, verbose, sizeLeft(maxSize, argBuf), safe));
-            }
-        }
-        argBuf.append(']');
-        return argBuf.toString();
-    }
-
-    /**
-     * A helper method to return the string representation of an array of objects
-     * with brace boundaries "[" and "]".
-     *
-     * @param arguments the array to process
-     * @param maxSize   stop after approximately this many characters and append '...'
-     * @param safe      whether to use a default object representation for any item in the array if an exception occurs when generating its toString
-     * @return the string representation of the array
-     */
-    public static String toArrayString(Object[] arguments, int maxSize, boolean safe) {
-        return toArrayString(arguments, false, maxSize, safe);
-    }
-
     public static List createRange(Object from, Object to, boolean exclusiveLeft, boolean exclusiveRight) {
         try {
             return ScriptBytecodeAdapter.createRange(from, to, exclusiveLeft, exclusiveRight);
@@ -935,10 +519,10 @@ public class InvokerHelper {
     }
 
     // Kept in for backwards compatibility
+
     public static List createRange(Object from, Object to, boolean inclusive) {
         return createRange(from, to, false, !inclusive);
     }
-
     public static Object bitwiseNegate(Object value) {
         if (value instanceof Integer) {
             Integer number = (Integer) value;
@@ -1084,4 +668,94 @@ public class InvokerHelper {
 
         return args;
     }
+
+    @SuppressWarnings("unchecked")
+    public static Iterator<Object> asIterator(Object o) {
+        return (Iterator) invokeMethod(o, "iterator", EMPTY_ARGS);
+    }
+
+    @Deprecated
+    public static String toString(Object arguments) {
+        return FormatHelper.toString(arguments);
+    }
+
+    @Deprecated
+    public static String inspect(Object self) {
+        return FormatHelper.inspect(self);
+    }
+
+    @Deprecated
+    public static void write(Writer out, Object object) throws IOException {
+        FormatHelper.write(out, object);
+    }
+
+    @Deprecated
+    public static void append(Appendable out, Object object) throws IOException {
+        FormatHelper.append(out, object);
+    }
+
+    @Deprecated
+    protected static String format(Object arguments, boolean verbose) {
+        return FormatHelper.format(arguments, verbose);
+    }
+
+    @Deprecated
+    public static String format(Object arguments, boolean verbose, int maxSize) {
+        return FormatHelper.format(arguments, verbose, maxSize);
+    }
+
+    @Deprecated
+    public static String format(Object arguments, boolean verbose, int maxSize, boolean safe) {
+        return FormatHelper.format(arguments, verbose, maxSize, safe);
+    }
+
+    @Deprecated
+    public static String escapeBackslashes(String orig) {
+        return FormatHelper.escapeBackslashes(orig);
+    }
+
+    @Deprecated
+    public static String toTypeString(Object[] arguments) {
+        return FormatHelper.toTypeString(arguments);
+    }
+
+    @Deprecated
+    public static String toTypeString(Object[] arguments, int maxSize) {
+        return FormatHelper.toTypeString(arguments, maxSize);
+    }
+
+    @Deprecated
+    public static String toMapString(Map arg) {
+        return FormatHelper.toMapString(arg);
+    }
+
+    @Deprecated
+    public static String toMapString(Map arg, int maxSize) {
+        return FormatHelper.toMapString(arg, maxSize);
+    }
+
+    @Deprecated
+    public static String toListString(Collection arg) {
+        return FormatHelper.toListString(arg);
+    }
+
+    @Deprecated
+    public static String toListString(Collection arg, int maxSize) {
+        return FormatHelper.toListString(arg, maxSize);
+    }
+
+    @Deprecated
+    public static String toListString(Collection arg, int maxSize, boolean safe) {
+        return FormatHelper.toListString(arg, maxSize, safe);
+    }
+
+    @Deprecated
+    public static String toArrayString(Object[] arguments) {
+        return FormatHelper.toArrayString(arguments);
+    }
+
+    @Deprecated
+    public static String toArrayString(Object[] arguments, int maxSize, boolean safe) {
+        return FormatHelper.toArrayString(arguments, maxSize, safe);
+    }
 }
diff --git a/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java b/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
index 5855d70..d567f76 100644
--- a/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
+++ b/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
@@ -709,7 +709,7 @@ public class MetaClassHelper {
                         + " on: "
                         + object
                         + " with arguments: "
-                        + InvokerHelper.toString(args)
+                        + FormatHelper.toString(args)
                         + " reason: "
                         + reason,
                 setReason ? reason : null);
diff --git a/src/main/java/org/codehaus/groovy/runtime/ResourceGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/ResourceGroovyMethods.java
index a7b3997..9a25ed1 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ResourceGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ResourceGroovyMethods.java
@@ -982,7 +982,7 @@ public class ResourceGroovyMethods extends DefaultGroovyMethodsSupport {
             if (shouldWriteBom) {
                 writeUTF16BomIfRequired(writer, Charset.defaultCharset().name());
             }
-            InvokerHelper.write(writer, text);
+            FormatHelper.write(writer, text);
             writer.flush();
 
             Writer temp = writer;
@@ -1072,7 +1072,7 @@ public class ResourceGroovyMethods extends DefaultGroovyMethodsSupport {
                 writeUTF16BomIfRequired(out, charset);
             }
             writer = new OutputStreamWriter(out, charset);
-            InvokerHelper.write(writer, text);
+            FormatHelper.write(writer, text);
             writer.flush();
 
             Writer temp = writer;
@@ -1172,7 +1172,7 @@ public class ResourceGroovyMethods extends DefaultGroovyMethodsSupport {
             if (shouldWriteBom) {
                 writeUTF16BomIfRequired(writer, charset);
             }
-            InvokerHelper.write(writer, text);
+            FormatHelper.write(writer, text);
             writer.flush();
 
             Writer temp = writer;
diff --git a/src/main/java/org/codehaus/groovy/runtime/StringGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/StringGroovyMethods.java
index 2863c17..9cbd80c 100644
--- a/src/main/java/org/codehaus/groovy/runtime/StringGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/StringGroovyMethods.java
@@ -1035,9 +1035,9 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
                 for (int i = 0; i <= count; i += 1) {
                     groups.add(matcher.group(i));
                 }
-                return InvokerHelper.toString(closure.call(groups));
+                return FormatHelper.toString(closure.call(groups));
             } else {
-                return InvokerHelper.toString(closure.call(matcher.group(0)));
+                return FormatHelper.toString(closure.call(matcher.group(0)));
             }
         }
         return null;
@@ -1520,7 +1520,7 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      */
     private static String getReplacement(final Matcher matcher, final Closure closure) {
         if (!hasGroup(matcher)) {
-            return InvokerHelper.toString(closure.call(matcher.group()));
+            return FormatHelper.toString(closure.call(matcher.group()));
         }
 
         int count = matcher.groupCount();
@@ -1531,9 +1531,9 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
 
         if (closure.getParameterTypes().length == 1
                 && closure.getParameterTypes()[0] == Object[].class) {
-            return InvokerHelper.toString(closure.call(groups.toArray()));
+            return FormatHelper.toString(closure.call(groups.toArray()));
         }
-        return InvokerHelper.toString(closure.call(groups));
+        return FormatHelper.toString(closure.call(groups));
     }
 
     /**
diff --git a/src/main/java/org/codehaus/groovy/runtime/powerassert/AssertionRenderer.java b/src/main/java/org/codehaus/groovy/runtime/powerassert/AssertionRenderer.java
index b067a5d..8504185 100644
--- a/src/main/java/org/codehaus/groovy/runtime/powerassert/AssertionRenderer.java
+++ b/src/main/java/org/codehaus/groovy/runtime/powerassert/AssertionRenderer.java
@@ -18,7 +18,7 @@
  */
 package org.codehaus.groovy.runtime.powerassert;
 
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -144,7 +144,7 @@ public final class AssertionRenderer {
         String toString;
 
         try {
-            toString = InvokerHelper.format(value, true, -1, false);
+            toString = FormatHelper.format(value, true, -1, false);
         } catch (Exception e) {
             return String.format("%s (toString() threw %s)",
                     javaLangObjectToString(value), e.getClass().getName());
diff --git a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
index a752cdf..ac816bd 100644
--- a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
+++ b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
@@ -24,6 +24,7 @@ import groovy.lang.GroovyRuntimeException;
 import org.codehaus.groovy.reflection.ReflectionCache;
 import org.codehaus.groovy.reflection.stdclasses.CachedSAMClass;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.runtime.InvokerInvocationException;
 import org.codehaus.groovy.runtime.IteratorClosureAdapter;
@@ -237,7 +238,7 @@ public class DefaultTypeTransformation {
         } else if (Collection.class.isAssignableFrom(type)) {
             return continueCastOnCollection(object, type);
         } else if (type == String.class) {
-            return InvokerHelper.toString(object);
+            return FormatHelper.toString(object);
         } else if (type == Character.class) {
             return ShortTypeHandling.castToChar(object);
         } else if (type == Boolean.class) {
diff --git a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
index b4e04f3..ca4fe6d 100644
--- a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
+++ b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
@@ -50,7 +50,7 @@ import org.codehaus.groovy.classgen.FinalVariableAnalyzer;
 import org.codehaus.groovy.classgen.Verifier;
 import org.codehaus.groovy.classgen.VerifierCodeVisitor;
 import org.codehaus.groovy.control.ResolveVisitor;
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.tools.Utilities;
 import org.codehaus.groovy.transform.trait.Traits;
 import org.objectweb.asm.Opcodes;
@@ -1066,7 +1066,7 @@ public class JavaStubGenerator {
     }
 
     private static String escapeSpecialChars(String value) {
-        return InvokerHelper.escapeBackslashes(value).replace("\"", "\\\"");
+        return FormatHelper.escapeBackslashes(value).replace("\"", "\\\"");
     }
 
     private static boolean isInterfaceOrTrait(ClassNode cn) {
diff --git a/src/test/groovy/lang/GStringTest.java b/src/test/groovy/lang/GStringTest.java
index 0f1476e..344d613 100644
--- a/src/test/groovy/lang/GStringTest.java
+++ b/src/test/groovy/lang/GStringTest.java
@@ -19,7 +19,7 @@
 package groovy.lang;
 
 import groovy.test.GroovyTestCase;
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 
 /**
  * Tests the use of the structured Attribute type
@@ -44,8 +44,8 @@ public class GStringTest extends GroovyTestCase {
     public void testAppendString2() {
         DummyGString a = new DummyGString(new Object[]{"James"}, new String[]{"Hello "});
         GString result = a.plus(" how are you?");
-        System.out.println("Strings: " + InvokerHelper.toString(result.getStrings()));
-        System.out.println("Values: " + InvokerHelper.toString(result.getValues()));
+        System.out.println("Strings: " + FormatHelper.toString(result.getStrings()));
+        System.out.println("Values: " + FormatHelper.toString(result.getValues()));
         assertEquals("Hello James how are you?", result.toString());
     }
 
diff --git a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy
index 6ea3b9f..aea8ace 100644
--- a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy
@@ -28,7 +28,7 @@ class DefaultGroovyMethodsTest extends GroovyTestCase {
     void testPrint() throws Exception {
         Map<String, String> map = ['bob': 'drools', 'james': 'geronimo']
         List<Map<String, String>> list = [map]
-        assertEquals("[[bob:drools, james:geronimo]]", InvokerHelper.toString(list))
+        assertEquals("[[bob:drools, james:geronimo]]", FormatHelper.toString(list))
     }
 
     void testFloatRounding() throws Exception {
diff --git a/src/test/org/codehaus/groovy/runtime/InvokeConstructorTest.java b/src/test/org/codehaus/groovy/runtime/InvokeConstructorTest.java
index fda5c3c..5500d4a 100644
--- a/src/test/org/codehaus/groovy/runtime/InvokeConstructorTest.java
+++ b/src/test/org/codehaus/groovy/runtime/InvokeConstructorTest.java
@@ -53,7 +53,7 @@ public class InvokeConstructorTest extends GroovyTestCase {
     protected void assertConstructor(Object expected, Object arguments) throws Throwable {
         Object value = invoke(expected.getClass(), arguments);
 
-        assertEquals("Invoking overloaded method for arguments: " + InvokerHelper.toString(arguments), expected, value);
+        assertEquals("Invoking overloaded method for arguments: " + FormatHelper.toString(arguments), expected, value);
     }
 
     protected Object invoke(Class type, Object args) throws Throwable {
diff --git a/src/test/org/codehaus/groovy/runtime/InvokeMethodTest.java b/src/test/org/codehaus/groovy/runtime/InvokeMethodTest.java
index 5996f4c..d67a612 100644
--- a/src/test/org/codehaus/groovy/runtime/InvokeMethodTest.java
+++ b/src/test/org/codehaus/groovy/runtime/InvokeMethodTest.java
@@ -416,7 +416,7 @@ public class InvokeMethodTest extends GroovyTestCase {
     protected void assertMethodChooser(Object expected, Object arguments) throws Throwable {
         Object value = invoke(this, "mockOverloadedMethod", arguments);
 
-        assertEquals("Invoking overloaded method for arguments: " + InvokerHelper.toString(arguments), expected, value);
+        assertEquals("Invoking overloaded method for arguments: " + FormatHelper.toString(arguments), expected, value);
     }
 
     protected Object invoke(Object object, String method, Object args) throws Throwable {
diff --git a/src/test/org/codehaus/groovy/runtime/InvokerHelperFormattingTest.groovy b/src/test/org/codehaus/groovy/runtime/InvokerHelperFormattingTest.groovy
index 96064fc..f667fd5 100644
--- a/src/test/org/codehaus/groovy/runtime/InvokerHelperFormattingTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/InvokerHelperFormattingTest.groovy
@@ -37,159 +37,159 @@ class InvokerHelperFormattingTest extends GroovyTestCase {
     }
 
     void testToStringLiterals() {
-        assert 'null' == InvokerHelper.toString(null)
-        assert '0.5' == InvokerHelper.toString(0.5)
-        assert '2' == InvokerHelper.toString(2)
-        assert '2' == InvokerHelper.toString(2L)
-        assert 'a' == InvokerHelper.toString('a')
-        assert 'a\'b' == InvokerHelper.toString('a\'b')
+        assert 'null' == FormatHelper.toString(null)
+        assert '0.5' == FormatHelper.toString(0.5)
+        assert '2' == FormatHelper.toString(2)
+        assert '2' == FormatHelper.toString(2L)
+        assert 'a' == FormatHelper.toString('a')
+        assert 'a\'b' == FormatHelper.toString('a\'b')
 
     }
 
     void testToStringThrows() {
         shouldFail(UnsupportedOperationException) {
-            InvokerHelper.toString(new ExceptionOnToString())
+            FormatHelper.toString(new ExceptionOnToString())
         }
     }
 
     void testFormat() {
-        assert 'null' == InvokerHelper.format(null, false)
-        assert '0.5' == InvokerHelper.format(0.5, false)
-        assert '2' == InvokerHelper.format(2, false)
-        assert '2' == InvokerHelper.format(2L, false)
-        assert 'a' == InvokerHelper.format('a', false)
-        assert 'a\'b' == InvokerHelper.format('a\'b', false)
-        assert 'a\\b' + '' == InvokerHelper.format('a\\b', false)
-        assert '\'a\\\'b\'' == InvokerHelper.format('a\'b', true)
-
-        assert 'null' == InvokerHelper.format(null, true)
-        assert '0.5' == InvokerHelper.format(0.5, true)
-        assert '2' == InvokerHelper.format(2, true)
-        assert '2' == InvokerHelper.format(2L, true)
-        assert '\'a\'' == InvokerHelper.format('a', true)
-        assert '\'a\\\'b\'' + '' == InvokerHelper.format('a\'b', true)
-        assert '\'a\\\\b\'' + '' == InvokerHelper.format('a\\b', true)
+        assert 'null' == FormatHelper.format(null, false)
+        assert '0.5' == FormatHelper.format(0.5, false)
+        assert '2' == FormatHelper.format(2, false)
+        assert '2' == FormatHelper.format(2L, false)
+        assert 'a' == FormatHelper.format('a', false)
+        assert 'a\'b' == FormatHelper.format('a\'b', false)
+        assert 'a\\b' + '' == FormatHelper.format('a\\b', false)
+        assert '\'a\\\'b\'' == FormatHelper.format('a\'b', true)
+
+        assert 'null' == FormatHelper.format(null, true)
+        assert '0.5' == FormatHelper.format(0.5, true)
+        assert '2' == FormatHelper.format(2, true)
+        assert '2' == FormatHelper.format(2L, true)
+        assert '\'a\'' == FormatHelper.format('a', true)
+        assert '\'a\\\'b\'' + '' == FormatHelper.format('a\'b', true)
+        assert '\'a\\\\b\'' + '' == FormatHelper.format('a\\b', true)
 
         Object eObject = new ExceptionOnToString()
         shouldFail(UnsupportedOperationException) {
-            InvokerHelper.format(eObject, false)
+            FormatHelper.format(eObject, false)
         }
-        assert InvokerHelper.format(new ExceptionOnToString(), false, -1, true) =~ (ExceptionOnToString.MATCHER)
+        assert FormatHelper.format(new ExceptionOnToString(), false, -1, true) =~ (ExceptionOnToString.MATCHER)
     }
 
     void testFormatRanges() {
-        assert '1..4' == InvokerHelper.format(1..4, false)
-        assert "a'b..a'd" == InvokerHelper.format('a\'b'..'a\'d', false)
-        assert "[1..4]" == InvokerHelper.format([1..4], false)
-        assert "[a'b..a'd]" == InvokerHelper.format(['a\'b'..'a\'d'], false)
+        assert '1..4' == FormatHelper.format(1..4, false)
+        assert "a'b..a'd" == FormatHelper.format('a\'b'..'a\'d', false)
+        assert "[1..4]" == FormatHelper.format([1..4], false)
+        assert "[a'b..a'd]" == FormatHelper.format(['a\'b'..'a\'d'], false)
 
         // verbose
-        assert '1..4' == InvokerHelper.format(1..4, true)
-        assert "'a\\'b'..'a\\'d'" == InvokerHelper.format('a\'b'..'a\'d', true)
-        assert "[1..4]" == InvokerHelper.format([1..4], true)
-        assert "['a\\'b'..'a\\'d']" == InvokerHelper.format(['a\'b'..'a\'d'], true)
+        assert '1..4' == FormatHelper.format(1..4, true)
+        assert "'a\\'b'..'a\\'d'" == FormatHelper.format('a\'b'..'a\'d', true)
+        assert "[1..4]" == FormatHelper.format([1..4], true)
+        assert "['a\\'b'..'a\\'d']" == FormatHelper.format(['a\'b'..'a\'d'], true)
 
         Object eObject = new ExceptionOnToString()
         Object eObject2 = new ExceptionOnToString()
         shouldFail(UnsupportedOperationException) {
-            InvokerHelper.format(eObject..eObject2)
+            FormatHelper.format(eObject..eObject2)
         }
 
-        assert InvokerHelper.format(eObject..eObject, false, -1, true) == '<ObjectRange@????>'
+        assert FormatHelper.format(eObject..eObject, false, -1, true) == '<ObjectRange@????>'
     }
 
     void testToStringLists() {
-        assert '[]' == InvokerHelper.toString([])
-        assert '[1, true, a, \'b\']' == InvokerHelper.toString([1, true, 'a, \'b\''])
+        assert '[]' == FormatHelper.toString([])
+        assert '[1, true, a, \'b\']' == FormatHelper.toString([1, true, 'a, \'b\''])
     }
 
     void testToListString() {
-        assert '[]' == InvokerHelper.toString([])
-        assert '[1, true, a, \'b\']' == InvokerHelper.toListString([1, true, 'a, \'b\''])
-        assert '[1, ...]' == InvokerHelper.toListString([1, true, 'a, \'b\''], 2)
+        assert '[]' == FormatHelper.toString([])
+        assert '[1, true, a, \'b\']' == FormatHelper.toListString([1, true, 'a, \'b\''])
+        assert '[1, ...]' == FormatHelper.toListString([1, true, 'a, \'b\''], 2)
         Object eObject = new ExceptionOnToString()
-        assert InvokerHelper.toListString([eObject], -1, true) =~ "\\[${ExceptionOnToString.MATCHER}\\]"
+        assert FormatHelper.toListString([eObject], -1, true) =~ "\\[${ExceptionOnToString.MATCHER}\\]"
         List list = [[z: eObject]]
-        assert InvokerHelper.toListString(list, -1, true) =~ "\\[\\[z:${ExceptionOnToString.MATCHER}\\]\\]"
+        assert FormatHelper.toListString(list, -1, true) =~ "\\[\\[z:${ExceptionOnToString.MATCHER}\\]\\]"
         // even when throwing object is deeply nested, exception handling only happens in Collection
         list = [[x: [y: [z: eObject, a: 2, b: 4]]]]
-        assert InvokerHelper.toListString(list, -1, true) =~ "\\[\\[x:\\[y:\\[z:${ExceptionOnToString.MATCHER}, a:2, b:4\\]\\]\\]\\]"
+        assert FormatHelper.toListString(list, -1, true) =~ "\\[\\[x:\\[y:\\[z:${ExceptionOnToString.MATCHER}, a:2, b:4\\]\\]\\]\\]"
 
         list = [[eObject, 1, 2]]
         // safe argument is not passed on recursively
-        assert InvokerHelper.toListString(list, -1, true) =~ "\\[\\[${ExceptionOnToString.MATCHER}, 1, 2\\]\\]"
+        assert FormatHelper.toListString(list, -1, true) =~ "\\[\\[${ExceptionOnToString.MATCHER}, 1, 2\\]\\]"
         list = [[[[[eObject, 1, 2]]]]]
-        assert InvokerHelper.toListString(list, -1, true) =~ "\\[\\[\\[\\[\\[${ExceptionOnToString.MATCHER}, 1, 2\\]\\]\\]\\]\\]"
+        assert FormatHelper.toListString(list, -1, true) =~ "\\[\\[\\[\\[\\[${ExceptionOnToString.MATCHER}, 1, 2\\]\\]\\]\\]\\]"
 
         shouldFail(UnsupportedOperationException) {
-            InvokerHelper.toListString([eObject], -1, false)
+            FormatHelper.toListString([eObject], -1, false)
         }
         shouldFail(UnsupportedOperationException) {
-            InvokerHelper.toListString([eObject], -1)
+            FormatHelper.toListString([eObject], -1)
         }
         shouldFail(UnsupportedOperationException) {
-            InvokerHelper.toListString([eObject])
+            FormatHelper.toListString([eObject])
         }
     }
 
     void testToStringRanges() {
-        assert '1..4' == InvokerHelper.toString(1..4)
-        assert "a'b..a'd" == InvokerHelper.toString('a\'b'..'a\'d')
-        assert "[1..4]" == InvokerHelper.toString([1..4])
-        assert "[a'b..a'd]" == InvokerHelper.toString(['a\'b'..'a\'d'])
+        assert '1..4' == FormatHelper.toString(1..4)
+        assert "a'b..a'd" == FormatHelper.toString('a\'b'..'a\'d')
+        assert "[1..4]" == FormatHelper.toString([1..4])
+        assert "[a'b..a'd]" == FormatHelper.toString(['a\'b'..'a\'d'])
     }
 
     void testToStringArrays() {
-        assert "[a, a'b]" == InvokerHelper.toString(['a', 'a\'b'] as String[])
-        assert "[a, a'b]" == InvokerHelper.toString(['a', 'a\'b'] as Object[])
+        assert "[a, a'b]" == FormatHelper.toString(['a', 'a\'b'] as String[])
+        assert "[a, a'b]" == FormatHelper.toString(['a', 'a\'b'] as Object[])
     }
 
     void testFormatArrays() {
-        assert "[a, a'b]" == InvokerHelper.format(['a', 'a\'b'] as String[], false)
-        assert "[a, a'b]" == InvokerHelper.format(['a', 'a\'b'] as Object[], false)
-        assert "['a', 'a\\'b']" == InvokerHelper.format(['a', 'a\'b'] as String[], true)
-        assert "['a', 'a\\'b']" == InvokerHelper.format(['a', 'a\'b'] as Object[], true)
+        assert "[a, a'b]" == FormatHelper.format(['a', 'a\'b'] as String[], false)
+        assert "[a, a'b]" == FormatHelper.format(['a', 'a\'b'] as Object[], false)
+        assert "['a', 'a\\'b']" == FormatHelper.format(['a', 'a\'b'] as String[], true)
+        assert "['a', 'a\\'b']" == FormatHelper.format(['a', 'a\'b'] as Object[], true)
         Object eObject = new ExceptionOnToString()
         shouldFail(UnsupportedOperationException) {
-            InvokerHelper.format([eObject] as ExceptionOnToString[], false)
+            FormatHelper.format([eObject] as ExceptionOnToString[], false)
         }
 
-        assert InvokerHelper.format([new ExceptionOnToString()] as Object[], false, -1, true) =~ "\\[${ExceptionOnToString.MATCHER}\\]"
+        assert FormatHelper.format([new ExceptionOnToString()] as Object[], false, -1, true) =~ "\\[${ExceptionOnToString.MATCHER}\\]"
     }
 
     void testToStringMaps() {
-        assert '[:]' == InvokerHelper.toString([:])
-        assert "[a'b:1, 2:b'c]" == InvokerHelper.toString(['a\'b':1, 2:'b\'c'])
+        assert '[:]' == FormatHelper.toString([:])
+        assert "[a'b:1, 2:b'c]" == FormatHelper.toString(['a\'b':1, 2:'b\'c'])
     }
 
     void testFormatMaps() {
-        assert '[:]' == InvokerHelper.format([:], false)
-        assert "[a'b:1, 2:b'c]" == InvokerHelper.format(['a\'b':1, 2:'b\'c'], false)
-        assert "['a\\'b':1, 2:'b\\'c']" == InvokerHelper.format(['a\'b':1, 2:'b\'c'], true, -1, true)
+        assert '[:]' == FormatHelper.format([:], false)
+        assert "[a'b:1, 2:b'c]" == FormatHelper.format(['a\'b':1, 2:'b\'c'], false)
+        assert "['a\\'b':1, 2:'b\\'c']" == FormatHelper.format(['a\'b':1, 2:'b\'c'], true, -1, true)
 
         Object eObject = new ExceptionOnToString()
         shouldFail(UnsupportedOperationException) {
-            InvokerHelper.format([foo: eObject], false)
+            FormatHelper.format([foo: eObject], false)
         }
 
-        assert InvokerHelper.format([foo: eObject], false, -1, true) =~ "\\[foo:${ExceptionOnToString.MATCHER}\\]"
-        assert InvokerHelper.format([foo: eObject], true, -1, true) =~ "\\['foo':${ExceptionOnToString.MATCHER}\\]"
+        assert FormatHelper.format([foo: eObject], false, -1, true) =~ "\\[foo:${ExceptionOnToString.MATCHER}\\]"
+        assert FormatHelper.format([foo: eObject], true, -1, true) =~ "\\['foo':${ExceptionOnToString.MATCHER}\\]"
         Map m = [:]
         m.put(eObject, eObject)
-        assert InvokerHelper.format(m, false, -1, true) =~ "\\[${ExceptionOnToString.MATCHER}:${ExceptionOnToString.MATCHER}\\]"
+        assert FormatHelper.format(m, false, -1, true) =~ "\\[${ExceptionOnToString.MATCHER}:${ExceptionOnToString.MATCHER}\\]"
     }
 
     void testToMapString() {
-        assert '[:]' == InvokerHelper.toMapString([:])
-        assert "[a'b:1, 2:b'c]" == InvokerHelper.toMapString(['a\'b':1, 2:'b\'c'])
-        assert "[a'b:1, ...]" == InvokerHelper.toMapString(['a\'b':1, 2:'b\'c'], 2)
+        assert '[:]' == FormatHelper.toMapString([:])
+        assert "[a'b:1, 2:b'c]" == FormatHelper.toMapString(['a\'b':1, 2:'b\'c'])
+        assert "[a'b:1, ...]" == FormatHelper.toMapString(['a\'b':1, 2:'b\'c'], 2)
         Object eObject = new ExceptionOnToString()
         // no safe / verbose toMapString method provided
         shouldFail(UnsupportedOperationException) {
-            InvokerHelper.toMapString([x: eObject])
+            FormatHelper.toMapString([x: eObject])
         }
         shouldFail(UnsupportedOperationException) {
-            InvokerHelper.toMapString([x: eObject], 2)
+            FormatHelper.toMapString([x: eObject], 2)
         }
     }
 
@@ -201,19 +201,19 @@ class InvokerHelperFormattingTest extends GroovyTestCase {
         list.add('fog'..'fop')
         list.add(['h', 'i'] as String[])
         list.add([10, 11] as int[])
-        assert "[key:[[a'b:c'd], [e, f, g], 5..9, fog..fop, [h, i], [10, 11]]]" == InvokerHelper.toString([key: list])
+        assert "[key:[[a'b:c'd], [e, f, g], 5..9, fog..fop, [h, i], [10, 11]]]" == FormatHelper.toString([key: list])
 
-        assert "['key':[['a\\'b':'c\\'d'], ['e', 'f', 'g'], 5..9, 'fog'..'fop', ['h', 'i'], [10, 11]]]" == InvokerHelper.format([key:list], true, -1, false)
+        assert "['key':[['a\\'b':'c\\'d'], ['e', 'f', 'g'], 5..9, 'fog'..'fop', ['h', 'i'], [10, 11]]]" == FormatHelper.format([key:list], true, -1, false)
     }
 
     void testToStringSelfContained() {
         List l = [];
         l.add(l)
-        assert '[(this Collection)]' == InvokerHelper.toString(l)
+        assert '[(this Collection)]' == FormatHelper.toString(l)
 
         Map m = [:]
         m.put(m, m)
-        assert '[(this Map):(this Map)]' == InvokerHelper.toString(m)
+        assert '[(this Map):(this Map)]' == FormatHelper.toString(m)
     }
 
 }
diff --git a/subprojects/groovy-ant/src/test/groovy/groovy/ant/SpoofTask.java b/subprojects/groovy-ant/src/test/groovy/groovy/ant/SpoofTask.java
index 21e0cb8..535cffd 100644
--- a/subprojects/groovy-ant/src/test/groovy/groovy/ant/SpoofTask.java
+++ b/subprojects/groovy-ant/src/test/groovy/groovy/ant/SpoofTask.java
@@ -20,7 +20,7 @@ package groovy.ant;
 
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Task;
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 
 public class SpoofTask extends Task {
     private int foo;
@@ -40,7 +40,7 @@ public class SpoofTask extends Task {
         SpoofTaskContainer.spoof("tag name from wrapper: " + getWrapper().getElementTag());
         // don't rely on Map.toString(), behaviour is not documented
         SpoofTaskContainer.spoof("attributes map from wrapper: "
-                + InvokerHelper.toMapString(getWrapper().getAttributeMap()));
+                + FormatHelper.toMapString(getWrapper().getAttributeMap()));
         SpoofTaskContainer.spoof("param foo: " + foo);
 
         SpoofTaskContainer.spoof("end SpoofTask execute");
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/OutputTransforms.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/OutputTransforms.groovy
index 5946426..022b4d7 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/OutputTransforms.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/OutputTransforms.groovy
@@ -19,7 +19,7 @@
 package groovy.console.ui
 
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.runtime.InvokerHelper
+import org.codehaus.groovy.runtime.FormatHelper
 
 import javax.swing.Icon
 import javax.swing.ImageIcon
@@ -92,7 +92,7 @@ class OutputTransforms {
         transforms << { it -> if (it instanceof Image) new ImageIcon(it)}
 
         // final case, non-nulls just get inspected as strings
-        transforms << { it -> if (it != null) "${InvokerHelper.inspect(it)}" }
+        transforms << { it -> if (it != null) "${FormatHelper.inspect(it)}" }
 
         return (List<Closure>) transforms
     }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Groovysh.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Groovysh.groovy
index a5eca30..afefc00 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Groovysh.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Groovysh.groovy
@@ -35,7 +35,7 @@ import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.ErrorCollector
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
 import org.codehaus.groovy.control.messages.Message
-import org.codehaus.groovy.runtime.InvokerHelper
+import org.codehaus.groovy.runtime.FormatHelper
 import org.codehaus.groovy.runtime.StackTraceUtils
 import org.codehaus.groovy.tools.shell.IO
 import org.codehaus.groovy.tools.shell.util.MessageSource
@@ -472,7 +472,7 @@ try {$COLLECTED_BOUND_VARS_MAP_VARNAME[\"$varname\"] = $varname;
         if (showLastResult) {
             // avoid String.valueOf here because it bypasses pretty-printing of Collections,
             // e.g. String.valueOf( ['a': 42] ) != ['a': 42].toString()
-            io.out.println("@|bold ===>|@ ${InvokerHelper.toString(result)}")
+            io.out.println("@|bold ===>|@ ${FormatHelper.toString(result)}")
         }
     }
 
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Interpreter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Interpreter.groovy
index 0387a9d..cc21a23 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Interpreter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Interpreter.groovy
@@ -19,7 +19,7 @@
 package org.apache.groovy.groovysh
 
 import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.runtime.InvokerHelper
+import org.codehaus.groovy.runtime.FormatHelper
 import org.codehaus.groovy.runtime.MethodClosure
 import org.codehaus.groovy.tools.shell.util.Logger
 
@@ -79,7 +79,7 @@ class Interpreter implements Evaluator
             }
 
             // Need to use String.valueOf() here to avoid icky exceptions causes by GString coercion
-            log.debug("Evaluation result: ${InvokerHelper.toString(result)} (${result?.getClass()})")
+            log.debug("Evaluation result: ${FormatHelper.toString(result)} (${result?.getClass()})")
 
             // Keep only the methods that have been defined in the script
             type.declaredMethods.each { Method m ->
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Shell.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Shell.groovy
index 150d0bd..615271a 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Shell.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Shell.groovy
@@ -18,7 +18,7 @@
  */
 package org.apache.groovy.groovysh
 
-import org.codehaus.groovy.runtime.InvokerHelper
+import org.codehaus.groovy.runtime.FormatHelper
 import org.apache.groovy.groovysh.util.CommandArgumentParser
 import org.codehaus.groovy.tools.shell.IO
 import org.codehaus.groovy.tools.shell.util.Logger
@@ -104,7 +104,7 @@ class Shell
             } catch (CommandException e) {
                 io.err.println(ansi().a(Ansi.Attribute.INTENSITY_BOLD).fg(Ansi.Color.RED).a(e.message).reset())
             }
-            log.debug("Result: ${InvokerHelper.toString(result)}")
+            log.debug("Result: ${FormatHelper.toString(result)}")
         }
 
         return result
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/commands/RecordCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/commands/RecordCommand.groovy
index aa68b65..ac80286 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/commands/RecordCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/commands/RecordCommand.groovy
@@ -18,7 +18,7 @@
  */
 package org.apache.groovy.groovysh.commands
 
-import org.codehaus.groovy.runtime.InvokerHelper
+import org.codehaus.groovy.runtime.FormatHelper
 import org.apache.groovy.groovysh.ComplexCommandSupport
 import org.apache.groovy.groovysh.Groovysh
 
@@ -59,7 +59,7 @@ class RecordCommand extends ComplexCommandSupport {
         // result maybe null
 
         if (isRecording()) {
-            writer.println("// RESULT: ${InvokerHelper.toString(result)}")
+            writer.println("// RESULT: ${FormatHelper.toString(result)}")
             writer.flush()
         }
     }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/commands/ShowCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/commands/ShowCommand.groovy
index 3336f7e..56f49b6 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/commands/ShowCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/commands/ShowCommand.groovy
@@ -20,7 +20,7 @@ package org.apache.groovy.groovysh.commands
 
 import org.apache.groovy.groovysh.ComplexCommandSupport
 import org.apache.groovy.groovysh.Groovysh
-import org.codehaus.groovy.runtime.InvokerHelper
+import org.codehaus.groovy.runtime.FormatHelper
 import org.codehaus.groovy.runtime.MethodClosure
 import org.codehaus.groovy.tools.shell.util.Preferences
 
@@ -49,7 +49,7 @@ class ShowCommand extends ComplexCommandSupport {
                     value = "method ${value.method}()"
                 }
 
-                io.out.println("  $key = ${InvokerHelper.toString(value)}")
+                io.out.println("  $key = ${FormatHelper.toString(value)}")
             }
         }
     }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/util/SimpleCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/util/SimpleCompleter.groovy
index 5439930..db8461e 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/util/SimpleCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/util/SimpleCompleter.groovy
@@ -19,7 +19,7 @@
 package org.apache.groovy.groovysh.util
 
 import jline.console.completer.Completer
-import org.codehaus.groovy.runtime.InvokerHelper
+import org.codehaus.groovy.runtime.FormatHelper
 
 /**
  * Support for simple completers.
@@ -68,7 +68,7 @@ class SimpleCompleter implements Completer {
         Iterator iter = list.iterator()
 
         while (iter.hasNext()) {
-            add(InvokerHelper.toString(iter.next()))
+            add(FormatHelper.toString(iter.next()))
         }
     }
 
diff --git a/subprojects/groovy-nio/src/main/java/org/apache/groovy/nio/extensions/NioExtensions.java b/subprojects/groovy-nio/src/main/java/org/apache/groovy/nio/extensions/NioExtensions.java
index c41c34a..dedf30e 100644
--- a/subprojects/groovy-nio/src/main/java/org/apache/groovy/nio/extensions/NioExtensions.java
+++ b/subprojects/groovy-nio/src/main/java/org/apache/groovy/nio/extensions/NioExtensions.java
@@ -32,6 +32,7 @@ import groovy.transform.stc.SimpleType;
 import org.apache.groovy.nio.runtime.WritablePath;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
 import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.IOGroovyMethods;
 import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.runtime.callsite.BooleanReturningMethodInvoker;
@@ -706,7 +707,7 @@ public class NioExtensions extends DefaultGroovyMethodsSupport {
                 writeUTF16BomIfRequired(out, resolvedCharset);
             }
             writer = new OutputStreamWriter(out, resolvedCharset);
-            InvokerHelper.write(writer, text);
+            FormatHelper.write(writer, text);
             writer.flush();
 
             Writer temp = writer;
@@ -823,7 +824,7 @@ public class NioExtensions extends DefaultGroovyMethodsSupport {
             if (shouldWriteBom) {
                 writeUTF16BomIfRequired(writer, charset);
             }
-            InvokerHelper.write(writer, text);
+            FormatHelper.write(writer, text);
             writer.flush();
 
             Writer temp = writer;
diff --git a/subprojects/groovy-templates/src/main/groovy/groovy/text/XmlTemplateEngine.java b/subprojects/groovy-templates/src/main/groovy/groovy/text/XmlTemplateEngine.java
index 9bab98d..68f413d 100644
--- a/subprojects/groovy-templates/src/main/groovy/groovy/text/XmlTemplateEngine.java
+++ b/subprojects/groovy-templates/src/main/groovy/groovy/text/XmlTemplateEngine.java
@@ -30,6 +30,7 @@ import groovy.xml.XmlParser;
 import groovy.namespace.QName;
 import org.apache.groovy.io.StringBuilderWriter;
 import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.InvokerHelper;
 import org.xml.sax.SAXException;
 
@@ -138,7 +139,7 @@ public class XmlTemplateEngine extends TemplateEngine {
         @Override
         protected void printSimpleItem(Object value) {
             this.printLineBegin();
-            out.print(escapeSpecialChars(InvokerHelper.toString(value)));
+            out.print(escapeSpecialChars(FormatHelper.toString(value)));
             printLineEnd();
         }
 
diff --git a/subprojects/groovy-test/src/main/java/groovy/test/GroovyTestCase.java b/subprojects/groovy-test/src/main/java/groovy/test/GroovyTestCase.java
index 4088ece..48e37f4 100644
--- a/subprojects/groovy-test/src/main/java/groovy/test/GroovyTestCase.java
+++ b/subprojects/groovy-test/src/main/java/groovy/test/GroovyTestCase.java
@@ -20,6 +20,7 @@ package groovy.test;
 
 import groovy.lang.Closure;
 import junit.framework.TestCase;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
 
@@ -68,7 +69,7 @@ public class GroovyTestCase extends TestCase {
      */
     protected void assertArrayEquals(Object[] expected, Object[] value) {
         String message =
-                "expected array: " + InvokerHelper.toString(expected) + " value array: " + InvokerHelper.toString(value);
+                "expected array: " + FormatHelper.toString(expected) + " value array: " + FormatHelper.toString(value);
         assertNotNull(message + ": expected should not be null", expected);
         assertNotNull(message + ": value should not be null", value);
         assertEquals(message, expected.length, value.length);
diff --git a/subprojects/groovy-xml/src/main/java/groovy/xml/XmlNodePrinter.java b/subprojects/groovy-xml/src/main/java/groovy/xml/XmlNodePrinter.java
index aa417f6..fdd419f 100644
--- a/subprojects/groovy-xml/src/main/java/groovy/xml/XmlNodePrinter.java
+++ b/subprojects/groovy-xml/src/main/java/groovy/xml/XmlNodePrinter.java
@@ -21,7 +21,7 @@ package groovy.xml;
 import groovy.namespace.QName;
 import groovy.util.IndentPrinter;
 import groovy.util.Node;
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
@@ -259,7 +259,7 @@ public class XmlNodePrinter {
 
     protected void printSimpleItem(Object value) {
         if (!preserveWhitespace) printLineBegin();
-        printEscaped(InvokerHelper.toString(value), false);
+        printEscaped(FormatHelper.toString(value), false);
         if (!preserveWhitespace) printLineEnd();
     }
 
@@ -331,7 +331,7 @@ public class XmlNodePrinter {
             if (value instanceof String) {
                 printEscaped((String) value, true);
             } else {
-                printEscaped(InvokerHelper.toString(value), true);
+                printEscaped(FormatHelper.toString(value), true);
             }
             out.print(quote);
             printNamespace(entry.getKey(), ctx);