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:17 UTC

[06/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/BytecodeInterface8.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/BytecodeInterface8.java b/src/main/java/org/codehaus/groovy/runtime/BytecodeInterface8.java
new file mode 100644
index 0000000..79fae05
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/BytecodeInterface8.java
@@ -0,0 +1,377 @@
+/*
+ *  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 org.codehaus.groovy.runtime.metaclass.DefaultMetaClassInfo;
+
+/**
+ * This class contains methods special to optimizations used directly from bytecode in Groovy 1.8
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class BytecodeInterface8 {
+    
+    public static boolean disabledStandardMetaClass() {
+        return DefaultMetaClassInfo.disabledStandardMetaClass();
+    }
+    
+    // ------------------ int ------------------
+    
+    /**
+     * @return true if integer has its default MetaClass
+     */
+    public static boolean isOrigInt(){
+       return DefaultMetaClassInfo.isOrigInt(); 
+    }
+
+    // ------------------ int[] ------------------
+    
+    /**
+     * @return true if integer array has its default MetaClass
+     */
+    public static boolean isOrigIntArray(){
+       return DefaultMetaClassInfo.isOrigIntArray(); 
+    }
+    
+    
+    /**
+     * get value from int[] using normalized index
+     */
+    public static int intArrayGet(int[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from int[] using normalized index
+     */
+    public static void intArraySet(int[] a, int i, int v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ byte ------------------
+    
+    /**
+     * @return true if byte has its default MetaClass
+     */
+    public static boolean isOrigB(){
+       return DefaultMetaClassInfo.isOrigByte(); 
+    }
+
+    // ------------------ byte[] ------------------
+    
+    /**
+     * @return true if byte array has its default MetaClass
+     */
+    public static boolean isOrigBArray(){
+       return false; 
+    }
+    
+    
+    /**
+     * get value from byte[] using normalized index
+     */
+    public static byte bArrayGet(byte[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from byte[] using normalized index
+     */
+    public static void bArraySet(byte[] a, int i, byte v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ short ------------------
+    
+    /**
+     * @return true if short has its default MetaClass
+     */
+    public static boolean isOrigS(){
+       return DefaultMetaClassInfo.isOrigShort(); 
+    }
+
+    // ------------------ short[] ------------------
+    
+    /**
+     * @return true if short array has its default MetaClass
+     */
+    public static boolean isOrigSArray(){
+       return false; 
+    }
+    
+    
+    /**
+     * get value from short[] using normalized index
+     */
+    public static short sArrayGet(short[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from short[] using normalized index
+     */
+    public static void sArraySet(short[] a, int i, short v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ char ------------------
+    
+    /**
+     * @return true if char has its default MetaClass
+     */
+    public static boolean isOrigC(){
+       return DefaultMetaClassInfo.isOrigChar(); 
+    }
+
+    // ------------------ char[] ------------------
+    
+    /**
+     * @return true if char array has its default MetaClass
+     */
+    public static boolean isOrigCArray(){
+       return false; 
+    }
+    
+    
+    /**
+     * get value from char[] using normalized index
+     */
+    public static char cArrayGet(char[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from char[] using normalized index
+     */
+    public static void cArraySet(char[] a, int i, char v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ long ------------------
+    
+    /**
+     * @return true if long has its default MetaClass
+     */
+    public static boolean isOrigL(){
+       return DefaultMetaClassInfo.isOrigLong(); 
+    }
+
+    // ------------------ long[] ------------------
+    
+    /**
+     * @return true if long array has its default MetaClass
+     */
+    public static boolean isOrigLArray(){
+       return false; 
+    }
+    
+    
+    /**
+     * get value from long[] using normalized index
+     */
+    public static long lArrayGet(long[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from long[] using normalized index
+     */
+    public static void lArraySet(long[] a, int i, long v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ boolean ------------------
+    
+    /**
+     * @return true if boolean has its default MetaClass
+     */
+    public static boolean isOrigZ(){
+       return DefaultMetaClassInfo.isOrigBool(); 
+    }
+
+    // ------------------ boolean[] ------------------
+    
+    /**
+     * @return true if boolean array has its default MetaClass
+     */
+    public static boolean isOrigZArray(){
+       return false; 
+    }
+    
+    /**
+     * get value from boolean[] using normalized index
+     */
+    public static boolean zArrayGet(boolean[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from boolean[] using normalized index
+     */
+    public static void zArraySet(boolean[] a, int i, boolean v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ float ------------------
+    
+    /**
+     * @return true if float has its default MetaClass
+     */
+    public static boolean isOrigF(){
+       return DefaultMetaClassInfo.isOrigFloat(); 
+    }
+
+    // ------------------ float[] ------------------
+    
+    /**
+     * @return true if float array has its default MetaClass
+     */
+    public static boolean isOrigFArray(){
+       return false; 
+    }
+    
+    /**
+     * get value from float[] using normalized index
+     */
+    public static float fArrayGet(float[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from float[] using normalized index
+     */
+    public static void fArraySet(float[] a, int i, float v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ double ------------------
+    
+    /**
+     * @return true if double has its default MetaClass
+     */
+    public static boolean isOrigD(){
+       return DefaultMetaClassInfo.isOrigDouble(); 
+    }
+
+    // ------------------ double[] ------------------
+    
+    /**
+     * @return true if double array has its default MetaClass
+     */
+    public static boolean isOrigDArray(){
+       return false; 
+    }
+    
+    /**
+     * get value from double[] using normalized index
+     */
+    public static double dArrayGet(double[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from double[] using normalized index
+     */
+    public static void dArraySet(double[] a, int i, double v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ Object[] ------------------
+    public static Object objectArrayGet(Object[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from double[] using normalized index
+     */
+    public static void objectArraySet(Object[] a, int i, Object v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ClassExtender.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ClassExtender.java b/src/main/java/org/codehaus/groovy/runtime/ClassExtender.java
new file mode 100644
index 0000000..6e5d371
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ClassExtender.java
@@ -0,0 +1,89 @@
+/*
+ *  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 java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * A helper class used by the runtime to allow Groovy classes to be extended at runtime
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ClassExtender {
+    private Map variables;
+    private Map methods;
+
+    public synchronized Object get(String name) {
+        if (variables != null) {
+            return variables.get(name);
+        }
+        return null;
+    }
+
+    public synchronized void set(String name, Object value) {
+        if (variables == null) {
+            variables = createMap();
+        }
+        variables.put(name, value);
+    }
+
+    public synchronized void remove(String name) {
+        if (variables != null) {
+            variables.remove(name);
+        }
+    }
+
+    public void call(String name, Object params) {
+        Closure closure = null;
+        synchronized (this) {
+            if (methods != null) {
+                closure = (Closure) methods.get(name);
+            }
+        }
+        if (closure != null) {
+            closure.call(params);
+        }
+        /*
+        else {
+            throw DoesNotUnderstandException();
+        }
+        */
+    }
+
+    public synchronized void addMethod(String name, Closure closure) {
+        if (methods == null) {
+            methods = createMap();
+        }
+        methods.put(name, methods);
+    }
+
+    public synchronized void removeMethod(String name) {
+        if (methods != null) {
+            methods.remove(name);
+        }
+    }
+
+    protected Map createMap() {
+        return new HashMap();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ComposedClosure.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ComposedClosure.java b/src/main/java/org/codehaus/groovy/runtime/ComposedClosure.java
new file mode 100644
index 0000000..63e0406
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ComposedClosure.java
@@ -0,0 +1,108 @@
+/*
+ *  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 java.util.List;
+
+/**
+ * A wrapper for Closure to support composition.
+ * Normally used only internally through the <code>rightShift()</code> and
+ * <code>leftShift()</code> methods on <code>Closure</code>.
+ * <p>
+ * Typical usages:
+ * <pre class="groovyTestCase">
+ * def twice = { a -> a * 2 }
+ * def inc = { b -> b + 1 }
+ * def f = { x -> twice(inc(x)) } // longhand
+ * def g = inc >> twice
+ * def h = twice << inc
+ * assert f(10) == 22
+ * assert g(10) == 22
+ * assert h(10) == 22
+ *
+ * def s2c = { it.chars[0] }
+ * def p = Integer.&toHexString >> s2c >> Character.&toUpperCase
+ * assert p(15) == 'F'
+ *
+ * def multiply = { a, b -> a * b }
+ * def identity = { a -> [a, a] }
+ * def sq = identity >> multiply
+ * assert (1..5).collect{ sq(it) } == [1, 4, 9, 16, 25]
+ *
+ * def add3 = { a, b, c -> a + b + c }
+ * def add2plus10 = add3.curry(10)
+ * def multBoth = { a, b, c -> [a*c, b*c] }
+ * def twiceBoth = multBoth.rcurry(2)
+ * def twiceBothPlus10 = twiceBoth >> add2plus10
+ * assert twiceBothPlus10(5, 10) == 40
+ * </pre>
+ *
+ * @author Paul King
+ */
+public final class ComposedClosure<V> extends Closure<V> {
+
+    private final Closure first;
+    private final Closure<V> second;
+
+    public ComposedClosure(Closure first, Closure<V> second) {
+        super(first.clone());
+        this.first = (Closure) getOwner();
+        this.second = (Closure<V>) second.clone();
+        maximumNumberOfParameters = first.getMaximumNumberOfParameters();
+    }
+
+    public void setDelegate(Object delegate) {
+        ((Closure) getOwner()).setDelegate(delegate);
+        second.setDelegate(delegate);
+    }
+
+    public Object getDelegate() {
+        return ((Closure) getOwner()).getDelegate();
+    }
+
+    public void setResolveStrategy(int resolveStrategy) {
+        ((Closure) getOwner()).setResolveStrategy(resolveStrategy);
+        second.setResolveStrategy(resolveStrategy);
+    }
+
+    public int getResolveStrategy() {
+        return ((Closure) getOwner()).getResolveStrategy();
+    }
+
+    public Object clone() {
+        return new ComposedClosure<V>(first, second);
+    }
+
+    public Class[] getParameterTypes() {
+        return first.getParameterTypes();
+    }
+
+    public Object doCall(Object... args) {
+        return call(args);
+    }
+
+    @Override
+    public V call(Object... args) {
+        Object temp = first.call(args);
+        if (temp instanceof List && second.getParameterTypes().length > 1) temp = ((List) temp).toArray();
+        return temp instanceof Object[] ? second.call((Object[]) temp) : second.call(temp);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java b/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java
new file mode 100644
index 0000000..8bf7c69
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java
@@ -0,0 +1,224 @@
+/*
+ *  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.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.GroovySystem;
+import groovy.lang.MetaClass;
+import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
+import org.codehaus.groovy.vmplugin.VMPlugin;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This class is a general adapter to map a call to a Java interface
+ * to a given delegate.
+ *
+ * @author Ben Yu
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ */
+public abstract class ConversionHandler implements InvocationHandler, Serializable {
+    private final Object delegate;
+    private static final long serialVersionUID = 1162833717190835227L;
+    private final ConcurrentHashMap<Method, Object> handleCache;
+    {
+        if (VMPluginFactory.getPlugin().getVersion() >= 7) {
+            handleCache = new ConcurrentHashMap<Method, Object>(16, 0.9f, 2);
+        } else {
+            handleCache = null;
+        }
+    }
+
+    private MetaClass metaClass;
+
+    /**
+     * Creates a ConversionHandler with an delegate.
+     *
+     * @param delegate the delegate
+     * @throws IllegalArgumentException if the given delegate is null
+     */
+    public ConversionHandler(Object delegate) {
+        if (delegate == null) {
+            throw new IllegalArgumentException("delegate must not be null");
+        }
+        this.delegate = delegate;
+    }
+
+    /**
+     * Returns the delegate.
+     *
+     * @return the delegate
+     */
+    public Object getDelegate() {
+        return delegate;
+    }
+
+    /**
+     * This method is a default implementation for the invoke method given in
+     * InvocationHandler. Any call to a method with a declaring class that is
+     * not Object, excluding toString() and default methods is redirected to invokeCustom.
+     * <p>
+     * Methods like equals and hashcode are called on the class itself instead
+     * of the delegate because they are considered fundamental methods that should
+     * not be overwritten. The toString() method gets special treatment as it is
+     * deemed to be a method that you might wish to override when called from Groovy.
+     * Interface default methods from Java 8 on the other hand are considered being
+     * default implementations you don't normally want to change. So they are called
+     * directly too
+     * </p><p>
+     * In many scenarios, it is better to overwrite the invokeCustom method where
+     * the core Object related methods are filtered out.
+     *</p>
+     * @param proxy  the proxy
+     * @param method the method
+     * @param args   the arguments
+     * @return the result of the invocation by method or delegate
+     * @throws Throwable if caused by the delegate or the method
+     * @see #invokeCustom(Object, Method, Object[])
+     * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+     */
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if (handleCache != null && isDefaultMethod(method)) {
+            VMPlugin plugin = VMPluginFactory.getPlugin();
+            Object handle = handleCache.get(method);
+            if (handle == null) {
+                handle = plugin.getInvokeSpecialHandle(method, proxy);
+                handleCache.put(method, handle);
+            }
+            return plugin.invokeHandle(handle, args);
+        }
+
+        if (!checkMethod(method)) {
+            try {
+                if (method.getDeclaringClass() == GroovyObject.class) {
+                    if ("getMetaClass".equals(method.getName())) {
+                        return getMetaClass(proxy);
+                    } else if ("setMetaClass".equals(method.getName())) {
+                        return setMetaClass((MetaClass) args[0]);
+                    }
+                }
+                return invokeCustom(proxy, method, args);
+            } catch (GroovyRuntimeException gre) {
+                throw ScriptBytecodeAdapter.unwrap(gre);
+            }
+        }
+
+        try {
+            return method.invoke(this, args);
+        } catch (InvocationTargetException ite) {
+            throw ite.getTargetException();
+        }
+    }
+
+    protected boolean isDefaultMethod(Method method) {
+        return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
+                Modifier.PUBLIC) && method.getDeclaringClass().isInterface();
+    }
+
+    protected boolean checkMethod(Method method) {
+        return isCoreObjectMethod(method);
+    }
+
+    /**
+     * This method is called for all Methods not defined on Object.
+     * The delegate should be called here.
+     *
+     * @param proxy  the proxy
+     * @param method the method
+     * @param args   the arguments
+     * @return the result of the invocation of the delegate
+     * @throws Throwable any exception causes by the delegate
+     * @see #invoke(Object, Method, Object[])
+     * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+     */
+    public abstract Object invokeCustom(Object proxy, Method method, Object[] args) throws Throwable;
+
+    /**
+     * Indicates whether some other object is "equal to" this one.
+     * The delegate is used if the class of the parameter and the
+     * current class are equal. In other cases the method will return
+     * false. The exact class is here used, if inheritance is needed,
+     * this method must be overwritten.
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof Proxy) {
+            obj = Proxy.getInvocationHandler(obj);
+        }
+
+        if (obj instanceof ConversionHandler) {
+            return (((ConversionHandler) obj).getDelegate()).equals(delegate);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns a hash code value for the delegate.
+     *
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return delegate.hashCode();
+    }
+
+    /**
+     * Returns a String version of the delegate.
+     *
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return delegate.toString();
+    }
+
+    /**
+     * Checks whether a method is a core method from java.lang.Object.
+     * Such methods often receive special treatment because they are
+     * deemed fundamental enough to not be tampered with.
+     *
+     * @param method the method to check
+     * @return true if the method is deemed to be a core method
+     */
+    public static boolean isCoreObjectMethod(Method method) {
+        return Object.class.equals(method.getDeclaringClass());
+    }
+
+    private MetaClass setMetaClass(MetaClass mc) {
+        metaClass = mc;
+        return mc;
+    }
+
+    private MetaClass getMetaClass(Object proxy) {
+        MetaClass mc = metaClass;
+        if (mc == null) {
+            mc = ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(proxy);
+            metaClass = mc;
+        }
+        return mc;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.java b/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.java
new file mode 100644
index 0000000..dfc7ea0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.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 java.io.Serializable;
+import java.lang.reflect.Method;
+
+/**
+ * This class is a general adapter to adapt a closure to any Java interface.
+ * <p>
+ * @author Ben Yu
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * Jul 27, 2006 3:50:51 PM
+ */
+public class ConvertedClosure extends ConversionHandler implements Serializable {
+    private final String methodName;
+    private static final long serialVersionUID = 1162833713450835227L;
+
+    /**
+     * to create a ConvertedClosure object.
+     * @param closure the closure object.
+     */
+    public ConvertedClosure(Closure closure, String method) {
+        super(closure);
+        this.methodName = method;
+    }
+    
+    public ConvertedClosure(Closure closure) {
+        this(closure,null);
+    }
+
+    @Override
+    public Object invokeCustom(Object proxy, Method method, Object[] args)
+    throws Throwable {
+        if (methodName!=null && !methodName.equals(method.getName())) return null;
+        return ((Closure) getDelegate()).call(args);
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ConvertedMap.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ConvertedMap.java b/src/main/java/org/codehaus/groovy/runtime/ConvertedMap.java
new file mode 100644
index 0000000..393d55e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ConvertedMap.java
@@ -0,0 +1,80 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * This class is a general adapter to adapt a map of closures to
+ * any Java interface.
+ *
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ */
+public class ConvertedMap extends ConversionHandler {
+
+    /**
+     * to create a ConvertedMap object.
+     *
+     * @param closures the map of closures
+     */
+    protected ConvertedMap(Map closures) {
+        super(closures);
+    }
+
+    @Override
+    public Object invokeCustom(Object proxy, Method method, Object[] args)
+            throws Throwable {
+        Map m = (Map) getDelegate();
+        Closure cl = (Closure) m.get(method.getName());
+        if(cl == null && "toString".equals(method.getName())) {
+            return m.toString();
+        }
+        if (cl == null) {
+            throw new UnsupportedOperationException();
+        }
+        return cl.call(args);
+    }
+
+    @Override
+    public String toString() {
+        return DefaultGroovyMethods.toString(getDelegate());
+    }
+
+    @Override
+    protected boolean checkMethod(Method method) {
+        return isCoreObjectMethod(method);
+    }
+
+    /**
+     * Checks whether a method is a core method from java.lang.Object.
+     * Such methods often receive special treatment because they are
+     * deemed fundamental enough to not be tampered with.
+     * call toString() is an exception to allow overriding toString() by a closure specified in the map
+     *
+     * @param method the method to check
+     * @return true if the method is deemed to be a core method
+     */
+    public static boolean isCoreObjectMethod(Method method) {
+        return ConversionHandler.isCoreObjectMethod(method) && !"toString".equals(method.getName());
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/CurriedClosure.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/CurriedClosure.java b/src/main/java/org/codehaus/groovy/runtime/CurriedClosure.java
new file mode 100644
index 0000000..cabe230
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/CurriedClosure.java
@@ -0,0 +1,192 @@
+/*
+ *  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;
+
+/**
+ * A wrapper for Closure to support currying.
+ * Normally used only internally through the <code>curry()</code>, <code>rcurry()</code> or
+ * <code>ncurry()</code> methods on <code>Closure</code>.
+ * Typical usages:
+ * <pre class="groovyTestCase">
+ * // normal usage
+ * def unitAdder = { first, second, unit -> "${first + second} $unit" }
+ * assert unitAdder(10, 15, "minutes") == "25 minutes"
+ * assert unitAdder.curry(60)(15, "minutes") == "75 minutes"
+ * def minuteAdder = unitAdder.rcurry("minutes")
+ * assert minuteAdder(15, 60) == "75 minutes"
+ *
+ * // explicit creation
+ * import org.codehaus.groovy.runtime.CurriedClosure
+ * assert new CurriedClosure(unitAdder, 45)(15, "minutes") == "60 minutes"
+ * assert new CurriedClosure(unitAdder, "six", "ty")("minutes") == "sixty minutes"
+ * </pre>
+ *
+ * Notes:
+ * <ul>
+ *     <li>Caters for Groovy's lazy (rcurry) and eager (ncurry) calculation of argument position</li>
+ * </ul>
+ */
+public final class CurriedClosure<V> extends Closure<V> {
+
+    private final Object[] curriedParams;
+    private final int minParamsExpected;
+    private int index;
+    private Class varargType = null;
+
+    /**
+     * Creates the curried closure.
+     *
+     * @param index the position where the parameters should be injected (-ve for lazy)
+     * @param uncurriedClosure the closure to be called after the curried parameters are injected
+     * @param arguments the supplied parameters
+     */
+    public CurriedClosure(int index, Closure<V> uncurriedClosure, Object... arguments) {
+        super(uncurriedClosure.clone());
+        curriedParams = arguments;
+        this.index = index;
+        final int origMaxLen = uncurriedClosure.getMaximumNumberOfParameters();
+        maximumNumberOfParameters = origMaxLen - arguments.length;
+        Class[] classes = uncurriedClosure.getParameterTypes();
+        Class lastType = classes.length == 0 ? null : classes[classes.length-1];
+        if (lastType != null && lastType.isArray()) {
+            varargType = lastType;
+        }
+
+        if (!isVararg()) {
+            // perform some early param checking for non-vararg case
+            if (index < 0) {
+                // normalise
+                this.index += origMaxLen;
+                minParamsExpected = 0;
+            } else {
+                minParamsExpected = index + arguments.length;
+            }
+            if (maximumNumberOfParameters < 0) {
+                throw new IllegalArgumentException("Can't curry " + arguments.length + " arguments for a closure with " + origMaxLen + " parameters.");
+            }
+            if (index < 0) {
+                if (index < -origMaxLen || index > -arguments.length)
+                    throw new IllegalArgumentException("To curry " + arguments.length + " argument(s) expect index range " +
+                            (-origMaxLen) + ".." + (-arguments.length) + " but found " + index);
+            } else if (index > maximumNumberOfParameters) {
+                throw new IllegalArgumentException("To curry " + arguments.length + " argument(s) expect index range 0.." +
+                        maximumNumberOfParameters + " but found " + index);
+            }
+        } else {
+            minParamsExpected = 0;
+        }
+    }
+
+    public CurriedClosure(Closure<V> uncurriedClosure, Object... arguments) {
+        this(0, uncurriedClosure, arguments);
+    }
+
+    public Object[] getUncurriedArguments(Object... arguments) {
+        if (isVararg()) {
+            int normalizedIndex = index < 0 ? index + arguments.length + curriedParams.length : index;
+            if (normalizedIndex < 0 || normalizedIndex > arguments.length) {
+                throw new IllegalArgumentException("When currying expected index range between " +
+                        (-arguments.length - curriedParams.length) + ".." + (arguments.length + curriedParams.length) + " but found " + index);
+            }
+            return createNewCurriedParams(normalizedIndex, arguments);
+        }
+        if (curriedParams.length + arguments.length < minParamsExpected) {
+            throw new IllegalArgumentException("When currying expected at least " + index + " argument(s) to be supplied before known curried arguments but found " + arguments.length);
+        }
+        int newIndex = Math.min(index, curriedParams.length + arguments.length - 1);
+        // rcurried arguments are done lazily to allow normal method selection between overloaded alternatives
+        newIndex = Math.min(newIndex, arguments.length);
+        return createNewCurriedParams(newIndex, arguments);
+    }
+
+    private Object[] createNewCurriedParams(int normalizedIndex, Object[] arguments) {
+        Object[] newCurriedParams = new Object[curriedParams.length + arguments.length];
+        System.arraycopy(arguments, 0, newCurriedParams, 0, normalizedIndex);
+        System.arraycopy(curriedParams, 0, newCurriedParams, normalizedIndex, curriedParams.length);
+        if (arguments.length - normalizedIndex > 0)
+            System.arraycopy(arguments, normalizedIndex, newCurriedParams, curriedParams.length + normalizedIndex, arguments.length - normalizedIndex);
+        return newCurriedParams;
+    }
+
+    public void setDelegate(Object delegate) {
+        ((Closure) getOwner()).setDelegate(delegate);
+    }
+
+    public Object getDelegate() {
+        return ((Closure) getOwner()).getDelegate();
+    }
+
+    public void setResolveStrategy(int resolveStrategy) {
+        ((Closure) getOwner()).setResolveStrategy(resolveStrategy);
+    }
+
+    public int getResolveStrategy() {
+        return ((Closure) getOwner()).getResolveStrategy();
+    }
+
+    @SuppressWarnings("unchecked")
+    public Object clone() {
+        Closure<V> uncurriedClosure = (Closure<V>) ((Closure) getOwner()).clone();
+        return new CurriedClosure<V>(index, uncurriedClosure, curriedParams);
+    }
+
+    public Class[] getParameterTypes() {
+        Class[] oldParams = ((Closure) getOwner()).getParameterTypes();
+        int extraParams = 0;
+        int gobbledParams = curriedParams.length;
+        if (isVararg()) {
+            int numNonVarargs = oldParams.length - 1;
+            if (index < 0) {
+                int absIndex = -index;
+                // do -ve indexes based on actual args, so can't accurately calculate type here
+                // so work out minimal type params and vararg on end will allow for other possibilities
+                if (absIndex > numNonVarargs) gobbledParams = numNonVarargs;
+                int newNumNonVarargs = numNonVarargs - gobbledParams;
+                if (absIndex - curriedParams.length > newNumNonVarargs) extraParams = absIndex - curriedParams.length - newNumNonVarargs;
+                int keptParams = Math.max(numNonVarargs - absIndex, 0);
+                Class[] newParams = new Class[keptParams + newNumNonVarargs + extraParams + 1];
+                System.arraycopy(oldParams, 0, newParams, 0, keptParams);
+                for (int i = 0; i < newNumNonVarargs; i++) newParams[keptParams + i] = Object.class;
+                for (int i = 0; i < extraParams; i++) newParams[keptParams + newNumNonVarargs + i] = varargType.getComponentType();
+                newParams[newParams.length - 1] = varargType;
+                return newParams;
+            }
+            int leadingKept = Math.min(index, numNonVarargs);
+            int trailingKept = Math.max(numNonVarargs - leadingKept - curriedParams.length, 0);
+            if (index > leadingKept) extraParams = index - leadingKept;
+            Class[] newParams = new Class[leadingKept + trailingKept + extraParams + 1];
+            System.arraycopy(oldParams, 0, newParams, 0, leadingKept);
+            if (trailingKept > 0) System.arraycopy(oldParams, leadingKept + curriedParams.length, newParams, leadingKept, trailingKept);
+            for (int i = 0; i < extraParams; i++) newParams[leadingKept + trailingKept + i] = varargType.getComponentType();
+            newParams[newParams.length - 1] = varargType;
+            return newParams;
+        }
+        Class[] newParams = new Class[oldParams.length - gobbledParams + extraParams];
+        System.arraycopy(oldParams, 0, newParams, 0, index);
+        if (newParams.length - index > 0)
+            System.arraycopy(oldParams, curriedParams.length + index, newParams, index, newParams.length - index);
+        return newParams;
+    }
+
+    private boolean isVararg() {
+        return varargType != null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java
new file mode 100644
index 0000000..1c30802
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java
@@ -0,0 +1,775 @@
+/*
+ *  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.GroovyRuntimeException;
+
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+/**
+ * This class defines new groovy methods which appear on normal JDK
+ * Date and Calendar classes inside the Groovy environment.
+ */
+public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
+
+    /**
+     * Support the subscript operator for a Date.
+     *
+     * @param self  a Date
+     * @param field a Calendar field, e.g. MONTH
+     * @return the value for the given field, e.g. FEBRUARY
+     * @see java.util.Calendar
+     * @since 1.5.5
+     */
+    public static int getAt(Date self, int field) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        return cal.get(field);
+    }
+
+    /**
+     * Convert a Date to a Calendar.
+     *
+     * @param self a Date
+     * @return a Calendar corresponding to the given Date
+     * @since 1.7.6
+     */
+    public static Calendar toCalendar(Date self) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        return cal;
+    }
+
+    /**
+     * Support the subscript operator for a Calendar.
+     *
+     * @param self  a Calendar
+     * @param field a Calendar field, e.g. MONTH
+     * @return the value for the given field, e.g. FEBRUARY
+     * @see java.util.Calendar
+     * @since 1.7.3
+     */
+    public static int getAt(Calendar self, int field) {
+        return self.get(field);
+    }
+
+    /**
+     * Support the subscript operator for mutating a Calendar.
+     * Example usage:
+     * <pre>
+     * import static java.util.Calendar.*
+     * def cal = Calendar.instance
+     * cal[DAY_OF_WEEK] = MONDAY
+     * cal[MONTH] = MARCH
+     * println cal.time // A Monday in March
+     * </pre>
+     *
+     * @param self  A Calendar
+     * @param field A Calendar field, e.g. MONTH
+     * @param value The value for the given field, e.g. FEBRUARY
+     * @see java.util.Calendar#set(int, int)
+     * @since 1.7.3
+     */
+    public static void putAt(Calendar self, int field, int value) {
+        self.set(field, value);
+    }
+
+    /**
+     * Support the subscript operator for mutating a Date.
+     *
+     * @param self  A Date
+     * @param field A Calendar field, e.g. MONTH
+     * @param value The value for the given field, e.g. FEBRUARY
+     * @see #putAt(java.util.Calendar, int, int)
+     * @see java.util.Calendar#set(int, int)
+     * @since 1.7.3
+     */
+    public static void putAt(Date self, int field, int value) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        putAt(cal, field, value);
+        self.setTime(cal.getTimeInMillis());
+    }
+
+    /**
+     * Support mutating a Calendar with a Map.
+     * <p>
+     * The map values are the normal values provided as the
+     * second parameter to <code>java.util.Calendar#set(int, int)</code>.
+     * The keys can either be the normal fields values provided as
+     * the first parameter to that method or one of the following Strings:
+     * <table border="1" cellpadding="4">
+     *   <caption>Calendar index values</caption>
+     *   <tr><td>year</td><td>Calendar.YEAR</td></tr>
+     *   <tr><td>month</td><td>Calendar.MONTH</td></tr>
+     *   <tr><td>date</td><td>Calendar.DATE</td></tr>
+     *   <tr><td>dayOfMonth</td><td>Calendar.DATE</td></tr>
+     *   <tr><td>hourOfDay</td><td>Calendar.HOUR_OF_DAY</td></tr>
+     *   <tr><td>minute</td><td>Calendar.MINUTE</td></tr>
+     *   <tr><td>second</td><td>Calendar.SECOND</td></tr>
+     * </table>
+     * Example usage:
+     * <pre>
+     * import static java.util.Calendar.*
+     * def cal = Calendar.instance
+     * def m = [:]
+     * m[YEAR] = 2010
+     * m[MONTH] = DECEMBER
+     * m[DATE] = 25
+     * cal.set(m)
+     * println cal.time // Christmas 2010
+     *
+     * cal.set(year:2011, month:DECEMBER, date:25)
+     * println cal.time // Christmas 2010
+     * </pre>
+     *
+     * @param self    A Calendar
+     * @param updates A Map of Calendar keys and values
+     * @see java.util.Calendar#set(int, int)
+     * @see java.util.Calendar#set(int, int, int, int, int, int)
+     * @since 1.7.3
+     */
+    public static void set(Calendar self, Map<Object, Integer> updates) {
+        for (Map.Entry<Object, Integer> entry : updates.entrySet()) {
+            Object key = entry.getKey();
+            if (key instanceof String) key = CAL_MAP.get(key);
+            if (key instanceof Integer) self.set((Integer) key, entry.getValue());
+        }
+    }
+
+    /**
+     * Legacy alias for copyWith. Will be deprecated and removed in future versions of Groovy.
+     *
+     * @see #copyWith(java.util.Calendar, java.util.Map)
+     * @since 1.7.3
+     */
+    public static Calendar updated(Calendar self, Map<Object, Integer> updates) {
+        Calendar result = (Calendar) self.clone();
+        set(result, updates);
+        return result;
+    }
+
+    /**
+     * Support creating a new Date having similar properties to
+     * an existing Date (which remains unaltered) but with
+     * some fields updated according to a Map of changes.
+     * <p>
+     * Example usage:
+     * <pre>
+     * import static java.util.Calendar.YEAR
+     * def now = Calendar.instance
+     * def nextYear = now[YEAR] + 1
+     * def oneYearFromNow = now.copyWith(year: nextYear)
+     * println now.time
+     * println oneYearFromNow.time
+     * </pre>
+     *
+     * @param self    A Calendar
+     * @param updates A Map of Calendar keys and values
+     * @return The newly created Calendar
+     * @see java.util.Calendar#set(int, int)
+     * @see java.util.Calendar#set(int, int, int, int, int, int)
+     * @see #set(java.util.Calendar, java.util.Map)
+     * @since 2.2.0
+     */
+    public static Calendar copyWith(Calendar self, Map<Object, Integer> updates) {
+        Calendar result = (Calendar) self.clone();
+        set(result, updates);
+        return result;
+    }
+
+    /**
+     * Support mutating a Date with a Map.
+     * <p>
+     * The map values are the normal values provided as the
+     * second parameter to <code>java.util.Calendar#set(int, int)</code>.
+     * The keys can either be the normal fields values provided as
+     * the first parameter to that method or one of the following Strings:
+     * <table border="1" cellpadding="4">
+     *   <caption>Calendar index values</caption>
+     *   <tr><td>year</td><td>Calendar.YEAR</td></tr>
+     *   <tr><td>month</td><td>Calendar.MONTH</td></tr>
+     *   <tr><td>date</td><td>Calendar.DATE</td></tr>
+     *   <tr><td>dayOfMonth</td><td>Calendar.DATE</td></tr>
+     *   <tr><td>hourOfDay</td><td>Calendar.HOUR_OF_DAY</td></tr>
+     *   <tr><td>minute</td><td>Calendar.MINUTE</td></tr>
+     *   <tr><td>second</td><td>Calendar.SECOND</td></tr>
+     * </table>
+     * Example usage:
+     * <pre>
+     * import static java.util.Calendar.YEAR
+     * def date = new Date()
+     * def nextYear = date[YEAR] + 1
+     * date.set(year: nextYear)
+     * println date
+     * </pre>
+     *
+     * @param self    A Date
+     * @param updates A Map of Calendar keys and values
+     * @see java.util.Calendar#set(int, int)
+     * @see #set(java.util.Calendar, java.util.Map)
+     * @since 1.7.3
+     */
+    public static void set(Date self, Map<Object, Integer> updates) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        set(cal, updates);
+        self.setTime(cal.getTimeInMillis());
+    }
+
+    /**
+     * Legacy alias for copyWith. Will be deprecated and removed in future versions of Groovy.
+     *
+     * @see #copyWith(java.util.Date, java.util.Map)
+     * @since 1.7.3
+     */
+    public static Date updated(Date self, Map<Object, Integer> updates) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        set(cal, updates);
+        return cal.getTime();
+    }
+
+    /**
+     * Support creating a new Date having similar properties to
+     * an existing Date (which remains unaltered) but with
+     * some fields updated according to a Map of changes.
+     * <p>
+     * Example usage:
+     * <pre>
+     * import static java.util.Calendar.YEAR
+     * def today = new Date()
+     * def nextYear = today[YEAR] + 1
+     * def oneYearFromNow = today.copyWith(year: nextYear)
+     * println today
+     * println oneYearFromNow
+     * </pre>
+     *
+     * @param self    A Date
+     * @param updates A Map of Calendar keys and values
+     * @return The newly created Date
+     * @see java.util.Calendar#set(int, int)
+     * @see #set(java.util.Date, java.util.Map)
+     * @see #copyWith(java.util.Calendar, java.util.Map)
+     * @since 2.2.0
+     */
+    public static Date copyWith(Date self, Map<Object, Integer> updates) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        set(cal, updates);
+        return cal.getTime();
+    }
+
+    private static final Map<String, Integer> CAL_MAP = new HashMap<String, Integer>();
+
+    static {
+        CAL_MAP.put("year", Calendar.YEAR);
+        CAL_MAP.put("month", Calendar.MONTH);
+        CAL_MAP.put("date", Calendar.DATE);
+        CAL_MAP.put("dayOfMonth", Calendar.DATE);
+        CAL_MAP.put("hourOfDay", Calendar.HOUR_OF_DAY);
+        CAL_MAP.put("minute", Calendar.MINUTE);
+        CAL_MAP.put("second", Calendar.SECOND);
+    }
+
+    /**
+     * Increment a Date by one day.
+     *
+     * @param self a Date
+     * @return the next days date
+     * @since 1.0
+     */
+    public static Date next(Date self) {
+        return plus(self, 1);
+    }
+
+    /**
+     * Increment a Calendar by one day.
+     *
+     * @param self a Calendar
+     * @return a new Calendar set to the next day
+     * @since 1.8.7
+     */
+    public static Calendar next(Calendar self) {
+        Calendar result = (Calendar) self.clone();
+        result.add(Calendar.DAY_OF_YEAR, 1);
+        return result;
+    }
+
+    /**
+     * Decrement a Calendar by one day.
+     *
+     * @param self a Calendar
+     * @return a new Calendar set to the previous day
+     * @since 1.8.7
+     */
+    public static Calendar previous(Calendar self) {
+        Calendar result = (Calendar) self.clone();
+        result.add(Calendar.DAY_OF_YEAR, -1);
+        return result;
+    }
+
+    /**
+     * Increment a java.sql.Date by one day.
+     *
+     * @param self a java.sql.Date
+     * @return the next days date
+     * @since 1.0
+     */
+    public static java.sql.Date next(java.sql.Date self) {
+        return new java.sql.Date(next((Date) self).getTime());
+    }
+
+    /**
+     * Decrement a Date by one day.
+     *
+     * @param self a Date
+     * @return the previous days date
+     * @since 1.0
+     */
+    public static Date previous(Date self) {
+        return minus(self, 1);
+    }
+
+    /**
+     * Decrement a java.sql.Date by one day.
+     *
+     * @param self a java.sql.Date
+     * @return the previous days date
+     * @since 1.0
+     */
+    public static java.sql.Date previous(java.sql.Date self) {
+        return new java.sql.Date(previous((Date) self).getTime());
+    }
+
+    /**
+     * Add a number of days to this date and returns the new date.
+     *
+     * @param self a Date
+     * @param days the number of days to increase
+     * @return the new date
+     * @since 1.0
+     */
+    public static Date plus(Date self, int days) {
+        Calendar calendar = (Calendar) Calendar.getInstance().clone();
+        calendar.setTime(self);
+        calendar.add(Calendar.DAY_OF_YEAR, days);
+        return calendar.getTime();
+    }
+
+    /**
+     * Add a number of days to this date and returns the new date.
+     *
+     * @param self a java.sql.Date
+     * @param days the number of days to increase
+     * @return the new date
+     * @since 1.0
+     */
+    public static java.sql.Date plus(java.sql.Date self, int days) {
+        return new java.sql.Date(plus((Date) self, days).getTime());
+    }
+
+    /**
+     * Add number of days to this Timestamp and returns the new Timestamp object.
+     *
+     * @param self a Timestamp
+     * @param days the number of days to increase
+     * @return the new Timestamp
+     */
+    public static Timestamp plus(Timestamp self, int days) {
+        Calendar calendar = (Calendar) Calendar.getInstance().clone();
+        calendar.setTime(self);
+        calendar.add(Calendar.DAY_OF_YEAR, days);
+        Timestamp ts = new Timestamp(calendar.getTime().getTime());
+        ts.setNanos(self.getNanos());
+        return ts;
+    }
+
+    /**
+     * Subtract a number of days from this date and returns the new date.
+     *
+     * @param self a Date
+     * @param days the number of days to subtract
+     * @return the new date
+     * @since 1.0
+     */
+    public static Date minus(Date self, int days) {
+        return plus(self, -days);
+    }
+
+    /**
+     * Subtract a number of days from this date and returns the new date.
+     *
+     * @param self a java.sql.Date
+     * @param days the number of days to subtract
+     * @return the new date
+     * @since 1.0
+     */
+    public static java.sql.Date minus(java.sql.Date self, int days) {
+        return new java.sql.Date(minus((Date) self, days).getTime());
+    }
+
+    /**
+     * Subtract a number of days from this Timestamp and returns the new Timestamp object.
+     *
+     * @param self a Timestamp
+     * @param days the number of days to subtract
+     * @return the new Timestamp
+     */
+    public static Timestamp minus(Timestamp self, int days) {
+        return plus(self, -days);
+    }
+
+    /**
+     * Subtract another date from this one and return the number of days of the difference.
+     * <p>
+     * Date self = Date then + (Date self - Date then)
+     * <p>
+     * IOW, if self is before then the result is a negative value.
+     *
+     * @param self a Calendar
+     * @param then another Calendar
+     * @return number of days
+     * @since 1.6.0
+     */
+    public static int minus(Calendar self, Calendar then) {
+        Calendar a = self;
+        Calendar b = then;
+
+        boolean swap = a.before(b);
+
+        if (swap) {
+            Calendar t = a;
+            a = b;
+            b = t;
+        }
+
+        int days = 0;
+
+        b = (Calendar) b.clone();
+
+        while (a.get(Calendar.YEAR) > b.get(Calendar.YEAR)) {
+            days += 1 + (b.getActualMaximum(Calendar.DAY_OF_YEAR) - b.get(Calendar.DAY_OF_YEAR));
+            b.set(Calendar.DAY_OF_YEAR, 1);
+            b.add(Calendar.YEAR, 1);
+        }
+
+        days += a.get(Calendar.DAY_OF_YEAR) - b.get(Calendar.DAY_OF_YEAR);
+
+        if (swap) days = -days;
+
+        return days;
+    }
+
+    /**
+     * Subtract another Date from this one and return the number of days of the difference.
+     * <p>
+     * Date self = Date then + (Date self - Date then)
+     * <p>
+     * IOW, if self is before then the result is a negative value.
+     *
+     * @param self a Date
+     * @param then another Date
+     * @return number of days
+     * @since 1.6.0
+     */
+    public static int minus(Date self, Date then) {
+        Calendar a = (Calendar) Calendar.getInstance().clone();
+        a.setTime(self);
+        Calendar b = (Calendar) Calendar.getInstance().clone();
+        b.setTime(then);
+        return minus(a, b);
+    }
+
+    /**
+     * <p>Create a String representation of this date according to the given
+     * format pattern.
+     * <p>
+     * <p>For example, if the system timezone is GMT,
+     * <code>new Date(0).format('MM/dd/yy')</code> would return the string
+     * <code>"01/01/70"</code>. See documentation for {@link java.text.SimpleDateFormat}
+     * for format pattern use.
+     * <p>
+     * <p>Note that a new DateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self   a Date
+     * @param format the format pattern to use according to {@link java.text.SimpleDateFormat}
+     * @return a string representation of this date.
+     * @see java.text.SimpleDateFormat
+     * @since 1.5.7
+     */
+    public static String format(Date self, String format) {
+        return new SimpleDateFormat(format).format(self);
+    }
+
+    /**
+     * <p>Create a String representation of this date according to the given
+     * format pattern and timezone.
+     * <p>
+     * <p>For example:
+     * <code>
+     * def d = new Date(0)
+     * def tz = TimeZone.getTimeZone('GMT')
+     * println d.format('dd/MMM/yyyy', tz)
+     * </code> would return the string
+     * <code>"01/Jan/1970"</code>. See documentation for {@link java.text.SimpleDateFormat}
+     * for format pattern use.
+     * <p>
+     * <p>Note that a new DateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self   a Date
+     * @param format the format pattern to use according to {@link java.text.SimpleDateFormat}
+     * @param tz     the TimeZone to use
+     * @return a string representation of this date.
+     * @see java.text.SimpleDateFormat
+     * @since 1.8.3
+     */
+    public static String format(Date self, String format, TimeZone tz) {
+        SimpleDateFormat sdf = new SimpleDateFormat(format);
+        sdf.setTimeZone(tz);
+        return sdf.format(self);
+    }
+
+    /**
+     * <p>Return a string representation of the 'day' portion of this date
+     * according to the locale-specific {@link java.text.DateFormat#SHORT} default format.
+     * For an "en_UK" system locale, this would be <code>dd/MM/yy</code>.
+     * <p>
+     * <p>Note that a new DateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self a Date
+     * @return a string representation of this date
+     * @see java.text.DateFormat#getDateInstance(int)
+     * @see java.text.DateFormat#SHORT
+     * @since 1.5.7
+     */
+    public static String getDateString(Date self) {
+        return DateFormat.getDateInstance(DateFormat.SHORT).format(self);
+    }
+
+    /**
+     * <p>Return a string representation of the time portion of this date
+     * according to the locale-specific {@link java.text.DateFormat#MEDIUM} default format.
+     * For an "en_UK" system locale, this would be <code>HH:MM:ss</code>.
+     * <p>
+     * <p>Note that a new DateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self a Date
+     * @return a string representing the time portion of this date
+     * @see java.text.DateFormat#getTimeInstance(int)
+     * @see java.text.DateFormat#MEDIUM
+     * @since 1.5.7
+     */
+    public static String getTimeString(Date self) {
+        return DateFormat.getTimeInstance(DateFormat.MEDIUM).format(self);
+    }
+
+    /**
+     * <p>Return a string representation of the date and time time portion of
+     * this Date instance, according to the locale-specific format used by
+     * {@link java.text.DateFormat}.  This method uses the {@link java.text.DateFormat#SHORT}
+     * preset for the day portion and {@link java.text.DateFormat#MEDIUM} for the time
+     * portion of the output string.
+     * <p>
+     * <p>Note that a new DateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self a Date
+     * @return a string representation of this date and time
+     * @see java.text.DateFormat#getDateTimeInstance(int, int)
+     * @since 1.5.7
+     */
+    public static String getDateTimeString(Date self) {
+        return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format(self);
+    }
+
+    /**
+     * Common code for {@link #clearTime(java.util.Calendar)} and {@link #clearTime(java.util.Date)}
+     * and {@link #clearTime(java.sql.Date)}
+     *
+     * @param self a Calendar to adjust
+     */
+    private static void clearTimeCommon(final Calendar self) {
+        self.set(Calendar.HOUR_OF_DAY, 0);
+        self.clear(Calendar.MINUTE);
+        self.clear(Calendar.SECOND);
+        self.clear(Calendar.MILLISECOND);
+    }
+
+    /**
+     * Clears the time portion of this Date instance; useful utility where
+     * it makes sense to compare month/day/year only portions of a Date.
+     *
+     * @param self a Date
+     * @return the Date but with the time portion cleared
+     * @since 1.6.7
+     */
+    public static Date clearTime(final Date self) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(self);
+        clearTimeCommon(calendar);
+        self.setTime(calendar.getTime().getTime());
+        return self;
+    }
+
+    /**
+     * Clears the time portion of this java.sql.Date instance; useful utility
+     * where it makes sense to compare month/day/year only portions of a Date.
+     *
+     * @param self a java.sql.Date
+     * @return the java.sql.Date but with the time portion cleared
+     * @since 1.6.7
+     */
+    public static java.sql.Date clearTime(final java.sql.Date self) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(self);
+        clearTimeCommon(calendar);
+        self.setTime(calendar.getTime().getTime());
+        return self;
+    }
+
+    /**
+     * Clears the time portion of this Calendar instance; useful utility
+     * where it makes sense to compare month/day/year only portions of a Calendar.
+     *
+     * @param self a Calendar
+     * @return the Calendar but with the time portion cleared
+     * @since 1.6.7
+     */
+    public static Calendar clearTime(final Calendar self) {
+        clearTimeCommon(self);
+        return self;
+    }
+
+    /**
+     * <p>Shortcut for {@link java.text.SimpleDateFormat} to output a String representation
+     * of this calendar instance.  This method respects the Calendar's assigned
+     * {@link java.util.TimeZone}, whereas calling <code>cal.time.format('HH:mm:ss')</code>
+     * would use the system timezone.
+     * <p>Note that Calendar equivalents of <code>date.getDateString()</code>
+     * and variants do not exist because those methods are Locale-dependent.
+     * Although a Calendar may be assigned a {@link java.util.Locale}, that information is
+     * lost and therefore cannot be used to control the default date/time formats
+     * provided by these methods.  Instead, the system Locale would always be
+     * used.  The alternative is to simply call
+     * {@link java.text.DateFormat#getDateInstance(int, java.util.Locale)} and pass the same Locale
+     * that was used for the Calendar.
+     *
+     * @param self    this calendar
+     * @param pattern format pattern
+     * @return String representation of this calendar with the given format.
+     * @see java.text.DateFormat#setTimeZone(java.util.TimeZone)
+     * @see java.text.SimpleDateFormat#format(java.util.Date)
+     * @see #format(java.util.Date, String)
+     * @since 1.6.0
+     */
+    public static String format(Calendar self, String pattern) {
+        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+        sdf.setTimeZone(self.getTimeZone());
+        return sdf.format(self.getTime());
+    }
+
+    /**
+     * Iterates from this date up to the given date, inclusive,
+     * incrementing by one day each time.
+     *
+     * @param self    a Date
+     * @param to      another Date to go up to
+     * @param closure the closure to call
+     * @since 2.2
+     */
+    public static void upto(Date self, Date to, Closure closure) {
+        if (self.compareTo(to) <= 0) {
+            for (Date i = (Date) self.clone(); i.compareTo(to) <= 0; i = next(i)) {
+                closure.call(i);
+            }
+        } else
+            throw new GroovyRuntimeException("The argument (" + to + 
+                    ") to upto() cannot be earlier than the value (" + self + ") it's called on.");
+    }
+
+    /**
+     * Iterates from the date represented by this calendar up to the date represented
+     * by the given calendar, inclusive, incrementing by one day each time.
+     *
+     * @param self    a Calendar
+     * @param to      another Calendar to go up to
+     * @param closure the closure to call
+     * @since 2.2
+     */
+    public static void upto(Calendar self, Calendar to, Closure closure) {
+        if (self.compareTo(to) <= 0) {
+            for (Calendar i = (Calendar) self.clone(); i.compareTo(to) <= 0; i = next(i)) {
+                closure.call(i);
+            }
+        } else
+            throw new GroovyRuntimeException("The argument (" + to + 
+                    ") to upto() cannot be earlier than the value (" + self + ") it's called on.");
+    }
+
+    /**
+     * Iterates from this date down to the given date, inclusive,
+     * decrementing by one day each time.
+     *
+     * @param self    a Date
+     * @param to      another Date to go down to
+     * @param closure the closure to call
+     * @since 2.2
+     */
+    public static void downto(Date self, Date to, Closure closure) {
+        if (self.compareTo(to) >= 0) {
+            for (Date i = (Date) self.clone(); i.compareTo(to) >= 0; i = previous(i)) {
+                closure.call(i);
+            }
+        } else
+            throw new GroovyRuntimeException("The argument (" + to + 
+                    ") to downto() cannot be later than the value (" + self + ") it's called on.");
+    }
+
+    /**
+     * Iterates from the date represented by this calendar up to the date represented
+     * by the given calendar, inclusive, incrementing by one day each time.
+     *
+     * @param self    a Calendar
+     * @param to      another Calendar to go down to
+     * @param closure the closure to call
+     * @since 2.2
+     */
+    public static void downto(Calendar self, Calendar to, Closure closure) {
+        if (self.compareTo(to) >= 0) {
+            for (Calendar i = (Calendar) self.clone(); i.compareTo(to) >= 0; i = previous(i)) {
+                closure.call(i);
+            }
+        } else
+            throw new GroovyRuntimeException("The argument (" + to + 
+                    ") to downto() cannot be later than the value (" + self + ") it's called on.");
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/DefaultCachedMethodKey.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultCachedMethodKey.java b/src/main/java/org/codehaus/groovy/runtime/DefaultCachedMethodKey.java
new file mode 100644
index 0000000..9dd8cd0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultCachedMethodKey.java
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.runtime;
+
+import org.codehaus.groovy.reflection.CachedClass;
+
+
+/**
+ * A default implementation of MethodKey
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class DefaultCachedMethodKey extends MethodKey{
+
+    private final CachedClass[] parameterTypes;
+
+    public DefaultCachedMethodKey(Class sender, String name, CachedClass[] parameterTypes, boolean isCallToSuper) {
+        super(sender, name,isCallToSuper);
+        this.parameterTypes = parameterTypes;
+    }
+
+    public int getParameterCount() {
+        return parameterTypes.length;
+    }
+
+    public Class getParameterType(int index) {
+        CachedClass c = parameterTypes[index];
+        if (c==null) return Object.class;
+        return c.getTheClass();
+    }
+}