You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2017/12/20 00:56:38 UTC
[41/49] groovy git commit: Move source files to proper packages
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/Closure.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Closure.java b/src/main/groovy/groovy/lang/Closure.java
new file mode 100644
index 0000000..99d2ea9
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Closure.java
@@ -0,0 +1,1054 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+import org.apache.groovy.internal.util.UncheckedThrow;
+import org.codehaus.groovy.reflection.ReflectionCache;
+import org.codehaus.groovy.reflection.stdclasses.CachedClosureClass;
+import org.codehaus.groovy.runtime.ComposedClosure;
+import org.codehaus.groovy.runtime.CurriedClosure;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
+import org.codehaus.groovy.runtime.callsite.BooleanClosureWrapper;
+import org.codehaus.groovy.runtime.memoize.LRUCache;
+import org.codehaus.groovy.runtime.memoize.Memoize;
+import org.codehaus.groovy.runtime.memoize.UnlimitedConcurrentCache;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.io.Writer;
+
+/**
+ * Represents any closure object in Groovy.
+ * <p>
+ * Groovy allows instances of Closures to be called in a
+ * short form. For example:
+ * <pre class="groovyTestCase">
+ * def a = 1
+ * def c = { a }
+ * assert c() == 1
+ * </pre>
+ * To be able to use a Closure in this way with your own
+ * subclass, you need to provide a doCall method with any
+ * signature you want to. This ensures that
+ * {@link #getMaximumNumberOfParameters()} and
+ * {@link #getParameterTypes()} will work too without any
+ * additional code. If no doCall method is provided a
+ * closure must be used in its long form like
+ * <pre class="groovyTestCase">
+ * def a = 1
+ * def c = {a}
+ * assert c.call() == 1
+ * </pre>
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:tug@wilson.co.uk">John Wilson</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @author Graeme Rocher
+ * @author Paul King
+ */
+public abstract class Closure<V> extends GroovyObjectSupport implements Cloneable, Runnable, GroovyCallable<V>, Serializable {
+
+ /**
+ * With this resolveStrategy set the closure will attempt to resolve property references and methods to the
+ * owner first, then the delegate (<b>this is the default strategy</b>).
+ *
+ * For example the following code:
+ * <pre>
+ * class Test {
+ * def x = 30
+ * def y = 40
+ *
+ * def run() {
+ * def data = [ x: 10, y: 20 ]
+ * def cl = { y = x + y }
+ * cl.delegate = data
+ * cl()
+ * assert x == 30
+ * assert y == 70
+ * assert data == [x:10, y:20]
+ * }
+ * }
+ *
+ * new Test().run()
+ * </pre>
+ * Will succeed, because the x and y fields declared in the Test class shadow the variables in the delegate.<p>
+ * <i>Note that local variables are always looked up first, independently of the resolution strategy.</i>
+ */
+ public static final int OWNER_FIRST = 0;
+
+ /**
+ * With this resolveStrategy set the closure will attempt to resolve property references and methods to the
+ * delegate first then the owner.
+ *
+ * For example the following code:
+ * <pre class="groovyTestCase">
+ * class Test {
+ * def x = 30
+ * def y = 40
+ *
+ * def run() {
+ * def data = [ x: 10, y: 20 ]
+ * def cl = { y = x + y }
+ * cl.delegate = data
+ * cl.resolveStrategy = Closure.DELEGATE_FIRST
+ * cl()
+ * assert x == 30
+ * assert y == 40
+ * assert data == [x:10, y:30]
+ * }
+ * }
+ *
+ * new Test().run()
+ * </pre>
+ * This will succeed, because the x and y variables declared in the delegate shadow the fields in the owner class.<p>
+ * <i>Note that local variables are always looked up first, independently of the resolution strategy.</i>
+ */
+ public static final int DELEGATE_FIRST = 1;
+
+ /**
+ * With this resolveStrategy set the closure will resolve property references and methods to the owner only
+ * and not call the delegate at all. For example the following code :
+ *
+ * <pre>
+ * class Test {
+ * def x = 30
+ * def y = 40
+ *
+ * def run() {
+ * def data = [ x: 10, y: 20, z: 30 ]
+ * def cl = { y = x + y + z }
+ * cl.delegate = data
+ * cl.resolveStrategy = Closure.OWNER_ONLY
+ * cl()
+ * println x
+ * println y
+ * println data
+ * }
+ * }
+ *
+ * new Test().run()
+ * </pre>
+ *
+ * will throw "No such property: z" error because even if the z variable is declared in the delegate, no
+ * lookup is made.<p>
+ * <i>Note that local variables are always looked up first, independently of the resolution strategy.</i>
+ */
+ public static final int OWNER_ONLY = 2;
+
+ /**
+ * With this resolveStrategy set the closure will resolve property references and methods to the delegate
+ * only and entirely bypass the owner. For example the following code :
+ *
+ * <pre>
+ * class Test {
+ * def x = 30
+ * def y = 40
+ * def z = 50
+ *
+ * def run() {
+ * def data = [ x: 10, y: 20 ]
+ * def cl = { y = x + y + z }
+ * cl.delegate = data
+ * cl.resolveStrategy = Closure.DELEGATE_ONLY
+ * cl()
+ * println x
+ * println y
+ * println data
+ * }
+ * }
+ *
+ * new Test().run()
+ * </pre>
+ *
+ * will throw an error because even if the owner declares a "z" field, the resolution strategy will bypass
+ * lookup in the owner.<p>
+ * <i>Note that local variables are always looked up first, independently of the resolution strategy.</i>
+ */
+ public static final int DELEGATE_ONLY = 3;
+
+ /**
+ * With this resolveStrategy set the closure will resolve property references to itself and go
+ * through the usual MetaClass look-up process. This means that properties and methods are neither resolved
+ * from the owner nor the delegate, but only on the closure object itself. This allows the developer to
+ * override getProperty using ExpandoMetaClass of the closure itself.<p>
+ * <i>Note that local variables are always looked up first, independently of the resolution strategy.</i>
+ */
+ public static final int TO_SELF = 4;
+
+ public static final int DONE = 1, SKIP = 2;
+ private static final Object[] EMPTY_OBJECT_ARRAY = {};
+ public static final Closure IDENTITY = new Closure<Object>(null) {
+ public Object doCall(Object args) {
+ return args;
+ }
+ };
+
+ private Object delegate;
+ private Object owner;
+ private Object thisObject;
+ private int resolveStrategy = OWNER_FIRST;
+ private int directive;
+ protected Class[] parameterTypes;
+ protected int maximumNumberOfParameters;
+ private static final long serialVersionUID = 4368710879820278874L;
+ private BooleanClosureWrapper bcw;
+
+ public Closure(Object owner, Object thisObject) {
+ this.owner = owner;
+ this.delegate = owner;
+ this.thisObject = thisObject;
+
+ final CachedClosureClass cachedClass = (CachedClosureClass) ReflectionCache.getCachedClass(getClass());
+ parameterTypes = cachedClass.getParameterTypes();
+ maximumNumberOfParameters = cachedClass.getMaximumNumberOfParameters();
+ }
+
+ /**
+ * Constructor used when the "this" object for the Closure is null.
+ * This is rarely the case in normal Groovy usage.
+ *
+ * @param owner the Closure owner
+ */
+ public Closure(Object owner) {
+ this(owner, null);
+ }
+
+ /**
+ * Sets the strategy which the closure uses to resolve property references and methods.
+ * The default is Closure.OWNER_FIRST
+ *
+ * @param resolveStrategy The resolve strategy to set
+ *
+ * @see groovy.lang.Closure#DELEGATE_FIRST
+ * @see groovy.lang.Closure#DELEGATE_ONLY
+ * @see groovy.lang.Closure#OWNER_FIRST
+ * @see groovy.lang.Closure#OWNER_ONLY
+ * @see groovy.lang.Closure#TO_SELF
+ */
+ public void setResolveStrategy(int resolveStrategy) {
+ this.resolveStrategy = resolveStrategy;
+ }
+
+ /**
+ * Gets the strategy which the closure uses to resolve methods and properties
+ *
+ * @return The resolve strategy
+ *
+ * @see groovy.lang.Closure#DELEGATE_FIRST
+ * @see groovy.lang.Closure#DELEGATE_ONLY
+ * @see groovy.lang.Closure#OWNER_FIRST
+ * @see groovy.lang.Closure#OWNER_ONLY
+ * @see groovy.lang.Closure#TO_SELF
+ */
+ public int getResolveStrategy() {
+ return resolveStrategy;
+ }
+
+ public Object getThisObject(){
+ return thisObject;
+ }
+
+ public Object getProperty(final String property) {
+ if ("delegate".equals(property)) {
+ return getDelegate();
+ } else if ("owner".equals(property)) {
+ return getOwner();
+ } else if ("maximumNumberOfParameters".equals(property)) {
+ return getMaximumNumberOfParameters();
+ } else if ("parameterTypes".equals(property)) {
+ return getParameterTypes();
+ } else if ("metaClass".equals(property)) {
+ return getMetaClass();
+ } else if ("class".equals(property)) {
+ return getClass();
+ } else if ("directive".equals(property)) {
+ return getDirective();
+ } else if ("resolveStrategy".equals(property)) {
+ return getResolveStrategy();
+ } else if ("thisObject".equals(property)) {
+ return getThisObject();
+ } else {
+ switch(resolveStrategy) {
+ case DELEGATE_FIRST:
+ return getPropertyDelegateFirst(property);
+ case DELEGATE_ONLY:
+ return InvokerHelper.getProperty(this.delegate, property);
+ case OWNER_ONLY:
+ return InvokerHelper.getProperty(this.owner, property);
+ case TO_SELF:
+ return super.getProperty(property);
+ default:
+ return getPropertyOwnerFirst(property);
+ }
+ }
+ }
+
+ private Object getPropertyDelegateFirst(String property) {
+ if (delegate == null) return getPropertyOwnerFirst(property);
+ return getPropertyTryThese(property, this.delegate, this.owner);
+ }
+
+ private Object getPropertyOwnerFirst(String property) {
+ return getPropertyTryThese(property, this.owner, this.delegate);
+ }
+
+ private Object getPropertyTryThese(String property, Object firstTry, Object secondTry) {
+ try {
+ // let's try getting the property on the first object
+ return InvokerHelper.getProperty(firstTry, property);
+
+ } catch (MissingPropertyException e1) {
+ if (secondTry != null && firstTry != this && firstTry != secondTry) {
+ try {
+ // let's try getting the property on the second object
+ return InvokerHelper.getProperty(secondTry, property);
+ } catch (GroovyRuntimeException e2) {
+ // ignore, we'll throw e1
+ }
+ }
+ throw e1;
+
+ } catch (MissingFieldException e2) { // see GROOVY-5875
+ if (secondTry != null && firstTry != this && firstTry != secondTry) {
+ try {
+ // let's try getting the property on the second object
+ return InvokerHelper.getProperty(secondTry, property);
+ } catch (GroovyRuntimeException e3) {
+ // ignore, we'll throw e2
+ }
+ }
+ throw e2;
+ }
+ }
+
+ public void setProperty(String property, Object newValue) {
+ if ("delegate".equals(property)) {
+ setDelegate(newValue);
+ } else if ("metaClass".equals(property)) {
+ setMetaClass((MetaClass) newValue);
+ } else if ("resolveStrategy".equals(property)) {
+ setResolveStrategy(((Number) newValue).intValue());
+ } else if ("directive".equals(property)) {
+ setDirective(((Number) newValue).intValue());
+ } else {
+ switch(resolveStrategy) {
+ case DELEGATE_FIRST:
+ setPropertyDelegateFirst(property, newValue);
+ break;
+ case DELEGATE_ONLY:
+ InvokerHelper.setProperty(this.delegate, property, newValue);
+ break;
+ case OWNER_ONLY:
+ InvokerHelper.setProperty(this.owner, property, newValue);
+ break;
+ case TO_SELF:
+ super.setProperty(property, newValue);
+ break;
+ default:
+ setPropertyOwnerFirst(property, newValue);
+ }
+ }
+ }
+
+ private void setPropertyDelegateFirst(String property, Object newValue) {
+ if (delegate == null) setPropertyOwnerFirst(property, newValue);
+ else setPropertyTryThese(property, newValue, this.delegate, this.owner);
+ }
+
+ private void setPropertyOwnerFirst(String property, Object newValue) {
+ setPropertyTryThese(property, newValue, this.owner, this.delegate);
+ }
+
+ private void setPropertyTryThese(String property, Object newValue, Object firstTry, Object secondTry) {
+ try {
+ // let's try setting the property on the first object
+ InvokerHelper.setProperty(firstTry, property, newValue);
+ } catch (GroovyRuntimeException e1) {
+ if (firstTry != null && firstTry != this && firstTry != secondTry) {
+ try {
+ // let's try setting the property on the second object
+ InvokerHelper.setProperty(secondTry, property, newValue);
+ return;
+ } catch (GroovyRuntimeException e2) {
+ // ignore, we'll throw e1
+ }
+ }
+ throw e1;
+ }
+ }
+
+ public boolean isCase(Object candidate){
+ if (bcw==null) {
+ bcw = new BooleanClosureWrapper(this);
+ }
+ return bcw.call(candidate);
+ }
+
+ /**
+ * Invokes the closure without any parameters, returning any value if applicable.
+ *
+ * @return the value if applicable or null if there is no return statement in the closure
+ */
+ public V call() {
+ final Object[] NOARGS = EMPTY_OBJECT_ARRAY;
+ return call(NOARGS);
+ }
+
+ @SuppressWarnings("unchecked")
+ public V call(Object... args) {
+ try {
+ return (V) getMetaClass().invokeMethod(this,"doCall",args);
+ } catch (InvokerInvocationException e) {
+ UncheckedThrow.rethrow(e.getCause());
+ return null; // unreachable statement
+ } catch (Exception e) {
+ return (V) throwRuntimeException(e);
+ }
+ }
+
+ /**
+ * Invokes the closure, returning any value if applicable.
+ *
+ * @param arguments could be a single value or a List of values
+ * @return the value if applicable or null if there is no return statement in the closure
+ */
+ public V call(final Object arguments) {
+ return call(new Object[]{arguments});
+ }
+
+ protected static Object throwRuntimeException(Throwable throwable) {
+ if (throwable instanceof RuntimeException) {
+ throw (RuntimeException) throwable;
+ } else {
+ throw new GroovyRuntimeException(throwable.getMessage(), throwable);
+ }
+ }
+
+ /**
+ * @return the owner Object to which method calls will go which is
+ * typically the outer class when the closure is constructed
+ */
+ public Object getOwner() {
+ return this.owner;
+ }
+
+ /**
+ * @return the delegate Object to which method calls will go which is
+ * typically the outer class when the closure is constructed
+ */
+ public Object getDelegate() {
+ return this.delegate;
+ }
+
+ /**
+ * Allows the delegate to be changed such as when performing markup building
+ *
+ * @param delegate the new delegate
+ */
+ public void setDelegate(Object delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * @return the parameter types of the longest doCall method
+ * of this closure
+ */
+ public Class[] getParameterTypes() {
+ return parameterTypes;
+ }
+
+ /**
+ * @return the maximum number of parameters a doCall method
+ * of this closure can take
+ */
+ public int getMaximumNumberOfParameters() {
+ return maximumNumberOfParameters;
+ }
+
+ /**
+ * @return a version of this closure which implements Writable. Note that
+ * the returned Writable also overrides {@link #toString()} in order
+ * to allow rendering the result directly to a String.
+ */
+ public Closure asWritable() {
+ return new WritableClosure();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+ call();
+ }
+
+ /**
+ * Support for Closure currying.
+ * <p>
+ * Typical usage:
+ * <pre class="groovyTestCase">
+ * def multiply = { a, b -> a * b }
+ * def doubler = multiply.curry(2)
+ * assert doubler(4) == 8
+ * </pre>
+ * Note: special treatment is given to Closure vararg-style capability.
+ * If you curry a vararg parameter, you don't consume the entire vararg array
+ * but instead the first parameter of the vararg array as the following example shows:
+ * <pre class="groovyTestCase">
+ * def a = { one, two, Object[] others -> one + two + others.sum() }
+ * assert a.parameterTypes.name == ['java.lang.Object', 'java.lang.Object', '[Ljava.lang.Object;']
+ * assert a(1,2,3,4) == 10
+ * def b = a.curry(1)
+ * assert b.parameterTypes.name == ['java.lang.Object', '[Ljava.lang.Object;']
+ * assert b(2,3,4) == 10
+ * def c = b.curry(2)
+ * assert c.parameterTypes.name == ['[Ljava.lang.Object;']
+ * assert c(3,4) == 10
+ * def d = c.curry(3)
+ * assert d.parameterTypes.name == ['[Ljava.lang.Object;']
+ * assert d(4) == 10
+ * def e = d.curry(4)
+ * assert e.parameterTypes.name == ['[Ljava.lang.Object;']
+ * assert e() == 10
+ * assert e(5) == 15
+ * </pre>
+ *
+ *
+ * @param arguments the arguments to bind
+ * @return the new closure with its arguments bound
+ */
+ public Closure<V> curry(final Object... arguments) {
+ return new CurriedClosure<V>(this, arguments);
+ }
+
+ /**
+ * Support for Closure currying.
+ *
+ * @param argument the argument to bind
+ * @return the new closure with the argument bound
+ * @see #curry(Object...)
+ */
+ public Closure<V> curry(final Object argument) {
+ return curry(new Object[]{argument});
+ }
+
+ /**
+ * Support for Closure "right" currying.
+ * Parameters are supplied on the right rather than left as per the normal curry() method.
+ * Typical usage:
+ * <pre class="groovyTestCase">
+ * def divide = { a, b -> a / b }
+ * def halver = divide.rcurry(2)
+ * assert halver(8) == 4
+ * </pre>
+ *
+ * The position of the curried parameters will be calculated lazily, for example,
+ * if two overloaded doCall methods are available, the supplied arguments plus the
+ * curried arguments will be concatenated and the result used for method selection.
+ *
+ * @param arguments the arguments to bind
+ * @return the new closure with its arguments bound
+ * @see #curry(Object...)
+ */
+ public Closure<V> rcurry(final Object... arguments) {
+ return new CurriedClosure<V>(-arguments.length, this, arguments);
+ }
+
+ /**
+ * Support for Closure "right" currying.
+ *
+ * @param argument the argument to bind
+ * @return the new closure with the argument bound
+ * @see #rcurry(Object...)
+ */
+ public Closure<V> rcurry(final Object argument) {
+ return rcurry(new Object[]{argument});
+ }
+
+ /**
+ * Support for Closure currying at a given index.
+ * Parameters are supplied from index position "n".
+ * Typical usage:
+ * <pre>
+ * def caseInsensitive = { a, b -> a.toLowerCase() <=> b.toLowerCase() } as Comparator
+ * def caseSensitive = { a, b -> a <=> b } as Comparator
+ * def animals1 = ['ant', 'dog', 'BEE']
+ * def animals2 = animals1 + ['Cat']
+ * // curry middle param of this utility method:
+ * // Collections#binarySearch(List list, Object key, Comparator c)
+ * def catSearcher = Collections.&binarySearch.ncurry(1, "cat")
+ * [[animals1, animals2], [caseInsensitive, caseSensitive]].combinations().each{ a, c ->
+ * def idx = catSearcher(a.sort(c), c)
+ * print a.sort(c).toString().padRight(22)
+ * if (idx < 0) println "Not found but would belong in position ${-idx - 1}"
+ * else println "Found at index $idx"
+ * }
+ * // =>
+ * // [ant, BEE, dog] Not found but would belong in position 2
+ * // [ant, BEE, Cat, dog] Found at index 2
+ * // [BEE, ant, dog] Not found but would belong in position 2
+ * // [BEE, Cat, ant, dog] Not found but would belong in position 3
+ * </pre>
+ *
+ * The position of the curried parameters will be calculated eagerly
+ * and implies all arguments prior to the specified n index are supplied.
+ * Default parameter values prior to the n index will not be available.
+ *
+ * @param n the index from which to bind parameters (may be -ve in which case it will be normalized)
+ * @param arguments the arguments to bind
+ * @return the new closure with its arguments bound
+ * @see #curry(Object...)
+ */
+ public Closure<V> ncurry(int n, final Object... arguments) {
+ return new CurriedClosure<V>(n, this, arguments);
+ }
+
+ /**
+ * Support for Closure currying at a given index.
+ *
+ * @param argument the argument to bind
+ * @return the new closure with the argument bound
+ * @see #ncurry(int, Object...)
+ */
+ public Closure<V> ncurry(int n, final Object argument) {
+ return ncurry(n, new Object[]{argument});
+ }
+
+ /**
+ * Support for Closure forward composition.
+ * <p>
+ * Typical usage:
+ * <pre class="groovyTestCase">
+ * def times2 = { a -> a * 2 }
+ * def add3 = { a -> a + 3 }
+ * def timesThenAdd = times2 >> add3
+ * // equivalent: timesThenAdd = { a -> add3(times2(a)) }
+ * assert timesThenAdd(3) == 9
+ * </pre>
+ *
+ * @param other the Closure to compose with the current Closure
+ * @return the new composed Closure
+ */
+ public <W> Closure<W> rightShift(final Closure<W> other) {
+ return new ComposedClosure<W>(this, other);
+ }
+
+ /**
+ * Support for Closure reverse composition.
+ * <p>
+ * Typical usage:
+ * <pre class="groovyTestCase">
+ * def times2 = { a -> a * 2 }
+ * def add3 = { a -> a + 3 }
+ * def addThenTimes = times2 << add3
+ * // equivalent: addThenTimes = { a -> times2(add3(a)) }
+ * assert addThenTimes(3) == 12
+ * </pre>
+ *
+ * @param other the Closure to compose with the current Closure
+ * @return the new composed Closure
+ */
+ public Closure<V> leftShift(final Closure other) {
+ return new ComposedClosure<V>(other, this);
+ }
+
+ /* *
+ * Alias for calling a Closure for non-closure arguments.
+ * <p>
+ * Typical usage:
+ * <pre class="groovyTestCase">
+ * def times2 = { a -> a * 2 }
+ * def add3 = { a -> a * 3 }
+ * assert add3 << times2 << 3 == 9
+ * </pre>
+ *
+ * @param arg the argument to call the closure with
+ * @return the result of calling the Closure
+ */
+ public V leftShift(final Object arg) {
+ return call(arg);
+ }
+
+ /**
+ * Creates a caching variant of the closure.
+ * Whenever the closure is called, the mapping between the parameters and the return value is preserved in cache
+ * making subsequent calls with the same arguments fast.
+ * This variant will keep all cached values forever, i.e. till the closure gets garbage-collected.
+ * The returned function can be safely used concurrently from multiple threads, however, the implementation
+ * values high average-scenario performance and so concurrent calls on the memoized function with identical argument values
+ * may not necessarily be able to benefit from each other's cached return value. With this having been mentioned,
+ * the performance trade-off still makes concurrent use of memoized functions safe and highly recommended.
+ *
+ * The cache gets garbage-collected together with the memoized closure.
+ *
+ * @return A new closure forwarding to the original one while caching the results
+ */
+ public Closure<V> memoize() {
+ return Memoize.buildMemoizeFunction(new UnlimitedConcurrentCache(), this);
+ }
+
+ /**
+ * Creates a caching variant of the closure with upper limit on the cache size.
+ * Whenever the closure is called, the mapping between the parameters and the return value is preserved in cache
+ * making subsequent calls with the same arguments fast.
+ * This variant will keep all values until the upper size limit is reached. Then the values in the cache start rotating
+ * using the LRU (Last Recently Used) strategy.
+ * The returned function can be safely used concurrently from multiple threads, however, the implementation
+ * values high average-scenario performance and so concurrent calls on the memoized function with identical argument values
+ * may not necessarily be able to benefit from each other's cached return value. With this having been mentioned,
+ * the performance trade-off still makes concurrent use of memoized functions safe and highly recommended.
+ *
+ * The cache gets garbage-collected together with the memoized closure.
+ *
+ * @param maxCacheSize The maximum size the cache can grow to
+ * @return A new function forwarding to the original one while caching the results
+ */
+ public Closure<V> memoizeAtMost(final int maxCacheSize) {
+ if (maxCacheSize < 0) throw new IllegalArgumentException("A non-negative number is required as the maxCacheSize parameter for memoizeAtMost.");
+
+ return Memoize.buildMemoizeFunction(new LRUCache(maxCacheSize), this);
+ }
+
+ /**
+ * Creates a caching variant of the closure with automatic cache size adjustment and lower limit
+ * on the cache size.
+ * Whenever the closure is called, the mapping between the parameters and the return value is preserved in cache
+ * making subsequent calls with the same arguments fast.
+ * This variant allows the garbage collector to release entries from the cache and at the same time allows
+ * the user to specify how many entries should be protected from the eventual gc-initiated eviction.
+ * Cached entries exceeding the specified preservation threshold are made available for eviction based on
+ * the LRU (Last Recently Used) strategy.
+ * Given the non-deterministic nature of garbage collector, the actual cache size may grow well beyond the limits
+ * set by the user if memory is plentiful.
+ * The returned function can be safely used concurrently from multiple threads, however, the implementation
+ * values high average-scenario performance and so concurrent calls on the memoized function with identical argument values
+ * may not necessarily be able to benefit from each other's cached return value. Also the protectedCacheSize parameter
+ * might not be respected accurately in such scenarios for some periods of time. With this having been mentioned,
+ * the performance trade-off still makes concurrent use of memoized functions safe and highly recommended.
+ *
+ * The cache gets garbage-collected together with the memoized closure.
+ * @param protectedCacheSize Number of cached return values to protect from garbage collection
+ * @return A new function forwarding to the original one while caching the results
+ */
+ public Closure<V> memoizeAtLeast(final int protectedCacheSize) {
+ if (protectedCacheSize < 0) throw new IllegalArgumentException("A non-negative number is required as the protectedCacheSize parameter for memoizeAtLeast.");
+
+ return Memoize.buildSoftReferenceMemoizeFunction(protectedCacheSize, new UnlimitedConcurrentCache(), this);
+ }
+
+ /**
+ * Creates a caching variant of the closure with automatic cache size adjustment and lower and upper limits
+ * on the cache size.
+ * Whenever the closure is called, the mapping between the parameters and the return value is preserved in cache
+ * making subsequent calls with the same arguments fast.
+ * This variant allows the garbage collector to release entries from the cache and at the same time allows
+ * the user to specify how many entries should be protected from the eventual gc-initiated eviction.
+ * Cached entries exceeding the specified preservation threshold are made available for eviction based on
+ * the LRU (Last Recently Used) strategy.
+ * Given the non-deterministic nature of garbage collector, the actual cache size may grow well beyond the protected
+ * size limits set by the user, if memory is plentiful.
+ * Also, this variant will never exceed in size the upper size limit. Once the upper size limit has been reached,
+ * the values in the cache start rotating using the LRU (Last Recently Used) strategy.
+ * The returned function can be safely used concurrently from multiple threads, however, the implementation
+ * values high average-scenario performance and so concurrent calls on the memoized function with identical argument values
+ * may not necessarily be able to benefit from each other's cached return value. Also the protectedCacheSize parameter
+ * might not be respected accurately in such scenarios for some periods of time. With this having been mentioned,
+ * the performance trade-off still makes concurrent use of memoized functions safe and highly recommended.
+ *
+ * The cache gets garbage-collected together with the memoized closure.
+ * @param protectedCacheSize Number of cached return values to protect from garbage collection
+ * @param maxCacheSize The maximum size the cache can grow to
+ * @return A new function forwarding to the original one while caching the results
+ */
+ public Closure<V> memoizeBetween(final int protectedCacheSize, final int maxCacheSize) {
+ if (protectedCacheSize < 0) throw new IllegalArgumentException("A non-negative number is required as the protectedCacheSize parameter for memoizeBetween.");
+ if (maxCacheSize < 0) throw new IllegalArgumentException("A non-negative number is required as the maxCacheSize parameter for memoizeBetween.");
+ if (protectedCacheSize > maxCacheSize) throw new IllegalArgumentException("The maxCacheSize parameter to memoizeBetween is required to be greater or equal to the protectedCacheSize parameter.");
+
+ return Memoize.buildSoftReferenceMemoizeFunction(protectedCacheSize, new LRUCache(maxCacheSize), this);
+ }
+
+ /**
+ * Builds a trampolined variant of the current closure.
+ * To prevent stack overflow due to deep recursion, functions can instead leverage the trampoline mechanism
+ * and avoid recursive calls altogether. Under trampoline, the function is supposed to perform one step of
+ * the calculation and, instead of a recursive call to itself or another function, it return back a new closure,
+ * which will be executed by the trampoline as the next step.
+ * Once a non-closure value is returned, the trampoline stops and returns the value as the final result.
+ * Here is an example:
+ * <pre>
+ * def fact
+ * fact = { n, total ->
+ * n == 0 ? total : fact.trampoline(n - 1, n * total)
+ * }.trampoline()
+ * def factorial = { n -> fact(n, 1G)}
+ * println factorial(20) // => 2432902008176640000
+ * </pre>
+ *
+ * @param args Parameters to the closure, so as the trampoline mechanism can call it
+ * @return A closure, which will execute the original closure on a trampoline.
+ */
+ public Closure<V> trampoline(final Object... args) {
+ return new TrampolineClosure<V>(this.curry(args));
+ }
+
+ /**
+ * Builds a trampolined variant of the current closure.
+ * To prevent stack overflow due to deep recursion, functions can instead leverage the trampoline mechanism
+ * and avoid recursive calls altogether. Under trampoline, the function is supposed to perform one step of
+ * the calculation and, instead of a recursive call to itself or another function, it return back a new closure,
+ * which will be executed by the trampoline as the next step.
+ * Once a non-closure value is returned, the trampoline stops and returns the value as the final result.
+ * @return A closure, which will execute the original closure on a trampoline.
+ * @see #trampoline(Object...)
+ */
+ public Closure<V> trampoline() {
+ return new TrampolineClosure<V>(this);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#clone()
+ */
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (final CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ /*
+ * Implementation note:
+ * This has to be an inner class!
+ *
+ * Reason:
+ * Closure.this.call will call the outer call method, but
+ * with the inner class as executing object. This means any
+ * invokeMethod or getProperty call will be called on this
+ * inner class instead of the outer!
+ */
+ private class WritableClosure extends Closure implements Writable {
+ public WritableClosure() {
+ super(Closure.this);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.Writable#writeTo(java.io.Writer)
+ */
+ public Writer writeTo(Writer out) throws IOException {
+ Closure.this.call(new Object[]{out});
+
+ return out;
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.GroovyObject#invokeMethod(java.lang.String, java.lang.Object)
+ */
+ public Object invokeMethod(String method, Object arguments) {
+ if ("clone".equals(method)) {
+ return clone();
+ } else if ("curry".equals(method)) {
+ return curry((Object[]) arguments);
+ } else if ("asWritable".equals(method)) {
+ return asWritable();
+ } else {
+ return Closure.this.invokeMethod(method, arguments);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.GroovyObject#getProperty(java.lang.String)
+ */
+ public Object getProperty(String property) {
+ return Closure.this.getProperty(property);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.GroovyObject#setProperty(java.lang.String, java.lang.Object)
+ */
+ public void setProperty(String property, Object newValue) {
+ Closure.this.setProperty(property, newValue);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.Closure#call()
+ */
+ public Object call() {
+ return ((Closure) getOwner()).call();
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.Closure#call(java.lang.Object)
+ */
+ public Object call(Object arguments) {
+ return ((Closure) getOwner()).call(arguments);
+ }
+
+ public Object call(Object... args) {
+ return ((Closure) getOwner()).call(args);
+ }
+
+ public Object doCall(Object... args) {
+ return call(args);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.Closure#getDelegate()
+ */
+ public Object getDelegate() {
+ return Closure.this.getDelegate();
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.Closure#setDelegate(java.lang.Object)
+ */
+ public void setDelegate(Object delegate) {
+ Closure.this.setDelegate(delegate);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.Closure#getParameterTypes()
+ */
+ public Class[] getParameterTypes() {
+ return Closure.this.getParameterTypes();
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.Closure#getParameterTypes()
+ */
+ public int getMaximumNumberOfParameters() {
+ return Closure.this.getMaximumNumberOfParameters();
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.Closure#asWritable()
+ */
+ public Closure asWritable() {
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+ Closure.this.run();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#clone()
+ */
+ public Object clone() {
+ return ((Closure) Closure.this.clone()).asWritable();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return Closure.this.hashCode();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object arg0) {
+ return Closure.this.equals(arg0);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ final StringWriter writer = new StringWriter();
+
+ try {
+ writeTo(writer);
+ } catch (IOException e) {
+ return null;
+ }
+
+ return writer.toString();
+ }
+
+ public Closure curry(final Object... arguments) {
+ return (new CurriedClosure(this, arguments)).asWritable();
+ }
+
+ public void setResolveStrategy(int resolveStrategy) {
+ Closure.this.setResolveStrategy(resolveStrategy);
+ }
+
+ public int getResolveStrategy() {
+ return Closure.this.getResolveStrategy();
+ }
+ }
+
+ /**
+ * @return Returns the directive.
+ */
+ public int getDirective() {
+ return directive;
+ }
+
+ /**
+ * @param directive The directive to set.
+ */
+ public void setDirective(int directive) {
+ this.directive = directive;
+ }
+
+ /**
+ * Returns a copy of this closure where the "owner", "delegate" and "thisObject"
+ * fields are null, allowing proper serialization when one of them is not serializable.
+ *
+ * @return a serializable closure.
+ *
+ * @since 1.8.5
+ */
+ @SuppressWarnings("unchecked")
+ public Closure<V> dehydrate() {
+ Closure<V> result = (Closure<V>) this.clone();
+ result.delegate = null;
+ result.owner = null;
+ result.thisObject = null;
+ return result;
+ }
+
+ /**
+ * Returns a copy of this closure for which the delegate, owner and thisObject are
+ * replaced with the supplied parameters. Use this when you want to rehydrate a
+ * closure which has been made serializable thanks to the {@link #dehydrate()}
+ * method.
+ * @param delegate the closure delegate
+ * @param owner the closure owner
+ * @param thisObject the closure "this" object
+ * @return a copy of this closure where owner, delegate and thisObject are replaced
+ *
+ * @since 1.8.5
+ */
+ @SuppressWarnings("unchecked")
+ public Closure<V> rehydrate(Object delegate, Object owner, Object thisObject) {
+ Closure<V> result = (Closure<V>) this.clone();
+ result.delegate = delegate;
+ result.owner = owner;
+ result.thisObject = thisObject;
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/ClosureException.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/ClosureException.java b/src/main/groovy/groovy/lang/ClosureException.java
new file mode 100644
index 0000000..12986ad
--- /dev/null
+++ b/src/main/groovy/groovy/lang/ClosureException.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+/**
+ * An exception thrown by a closure invocation
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ClosureException extends RuntimeException {
+
+ private final Closure closure;
+
+ public ClosureException(Closure closure, Throwable cause) {
+ super("Exception thrown by call to closure: " + closure + " reason: " + cause, cause);
+ this.closure = closure;
+ }
+
+ public Closure getClosure() {
+ return closure;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/ClosureInvokingMethod.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/ClosureInvokingMethod.java b/src/main/groovy/groovy/lang/ClosureInvokingMethod.java
new file mode 100644
index 0000000..3e54278
--- /dev/null
+++ b/src/main/groovy/groovy/lang/ClosureInvokingMethod.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+/**
+ * An interface for MetaMethods that invoke closures to implements. Used by ExpandoMetaClass
+ *
+ * @see groovy.lang.ExpandoMetaClass
+ *
+ * @author Graeme Rocher
+ * @since 1.5
+ */
+public interface ClosureInvokingMethod {
+
+ /**
+ * Returns the original closure that this method invokes
+ * @return The closure
+ */
+ Closure getClosure();
+
+ /**
+ * Is it a static method?
+ * @return True if it is
+ */
+ boolean isStatic();
+
+ /**
+ * The method name
+ * @return The method name
+ */
+ String getName();
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/Delegate.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Delegate.java b/src/main/groovy/groovy/lang/Delegate.java
new file mode 100644
index 0000000..180dc84
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Delegate.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+import groovy.transform.Undefined;
+import org.codehaus.groovy.transform.GroovyASTTransformationClass;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to automatically delegate part of the functionality of an owner class to the
+ * annotated delegation target. The target can be a field (or property) or a method's return value.
+ * <p>
+ * The delegate type is either the type of the annotated field (or property) or the return type of
+ * the annotated method. The method can be thought of as a getter or factory method for the delegate.
+ * All public instance methods present in the delegate type and not present in the owner class
+ * will be added to owner class at compile time. The implementation of such automatically added
+ * methods is code which calls through to the delegate as per the normal delegate pattern.
+ * <p>
+ * As an example, consider this code:
+ * <pre class="groovyTestCase">
+ * class Event {
+ * {@code @Delegate} Date when
+ * String title, url
+ * }
+ *
+ * def gr8conf = new Event(title: "GR8 Conference",
+ * url: "http://www.gr8conf.org",
+ * when: Date.parse("yyyy/MM/dd", "2009/05/18"))
+ *
+ * def javaOne = new Event(title: "JavaOne",
+ * url: "http://java.sun.com/javaone/",
+ * when: Date.parse("yyyy/MM/dd", "2009/06/02"))
+ *
+ * assert gr8conf.before(javaOne.when)
+ * </pre>
+ *
+ * In this example, the {@code Event} class will have a method called
+ * {@code before(Date otherDate)} as well as other public methods of the
+ * {@code Date} class.
+ * The implementation of the {@code before()} method will look like this:
+ * <pre>
+ * public boolean before(Date otherDate) {
+ * return when.before(otherDate);
+ * }
+ * </pre>
+ *
+ * By default, the owner class will also be modified to implement any interfaces
+ * implemented by the delegate type. So, in the example above, because {@code Date}
+ * implements {@code Cloneable} the following will be true:
+ *
+ * <pre>
+ * assert gr8conf instanceof Cloneable
+ * </pre>
+ *
+ * This behavior can be disabled by setting the
+ * annotation's {@code interfaces} element to false,
+ * i.e. {@code @Delegate(interfaces = false)}, e.g. in the above
+ * example, the delegate definition would become:
+ * <pre>
+ * {@code @Delegate}(interfaces = false) Date when
+ * </pre>
+ * and the following would be true:
+ * <pre>
+ * assert !(gr8conf instanceof Cloneable)
+ * </pre>
+ *
+ * If multiple delegation targets are used and the same method signature occurs
+ * in more than one of the respective delegate types, then the delegate will be
+ * made to the first defined target having that signature. If this does occur,
+ * it might be regarded as a smell (or at least poor style) and it might be
+ * clearer to do the delegation by long hand.
+ * <p>
+ * By default, methods of the delegate type marked as {@code @Deprecated} are
+ * not automatically added to the owner class (but see the technical note
+ * about interfaces below). You can force these methods to
+ * be added by setting the annotation's {@code deprecated} element to true,
+ * i.e. {@code @Delegate(deprecated = true)}.
+ * <p>
+ * For example, in the example above if we change the delegate definition to:
+ * <pre>
+ * {@code @Delegate}(deprecated = true) Date when
+ * </pre>
+ * then the following additional lines will execute successfully (during 2009):
+ * <pre>
+ * assert gr8conf.year + 1900 == 2009
+ * assert gr8conf.toGMTString().contains(" 2009 ")
+ * </pre>
+ * Otherwise these lines produce a groovy.lang.MissingPropertyException
+ * or groovy.lang.MissingMethodException respectively as those two methods are
+ * {@code @Deprecated} in {@code Date}.
+ * <p>
+ * <b>Technical notes</b>:
+ * <ul>
+ * <li>Static methods, synthetic methods or methods from the <code>GroovyObject</code> interface
+ * are not candidates for delegation</li>
+ * <li>Non-abstract non-static methods defined in the owner class or its superclasses take
+ * precedence over methods with identical signatures from a {@code @Delegate} target</li>
+ * <li>All methods defined in the owner class (including static, abstract or private etc.)
+ * take precedence over methods with identical signatures from a {@code @Delegate} target</li>
+ * <li>Recursive delegation to your own class is not allowed</li>
+ * <li>Mixing of {@code @Delegate} with default method arguments is known not to work in some cases.
+ * We recommend not using these features together.</li>
+ * <li>When the delegate type is an interface, the {@code deprecated} attribute will be
+ * ignored if the owner class implements that interface (i.e. you must set {@code interfaces=false}
+ * if you want the {@code deprecated} attribute to be used). Otherwise, the resulting class would
+ * not compile anyway without manually adding in any deprecated methods in the interface.</li>
+ * <li>{@code @Delegate} can work in combination with {@code @Lazy} when annotating a field (or property)</li>
+ * </ul>
+ */
+@java.lang.annotation.Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD})
+@GroovyASTTransformationClass("org.codehaus.groovy.transform.DelegateASTTransformation")
+public @interface Delegate {
+ /**
+ * @return true if owner class should implement interfaces implemented by delegate type
+ */
+ boolean interfaces() default true;
+
+ /**
+ * Whether to apply the delegate pattern to deprecated methods; to avoid compilation
+ * errors, this is ignored if the type of the delegate target is an interface and
+ * {@code interfaces=true}.
+ *
+ * @return true if owner class should delegate to methods annotated with @Deprecated
+ */
+ boolean deprecated() default false;
+
+ /**
+ * Whether to carry over annotations from the methods of the delegate
+ * to your delegating method. Currently Closure annotation members are
+ * not supported.
+ *
+ * @return true if generated delegate methods should keep method annotations
+ */
+ boolean methodAnnotations() default false;
+
+ /**
+ * Whether to carry over annotations from the parameters of delegate
+ * methods to your delegating method. Currently Closure annotation members are
+ * not supported.
+ *
+ * @return true if generated delegate methods should keep parameter annotations
+ */
+ boolean parameterAnnotations() default false;
+
+ /**
+ * List of method and/or property names to exclude when delegating.
+ * Only one of 'includes', 'includeTypes', 'excludes' or 'excludeTypes' should be used.
+ * For convenience, a String with comma separated names
+ * can be used in addition to an array (using Groovy's literal list notation) of String values.
+ * If interfaces is true (the default), you will need to manually supply any methods excluded
+ * from delegation that are required for the interface.
+ * @since 2.2.0
+ */
+ String[] excludes() default {};
+
+
+ /**
+ * List of interfaces containing method signatures to exclude when delegating.
+ * Only one of 'includes', 'includeTypes', 'excludes', 'excludeTypes' should be used.
+ * If interfaces is true (the default), you will need to manually supply any methods excluded
+ * from delegation that are required for the interface.
+ * @since 2.3.0
+ */
+ Class[] excludeTypes() default {};
+
+ /**
+ * List of method and/or property names to include when delegating.
+ * Only one of 'includes', 'includeTypes', 'excludes' or 'excludeTypes' should be used.
+ * For convenience, a String with comma separated names
+ * can be used in addition to an array (using Groovy's literal list notation) of String values.
+ * The default value is a special marker value indicating that no includes are defined; all fields
+ * are included if 'includes' remains undefined and 'excludes' is explicitly or implicitly an empty list.
+ * If interfaces is true (the default), you will need to manually supply any methods not included
+ * via delegation that are required for the interface.
+ * @since 2.2.0
+ */
+ String[] includes() default {Undefined.STRING};
+
+ /**
+ * List of interfaces containing method signatures to include when delegating.
+ * Only one of 'includes', 'includeTypes', 'excludes' or 'excludeTypes' should be used.
+ * The default value is a special marker value indicating that no includeTypes are defined.
+ * If interfaces is true (the default), you will need to manually supply any methods excluded
+ * from delegation that are required for the interface.
+ * @since 2.3.0
+ */
+ Class[] includeTypes() default {Undefined.CLASS.class};
+
+ /**
+ * Whether to apply the delegate pattern to all methods, including those with names that are considered internal.
+ *
+ * @return true if owner class should delegate to methods which have internal names
+ * @since 2.5.0
+ */
+ boolean allNames() default false;
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/DelegatesTo.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/DelegatesTo.java b/src/main/groovy/groovy/lang/DelegatesTo.java
new file mode 100644
index 0000000..54a5e36
--- /dev/null
+++ b/src/main/groovy/groovy/lang/DelegatesTo.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation can be used by API or DSL writers to document parameters which accept a closure.
+ * In that case, using this annotation, you can specify what the delegate type of the closure will
+ * be. This is important for IDE support.
+ * <p>
+ * This annotation can also be used to help the type checker ({@link groovy.transform.TypeChecked})
+ * which would not report errors then if the delegate is of the documented type. Of course, it is
+ * also compatible with {@link groovy.transform.CompileStatic}.
+ * <p>
+ * Example:
+ * <pre>
+ * // Document the fact that the delegate of the closure will be an ExecSpec
+ * ExecResult exec(@DelegatesTo(ExecSpec) Closure closure) { ... }
+ * </pre>
+ *
+ * @author Cedric Champeau
+ * @author Peter Niderwieser
+ * @since 2.1.0
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface DelegatesTo {
+ Class value() default Target.class;
+
+ /**
+ * The {@link Closure#resolveStrategy} used by the closure.
+ */
+ int strategy() default Closure.OWNER_FIRST;
+
+ /**
+ * The index of the generic type that will be the type of the closure's delegate.
+ * The generic types are considered with respect to the {@code @DelegatesTo.Target} annotated
+ * parameter for this usage, with the index starting at 0.
+ */
+ int genericTypeIndex() default -1;
+
+ /**
+ * In cases when there are multiple {@code @DelegatesTo.Target} annotated parameters, this
+ * member should be set to the {@link DelegatesTo.Target#value()} of the correct target.
+ */
+ String target() default "";
+
+ /**
+ * The type member should be used when the type of the delegate cannot
+ * be represented with {@link #value()}, {@link #genericTypeIndex()} or
+ * {@link #target()}. In this case, it is possible to use a String to represent
+ * the type, at the cost of potential uncaught errors at compile time if the
+ * type is invalid and increased compile time.
+ *
+ * @return a String representation of a type
+ * @since 2.4.0
+ */
+ String type() default "";
+
+ /**
+ * Parameter annotation used to specify the delegate for a {@code @DelegatesTo} annotated
+ * parameter of the same method.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @java.lang.annotation.Target({ElementType.PARAMETER})
+ public static @interface Target {
+
+ /**
+ * An identifier that should be used to disambiguate targets when there are
+ * multiple {@code @DelegatesTo.Target} annotated parameters.
+ */
+ String value() default "";
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/DelegatingMetaClass.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/DelegatingMetaClass.java b/src/main/groovy/groovy/lang/DelegatingMetaClass.java
new file mode 100644
index 0000000..ee2ade9
--- /dev/null
+++ b/src/main/groovy/groovy/lang/DelegatingMetaClass.java
@@ -0,0 +1,308 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+/**
+ * @author John Wilson
+ */
+
+public class DelegatingMetaClass implements MetaClass, MutableMetaClass, GroovyObject {
+ protected MetaClass delegate;
+
+ public DelegatingMetaClass(final MetaClass delegate) {
+ this.delegate = delegate;
+ }
+
+ public DelegatingMetaClass(final Class theClass) {
+ this(GroovySystem.getMetaClassRegistry().getMetaClass(theClass));
+ }
+
+ public boolean isModified() {
+ return this.delegate instanceof MutableMetaClass && ((MutableMetaClass) this.delegate).isModified();
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#addNewInstanceMethod(java.lang.reflect.Method)
+ */
+ public void addNewInstanceMethod(Method method) {
+ if (delegate instanceof MutableMetaClass)
+ ((MutableMetaClass) delegate).addNewInstanceMethod(method);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#addNewStaticMethod(java.lang.reflect.Method)
+ */
+ public void addNewStaticMethod(Method method) {
+ if (delegate instanceof MutableMetaClass)
+ ((MutableMetaClass) delegate).addNewStaticMethod(method);
+ }
+
+ public void addMetaMethod(MetaMethod metaMethod) {
+ if (delegate instanceof MutableMetaClass)
+ ((MutableMetaClass) delegate).addMetaMethod(metaMethod);
+ }
+
+ public void addMetaBeanProperty(MetaBeanProperty metaBeanProperty) {
+ if (delegate instanceof MutableMetaClass)
+ ((MutableMetaClass) delegate).addMetaBeanProperty(metaBeanProperty);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#initialize()
+ */
+ public void initialize() {
+ delegate.initialize();
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#getAttribute(java.lang.Object, java.lang.String)
+ */
+ public Object getAttribute(Object object, String attribute) {
+ return delegate.getAttribute(object, attribute);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#getClassNode()
+ */
+ public ClassNode getClassNode() {
+ return delegate.getClassNode();
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#getMetaMethods()
+ */
+ public List<MetaMethod> getMetaMethods() {
+ return delegate.getMetaMethods();
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#getMethods()
+ */
+ public List<MetaMethod> getMethods() {
+ return delegate.getMethods();
+ }
+
+ public List<MetaMethod> respondsTo(Object obj, String name, Object[] argTypes) {
+ return delegate.respondsTo(obj, name, argTypes);
+ }
+
+ public List<MetaMethod> respondsTo(Object obj, String name) {
+ return delegate.respondsTo(obj, name);
+ }
+
+ public MetaProperty hasProperty(Object obj, String name) {
+ return delegate.hasProperty(obj, name);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#getProperties()
+ */
+ public List<MetaProperty> getProperties() {
+ return delegate.getProperties();
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#getProperty(java.lang.Object, java.lang.String)
+ */
+ public Object getProperty(Object object, String property) {
+ return delegate.getProperty(object, property);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#invokeConstructor(java.lang.Object[])
+ */
+ public Object invokeConstructor(Object[] arguments) {
+ return delegate.invokeConstructor(arguments);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#invokeMethod(java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public Object invokeMethod(Object object, String methodName, Object arguments) {
+ return delegate.invokeMethod(object, methodName, arguments);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#invokeMethod(java.lang.Object, java.lang.String, java.lang.Object[])
+ */
+ public Object invokeMethod(Object object, String methodName, Object[] arguments) {
+ return delegate.invokeMethod(object, methodName, arguments);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#invokeStaticMethod(java.lang.Object, java.lang.String, java.lang.Object[])
+ */
+ public Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
+ return delegate.invokeStaticMethod(object, methodName, arguments);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#setAttribute(java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void setAttribute(Object object, String attribute, Object newValue) {
+ delegate.setAttribute(object, attribute, newValue);
+ }
+
+ /* (non-Javadoc)
+ * @see groovy.lang.MetaClass#setProperty(java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void setProperty(Object object, String property, Object newValue) {
+ delegate.setProperty(object, property, newValue);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ return delegate.equals(obj);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+
+ public String toString() {
+ return super.toString() + "[" + delegate.toString() + "]";
+ }
+
+ /**
+ * @deprecated
+ */
+ @Deprecated
+ public MetaMethod pickMethod(String methodName, Class[] arguments) {
+ return delegate.pickMethod(methodName, arguments);
+ }
+
+ public Object getAttribute(Class sender, Object receiver, String messageName, boolean useSuper) {
+ return this.delegate.getAttribute(sender, receiver, messageName, useSuper);
+ }
+
+ public Object getProperty(Class sender, Object receiver, String messageName, boolean useSuper, boolean fromInsideClass) {
+ return this.delegate.getProperty(sender, receiver, messageName, useSuper, fromInsideClass);
+ }
+
+ public MetaProperty getMetaProperty(String name) {
+ return this.delegate.getMetaProperty(name);
+ }
+
+ public MetaMethod getStaticMetaMethod(String name, Object[] args) {
+ return this.delegate.getStaticMetaMethod(name, args);
+ }
+
+ public MetaMethod getStaticMetaMethod(String name, Class[] argTypes) {
+ return this.delegate.getStaticMetaMethod(name, argTypes);
+ }
+
+ public MetaMethod getMetaMethod(String name, Object[] args) {
+ return this.delegate.getMetaMethod(name, args);
+ }
+
+ public Class getTheClass() {
+ return this.delegate.getTheClass();
+ }
+
+ public Object invokeMethod(Class sender, Object receiver, String methodName, Object[] arguments, boolean isCallToSuper, boolean fromInsideClass) {
+ return this.delegate.invokeMethod(sender, receiver, methodName, arguments, isCallToSuper, fromInsideClass);
+ }
+
+ public Object invokeMissingMethod(Object instance, String methodName, Object[] arguments) {
+ return this.delegate.invokeMissingMethod(instance, methodName, arguments);
+ }
+
+ public Object invokeMissingProperty(Object instance, String propertyName, Object optionalValue, boolean isGetter) {
+ return this.delegate.invokeMissingProperty(instance, propertyName, optionalValue, isGetter);
+ }
+
+ public boolean isGroovyObject() {
+ return GroovyObject.class.isAssignableFrom(this.delegate.getTheClass());
+ }
+
+ public void setAttribute(Class sender, Object receiver, String messageName, Object messageValue, boolean useSuper, boolean fromInsideClass) {
+ this.delegate.setAttribute(sender, receiver, messageName, messageValue, useSuper, fromInsideClass);
+ }
+
+ public void setProperty(Class sender, Object receiver, String messageName, Object messageValue, boolean useSuper, boolean fromInsideClass) {
+ this.delegate.setProperty(sender, receiver, messageName, messageValue, useSuper, fromInsideClass);
+ }
+
+ public int selectConstructorAndTransformArguments(int numberOfConstructors, Object[] arguments) {
+ return this.delegate.selectConstructorAndTransformArguments(numberOfConstructors, arguments);
+ }
+
+ public void setAdaptee(MetaClass adaptee) {
+ this.delegate = adaptee;
+ }
+
+ public MetaClass getAdaptee() {
+ return this.delegate;
+ }
+
+ public Object invokeMethod(String name, Object args) {
+ try {
+ return getMetaClass().invokeMethod(this, name, args);
+ }
+ catch (MissingMethodException e) {
+ if (delegate instanceof GroovyObject)
+ return ((GroovyObject) delegate).invokeMethod(name, args);
+ else
+ throw e;
+ }
+ }
+
+ public Object getProperty(String property) {
+ try {
+ return getMetaClass().getProperty(this, property);
+ }
+ catch (MissingPropertyException e) {
+ if (delegate instanceof GroovyObject)
+ return ((GroovyObject) delegate).getProperty(property);
+ else
+ throw e;
+ }
+ }
+
+ public void setProperty(String property, Object newValue) {
+ try {
+ getMetaClass().setProperty(this, property, newValue);
+ }
+ catch (MissingPropertyException e) {
+ if (delegate instanceof GroovyObject)
+ ((GroovyObject) delegate).setProperty(property, newValue);
+ else
+ throw e;
+ }
+ }
+
+ public MetaClass getMetaClass() {
+ return InvokerHelper.getMetaClass(getClass());
+ }
+
+ public void setMetaClass(MetaClass metaClass) {
+ throw new UnsupportedOperationException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/DeprecationException.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/DeprecationException.java b/src/main/groovy/groovy/lang/DeprecationException.java
new file mode 100644
index 0000000..36ad893
--- /dev/null
+++ b/src/main/groovy/groovy/lang/DeprecationException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+/**
+ * Use this exception to mark a method implementation as being deprecated.
+ *
+ * Use the message to indicate the recommended way of calling the desired functionality.
+ * Make throwing this exception the only line in the method implementation, i.e. unlike
+ * the JavaDoc deprecated feature there is no relay to the new implementation but an early
+ * and deliberate halt of execution ("fail early").
+ *
+ * This exception is supposed to be used in the SNAPSHOT releases only. Before release, all
+ * references to this exception should be resolved and the according methods removed.
+ *
+ * @author Dierk Koenig
+ */
+public class DeprecationException extends RuntimeException {
+
+ public DeprecationException(String message) {
+ super(message);
+ }
+
+ public DeprecationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/EmptyRange.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/EmptyRange.java b/src/main/groovy/groovy/lang/EmptyRange.java
new file mode 100644
index 0000000..b67b32e
--- /dev/null
+++ b/src/main/groovy/groovy/lang/EmptyRange.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Constructing Ranges like 0..<0
+ */
+public class EmptyRange<T extends Comparable> extends AbstractList<T> implements Range<T> {
+
+ /**
+ * The value at which the range originates (may be <code>null</code>).
+ */
+ protected T at;
+
+ /**
+ * Creates a new {@link EmptyRange}.
+ *
+ * @param at the value at which the range starts (may be <code>null</code>).
+ */
+ public EmptyRange(T at) {
+ this.at = at;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public T getFrom() {
+ return at;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public T getTo() {
+ return at;
+ }
+
+ /**
+ * Never true for an empty range.
+ *
+ * @return <code>false</code>
+ */
+ @Override
+ public boolean isReverse() {
+ return false;
+ }
+
+ /**
+ * Never true for an empty range.
+ *
+ * @return <code>false</code>
+ */
+ @Override
+ public boolean containsWithinBounds(Object o) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String inspect() {
+ return InvokerHelper.inspect(at) + "..<" + InvokerHelper.inspect(at);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String toString() {
+ return (null == at)
+ ? "null..<null"
+ : at + "..<" + at;
+ }
+
+ /**
+ * Always 0 for an empty range.
+ *
+ * @return 0
+ */
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ /**
+ * Always throws <code>IndexOutOfBoundsException</code> for an empty range.
+ *
+ * @throws IndexOutOfBoundsException always
+ */
+ @Override
+ public T get(int index) {
+ throw new IndexOutOfBoundsException("can't get values from Empty Ranges");
+ }
+
+ /**
+ * Always throws <code>UnsupportedOperationException</code> for an empty range.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public boolean add(T o) {
+ throw new UnsupportedOperationException("cannot add to Empty Ranges");
+ }
+
+ /**
+ * Always throws <code>UnsupportedOperationException</code> for an empty range.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public boolean addAll(int index, Collection<? extends T> c) {
+ throw new UnsupportedOperationException("cannot add to Empty Ranges");
+ }
+
+ /**
+ * Always throws <code>UnsupportedOperationException</code> for an empty range.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public boolean addAll(Collection<? extends T> c) {
+ throw new UnsupportedOperationException("cannot add to Empty Ranges");
+ }
+
+ /**
+ * Always throws <code>UnsupportedOperationException</code> for an empty range.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException("cannot remove from Empty Ranges");
+ }
+
+ /**
+ * Always throws <code>UnsupportedOperationException</code> for an empty range.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public T remove(int index) {
+ throw new UnsupportedOperationException("cannot remove from Empty Ranges");
+ }
+
+ /**
+ * Always throws <code>UnsupportedOperationException</code> for an empty range.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ throw new UnsupportedOperationException("cannot remove from Empty Ranges");
+ }
+
+ /**
+ * Always throws <code>UnsupportedOperationException</code> for an empty range.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ throw new UnsupportedOperationException("cannot retainAll in Empty Ranges");
+ }
+
+ /**
+ * Always throws <code>UnsupportedOperationException</code> for an empty range.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public T set(int index, T element) {
+ throw new UnsupportedOperationException("cannot set in Empty Ranges");
+ }
+
+ /**
+ * Always does nothing for an empty range.
+ */
+ @Override
+ public void step(int step, Closure closure) {
+ }
+
+ /**
+ * Always returns an empty list for an empty range.
+ */
+ @Override
+ public List<T> step(int step) {
+ return new ArrayList<T>();
+ }
+}