You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by cc...@apache.org on 2017/12/17 14:01:13 UTC
[02/62] [abbrv] [partial] groovy git commit: Move Java source set
into `src/main/java`
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
new file mode 100644
index 0000000..890abf2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
@@ -0,0 +1,1079 @@
+/*
+ * 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.Binding;
+import groovy.lang.Closure;
+import groovy.lang.GString;
+import groovy.lang.GroovyInterceptable;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.GroovySystem;
+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.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.StringWriter;
+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;
+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;
+
+/**
+ * A static helper class to make bytecode generation easier and act as a facade over the Invoker
+ */
+public class InvokerHelper {
+ private static final Object[] EMPTY_MAIN_ARGS = new Object[]{new String[0]};
+
+ public static final Object[] EMPTY_ARGS = {};
+ 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";
+
+ public static void removeClass(Class clazz) {
+ metaRegistry.removeMetaClass(clazz);
+ ClassInfo.remove(clazz);
+ Introspector.flushFromCaches(clazz);
+ }
+
+ public static Object invokeMethodSafe(Object object, String methodName, Object arguments) {
+ if (object != null) {
+ return invokeMethod(object, methodName, arguments);
+ }
+ return null;
+ }
+
+ public static Object invokeStaticMethod(String klass, String methodName, Object arguments) throws ClassNotFoundException {
+ Class type = Class.forName(klass);
+ return invokeStaticMethod(type, methodName, arguments);
+ }
+
+
+ public static Object invokeStaticNoArgumentsMethod(Class type, String methodName) {
+ return invokeStaticMethod(type, methodName, EMPTY_ARGS);
+ }
+
+ public static Object invokeConstructorOf(String klass, Object arguments) throws ClassNotFoundException {
+ Class type = Class.forName(klass);
+ return invokeConstructorOf(type, arguments);
+ }
+
+ public static Object invokeNoArgumentsConstructorOf(Class type) {
+ return invokeConstructorOf(type, EMPTY_ARGS);
+ }
+
+ public static Object invokeClosure(Object closure, Object arguments) {
+ return invokeMethod(closure, "doCall", arguments);
+ }
+
+ public static List asList(Object value) {
+ if (value == null) {
+ return Collections.EMPTY_LIST;
+ }
+ if (value instanceof List) {
+ return (List) value;
+ }
+ if (value.getClass().isArray()) {
+ return Arrays.asList((Object[]) value);
+ }
+ if (value instanceof Enumeration) {
+ Enumeration e = (Enumeration) value;
+ List answer = new ArrayList();
+ while (e.hasMoreElements()) {
+ answer.add(e.nextElement());
+ }
+ return answer;
+ }
+ // let's assume its a collection of 1
+ 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();
+ }
+
+ if (object instanceof Class) {
+ return metaRegistry.getMetaClass((Class) object).getAttribute(object, attribute);
+ } else if (object instanceof GroovyObject) {
+ return ((GroovyObject) object).getMetaClass().getAttribute(object, attribute);
+ } else {
+ return metaRegistry.getMetaClass(object.getClass()).getAttribute(object, attribute);
+ }
+ }
+
+ public static void setAttribute(Object object, String attribute, Object newValue) {
+ if (object == null) {
+ object = NullObject.getNullObject();
+ }
+
+ if (object instanceof Class) {
+ metaRegistry.getMetaClass((Class) object).setAttribute(object, attribute, newValue);
+ } else if (object instanceof GroovyObject) {
+ ((GroovyObject) object).getMetaClass().setAttribute(object, attribute, newValue);
+ } else {
+ metaRegistry.getMetaClass(object.getClass()).setAttribute(object, attribute, newValue);
+ }
+ }
+
+ public static Object getProperty(Object object, String property) {
+ if (object == null) {
+ object = NullObject.getNullObject();
+ }
+
+ if (object instanceof GroovyObject) {
+ GroovyObject pogo = (GroovyObject) object;
+ return pogo.getProperty(property);
+ } else if (object instanceof Class) {
+ Class c = (Class) object;
+ return metaRegistry.getMetaClass(c).getProperty(object, property);
+ } else {
+ return ((MetaClassRegistryImpl) metaRegistry).getMetaClass(object).getProperty(object, property);
+ }
+ }
+
+ public static Object getPropertySafe(Object object, String property) {
+ if (object != null) {
+ return getProperty(object, property);
+ }
+ return null;
+ }
+
+ public static void setProperty(Object object, String property, Object newValue) {
+ if (object == null) {
+ object = NullObject.getNullObject();
+ }
+
+ if (object instanceof GroovyObject) {
+ GroovyObject pogo = (GroovyObject) object;
+ pogo.setProperty(property, newValue);
+ } else if (object instanceof Class) {
+ metaRegistry.getMetaClass((Class) object).setProperty((Class) object, property, newValue);
+ } else {
+ ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(object).setProperty(object, property, newValue);
+ }
+ }
+
+ /**
+ * This is so we don't have to reorder the stack when we call this method.
+ * At some point a better name might be in order.
+ */
+ public static void setProperty2(Object newValue, Object object, String property) {
+ setProperty(object, property, newValue);
+ }
+
+
+ /**
+ * This is so we don't have to reorder the stack when we call this method.
+ * At some point a better name might be in order.
+ */
+ public static void setGroovyObjectProperty(Object newValue, GroovyObject object, String property) {
+ object.setProperty(property, newValue);
+ }
+
+ public static Object getGroovyObjectProperty(GroovyObject object, String property) {
+ return object.getProperty(property);
+ }
+
+
+ /**
+ * This is so we don't have to reorder the stack when we call this method.
+ * At some point a better name might be in order.
+ */
+ public static void setPropertySafe2(Object newValue, Object object, String property) {
+ if (object != null) {
+ setProperty2(newValue, object, property);
+ }
+ }
+
+ /**
+ * Returns the method pointer for the given object name
+ */
+ public static Closure getMethodPointer(Object object, String methodName) {
+ if (object == null) {
+ throw new NullPointerException("Cannot access method pointer for '" + methodName + "' on null object");
+ }
+ return new MethodClosure(object, methodName);
+ }
+
+ public static Object unaryMinus(Object value) {
+ if (value instanceof Integer) {
+ Integer number = (Integer) value;
+ return Integer.valueOf(-number.intValue());
+ }
+ if (value instanceof Long) {
+ Long number = (Long) value;
+ return -number;
+ }
+ if (value instanceof BigInteger) {
+ return ((BigInteger) value).negate();
+ }
+ if (value instanceof BigDecimal) {
+ return ((BigDecimal) value).negate();
+ }
+ if (value instanceof Double) {
+ Double number = (Double) value;
+ return -number;
+ }
+ if (value instanceof Float) {
+ Float number = (Float) value;
+ return -number;
+ }
+ if (value instanceof Short) {
+ Short number = (Short) value;
+ return Short.valueOf((short) -number.shortValue());
+ }
+ if (value instanceof Byte) {
+ Byte number = (Byte) value;
+ return Byte.valueOf((byte) -number.byteValue());
+ }
+ if (value instanceof ArrayList) {
+ // value is a list.
+ List newlist = new ArrayList();
+ for (Object o : ((ArrayList) value)) {
+ newlist.add(unaryMinus(o));
+ }
+ return newlist;
+ }
+ return invokeMethod(value, "negative", EMPTY_ARGS);
+ }
+
+ public static Object unaryPlus(Object value) {
+ if (value instanceof Integer ||
+ value instanceof Long ||
+ value instanceof BigInteger ||
+ value instanceof BigDecimal ||
+ value instanceof Double ||
+ value instanceof Float ||
+ value instanceof Short ||
+ value instanceof Byte) {
+ return value;
+ }
+ if (value instanceof ArrayList) {
+ // value is a list.
+ List newlist = new ArrayList();
+ for (Object o : ((ArrayList) value)) {
+ newlist.add(unaryPlus(o));
+ }
+ return newlist;
+ }
+ return invokeMethod(value, "positive", EMPTY_ARGS);
+ }
+
+ /**
+ * Find the right hand regex within the left hand string and return a matcher.
+ *
+ * @param left string to compare
+ * @param right regular expression to compare the string to
+ */
+ public static Matcher findRegex(Object left, Object right) {
+ String stringToCompare;
+ if (left instanceof String) {
+ stringToCompare = (String) left;
+ } else {
+ stringToCompare = toString(left);
+ }
+ String regexToCompareTo;
+ if (right instanceof String) {
+ regexToCompareTo = (String) right;
+ } else if (right instanceof Pattern) {
+ Pattern pattern = (Pattern) right;
+ return pattern.matcher(stringToCompare);
+ } else {
+ regexToCompareTo = toString(right);
+ }
+ return Pattern.compile(regexToCompareTo).matcher(stringToCompare);
+ }
+
+ /**
+ * Find the right hand regex within the left hand string and return a matcher.
+ *
+ * @param left string to compare
+ * @param right regular expression to compare the string to
+ */
+ public static boolean matchRegex(Object left, Object right) {
+ if (left == null || right == null) return false;
+ Pattern pattern;
+ if (right instanceof Pattern) {
+ pattern = (Pattern) right;
+ } else {
+ pattern = Pattern.compile(toString(right));
+ }
+ String stringToCompare = toString(left);
+ Matcher matcher = pattern.matcher(stringToCompare);
+ RegexSupport.setLastMatcher(matcher);
+ return matcher.matches();
+ }
+
+ public static Tuple createTuple(Object[] array) {
+ return new Tuple(array);
+ }
+
+ public static SpreadMap spreadMap(Object value) {
+ if (value instanceof Map) {
+ Object[] values = new Object[((Map) value).keySet().size() * 2];
+ int index = 0;
+ for (Object key : ((Map) value).keySet()) {
+ values[index++] = key;
+ values[index++] = ((Map) value).get(key);
+ }
+ return new SpreadMap(values);
+ }
+ throw new SpreadMapEvaluatingException("Cannot spread the map " + typeName(value) + ", value " + value);
+ }
+
+ public static List createList(Object[] values) {
+ List answer = new ArrayList(values.length);
+ answer.addAll(Arrays.asList(values));
+ return answer;
+ }
+
+ public static Map createMap(Object[] values) {
+ Map answer = new LinkedHashMap(values.length / 2);
+ int i = 0;
+ while (i < values.length - 1) {
+ if ((values[i] instanceof SpreadMap) && (values[i + 1] instanceof Map)) {
+ Map smap = (Map) values[i + 1];
+ for (Object e : smap.entrySet()) {
+ Map.Entry entry = (Map.Entry) e;
+ answer.put(entry.getKey(), entry.getValue());
+ }
+ i += 2;
+ } else {
+ answer.put(values[i++], values[i++]);
+ }
+ }
+ return answer;
+ }
+
+ public static void assertFailed(Object expression, Object message) {
+ if (message == null || "".equals(message)) {
+ throw new PowerAssertionError(expression.toString());
+ }
+ throw new AssertionError(String.valueOf(message) + ". Expression: " + expression);
+ }
+
+ public static Object runScript(Class scriptClass, String[] args) {
+ Binding context = new Binding(args);
+ Script script = createScript(scriptClass, context);
+ return invokeMethod(script, "run", EMPTY_ARGS);
+ }
+
+ static class NullScript extends Script {
+ public NullScript() { this(new Binding()); }
+ public NullScript(Binding context) { super(context); }
+ public Object run() { return null; }
+ }
+
+ public static Script createScript(Class scriptClass, Binding context) {
+ Script script;
+
+ if (scriptClass == null) {
+ script = new NullScript(context);
+ } else {
+ try {
+ if (Script.class.isAssignableFrom(scriptClass)) {
+ script = newScript(scriptClass, context);
+ } else {
+ final GroovyObject object = (GroovyObject) scriptClass.newInstance();
+ // it could just be a class, so let's wrap it in a Script
+ // wrapper; though the bindings will be ignored
+ script = new Script(context) {
+ public Object run() {
+ Object argsToPass = EMPTY_MAIN_ARGS;
+ try {
+ Object args = getProperty("args");
+ if (args instanceof String[]) {
+ argsToPass = args;
+ }
+ } catch (MissingPropertyException e) {
+ // They'll get empty args since none exist in the context.
+ }
+ object.invokeMethod(MAIN_METHOD_NAME, argsToPass);
+ return null;
+ }
+ };
+ Map variables = context.getVariables();
+ MetaClass mc = getMetaClass(object);
+ for (Object o : variables.entrySet()) {
+ Map.Entry entry = (Map.Entry) o;
+ String key = entry.getKey().toString();
+ // assume underscore variables are for the wrapper script
+ setPropertySafe(key.startsWith("_") ? script : object, mc, key, entry.getValue());
+ }
+ }
+ } catch (Exception e) {
+ throw new GroovyRuntimeException(
+ "Failed to create Script instance for class: "
+ + scriptClass + ". Reason: " + e, e);
+ }
+ }
+ return script;
+ }
+
+ public static Script newScript(Class<?> scriptClass, Binding context) throws InstantiationException, IllegalAccessException, InvocationTargetException {
+ Script script;
+ try {
+ Constructor constructor = scriptClass.getConstructor(Binding.class);
+ script = (Script) constructor.newInstance(context);
+ } catch (NoSuchMethodException e) {
+ // Fallback for non-standard "Script" classes.
+ script = (Script) scriptClass.newInstance();
+ script.setBinding(context);
+ }
+ return script;
+ }
+
+ /**
+ * Sets the properties on the given object
+ */
+ public static void setProperties(Object object, Map map) {
+ MetaClass mc = getMetaClass(object);
+ for (Object o : map.entrySet()) {
+ Map.Entry entry = (Map.Entry) o;
+ String key = entry.getKey().toString();
+ Object value = entry.getValue();
+ setPropertySafe(object, mc, key, value);
+ }
+ }
+
+ private static void setPropertySafe(Object object, MetaClass mc, String key, Object value) {
+ try {
+ mc.setProperty(object, key, value);
+ } catch (MissingPropertyException mpe) {
+ // Ignore
+ } catch (InvokerInvocationException iie) {
+ // GROOVY-5802 IAE for missing properties with classes that extend List
+ Throwable cause = iie.getCause();
+ if (cause == null || !(cause instanceof IllegalArgumentException)) throw iie;
+ }
+ }
+
+ /**
+ * 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;
+ }
+ char[] chars = new char[8192];
+ int i;
+ while ((i = reader.read(chars)) != -1) {
+ out.write(chars, 0, i);
+ }
+ reader.close();
+ } 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;
+ StringWriter stringWriter = new StringWriter();
+ writable.writeTo(stringWriter);
+ out.append(stringWriter.toString());
+ } 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;
+ }
+ char[] chars = new char[8192];
+ int i;
+ while ((i = reader.read(chars)) != -1) {
+ for (int j = 0; j < i; j++) {
+ out.append(chars[j]);
+ }
+ }
+ reader.close();
+ } 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("groovy.xml.XmlUtil").getMethod("serialize", Element.class);
+ return (String) serialize.invoke(null, arguments);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ if (arguments instanceof String) {
+ if (verbose) {
+ String arg = escapeBackslashes((String) arguments)
+ .replaceAll("'", "\\\\'"); // 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
+ .replaceAll("\\r", "\\\\r") // carriage return
+ .replaceAll("\\t", "\\\\t") // tab
+ .replaceAll("\\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 : Math.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 Set<String> DEFAULT_IMPORT_PKGS = new HashSet<String>();
+ private static 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 inclusive) {
+ try {
+ return ScriptBytecodeAdapter.createRange(from, to, inclusive);
+ } catch (RuntimeException re) {
+ throw re;
+ } catch (Error e) {
+ throw e;
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ public static Object bitwiseNegate(Object value) {
+ if (value instanceof Integer) {
+ Integer number = (Integer) value;
+ return ~number;
+ }
+ if (value instanceof Long) {
+ Long number = (Long) value;
+ return ~number;
+ }
+ if (value instanceof BigInteger) {
+ return ((BigInteger) value).not();
+ }
+ if (value instanceof String) {
+ // value is a regular expression.
+ return StringGroovyMethods.bitwiseNegate(value.toString());
+ }
+ if (value instanceof GString) {
+ // value is a regular expression.
+ return StringGroovyMethods.bitwiseNegate(value.toString());
+ }
+ if (value instanceof ArrayList) {
+ // value is a list.
+ List newlist = new ArrayList();
+ for (Object o : ((ArrayList) value)) {
+ newlist.add(bitwiseNegate(o));
+ }
+ return newlist;
+ }
+ return invokeMethod(value, "bitwiseNegate", EMPTY_ARGS);
+ }
+
+ public static MetaClassRegistry getMetaRegistry() {
+ return metaRegistry;
+ }
+
+ public static MetaClass getMetaClass(Object object) {
+ if (object instanceof GroovyObject)
+ return ((GroovyObject) object).getMetaClass();
+ else
+ return ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(object);
+ }
+
+ public static MetaClass getMetaClass(Class cls) {
+ return metaRegistry.getMetaClass(cls);
+ }
+
+ /**
+ * Invokes the given method on the object.
+ */
+ public static Object invokeMethod(Object object, String methodName, Object arguments) {
+ if (object == null) {
+ object = NullObject.getNullObject();
+ //throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
+ }
+
+ // if the object is a Class, call a static method from that class
+ if (object instanceof Class) {
+ Class theClass = (Class) object;
+ MetaClass metaClass = metaRegistry.getMetaClass(theClass);
+ return metaClass.invokeStaticMethod(object, methodName, asArray(arguments));
+ }
+
+ // it's an instance; check if it's a Java one
+ if (!(object instanceof GroovyObject)) {
+ return invokePojoMethod(object, methodName, arguments);
+ }
+
+ // a groovy instance (including builder, closure, ...)
+ return invokePogoMethod(object, methodName, arguments);
+ }
+
+ static Object invokePojoMethod(Object object, String methodName, Object arguments) {
+ MetaClass metaClass = InvokerHelper.getMetaClass(object);
+ return metaClass.invokeMethod(object, methodName, asArray(arguments));
+ }
+
+ static Object invokePogoMethod(Object object, String methodName, Object arguments) {
+ GroovyObject groovy = (GroovyObject) object;
+ boolean intercepting = groovy instanceof GroovyInterceptable;
+ try {
+ // if it's a pure interceptable object (even intercepting toString(), clone(), ...)
+ if (intercepting) {
+ return groovy.invokeMethod(methodName, asUnwrappedArray(arguments));
+ }
+ //else try a statically typed method or a GDK method
+ return groovy.getMetaClass().invokeMethod(object, methodName, asArray(arguments));
+ } catch (MissingMethodException e) {
+ if (e instanceof MissingMethodExecutionFailed) {
+ throw (MissingMethodException) e.getCause();
+ } else if (!intercepting && e.getMethod().equals(methodName) && object.getClass() == e.getType()) {
+ // in case there's nothing else, invoke the object's own invokeMethod()
+ return groovy.invokeMethod(methodName, asUnwrappedArray(arguments));
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ public static Object invokeSuperMethod(Object object, String methodName, Object arguments) {
+ if (object == null) {
+ throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
+ }
+
+ Class theClass = object.getClass();
+
+ MetaClass metaClass = metaRegistry.getMetaClass(theClass.getSuperclass());
+ return metaClass.invokeMethod(object, methodName, asArray(arguments));
+ }
+
+ public static Object invokeStaticMethod(Class type, String method, Object arguments) {
+ MetaClass metaClass = metaRegistry.getMetaClass(type);
+ return metaClass.invokeStaticMethod(type, method, asArray(arguments));
+ }
+
+ public static Object invokeConstructorOf(Class type, Object arguments) {
+ MetaClass metaClass = metaRegistry.getMetaClass(type);
+ return metaClass.invokeConstructor(asArray(arguments));
+ }
+
+ /**
+ * Converts the given object into an array; if its an array then just
+ * cast otherwise wrap it in an array
+ */
+ public static Object[] asArray(Object arguments) {
+
+ if (arguments == null) {
+ return EMPTY_ARGUMENTS;
+ }
+ if (arguments instanceof Object[]) {
+ return (Object[]) arguments;
+ }
+ return new Object[]{arguments};
+ }
+
+ public static Object[] asUnwrappedArray(Object arguments) {
+
+ Object[] args = asArray(arguments);
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] instanceof PojoWrapper) {
+ args[i] = ((PojoWrapper) args[i]).unwrap();
+ }
+ }
+
+ return args;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/InvokerInvocationException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/InvokerInvocationException.java b/src/main/java/org/codehaus/groovy/runtime/InvokerInvocationException.java
new file mode 100644
index 0000000..2f03126
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/InvokerInvocationException.java
@@ -0,0 +1,44 @@
+/*
+ * 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 java.lang.reflect.InvocationTargetException;
+
+/**
+ * An exception thrown if a method is called and an exception occurred
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class InvokerInvocationException extends GroovyRuntimeException {
+
+ public InvokerInvocationException(InvocationTargetException e) {
+ super(e.getTargetException());
+ }
+
+ public InvokerInvocationException(Throwable cause) {
+ super(cause);
+ }
+
+ public String getMessage() {
+ Throwable cause = getCause();
+ return (cause==null)?"java.lang.NullPointerException":cause.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/IteratorClosureAdapter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/IteratorClosureAdapter.java b/src/main/java/org/codehaus/groovy/runtime/IteratorClosureAdapter.java
new file mode 100644
index 0000000..24d74f6
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/IteratorClosureAdapter.java
@@ -0,0 +1,58 @@
+/*
+ * 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.Closure;
+import groovy.lang.MetaClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A closure which stores calls in a List so that method calls
+ * can be iterated over in a 'yield' style way
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class IteratorClosureAdapter<T> extends Closure {
+
+ private final List<T> list = new ArrayList<T>();
+ private MetaClass metaClass = InvokerHelper.getMetaClass(getClass());
+
+ public IteratorClosureAdapter(Object delegate) {
+ super(delegate);
+ }
+
+ public MetaClass getMetaClass() {
+ return metaClass;
+ }
+
+ public void setMetaClass(MetaClass metaClass) {
+ this.metaClass = metaClass;
+ }
+
+ public List<T> asList() {
+ return list;
+ }
+
+ protected Object doCall(T argument) {
+ list.add(argument);
+ return null;
+ }
+}