http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/transform/Trait.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/Trait.java 
b/src/main/groovy/groovy/transform/Trait.java
new file mode 100644
index 0000000..de88180
--- /dev/null
+++ b/src/main/groovy/groovy/transform/Trait.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.transform;
+
+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;
+
+/**
+ * Used to mark a class as being a trait.
+ *
+ * @since 2.3.0
+ */
[email protected]
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+@GroovyASTTransformationClass("org.codehaus.groovy.transform.trait.TraitASTTransformation")
+public @interface Trait {
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/transform/TupleConstructor.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/TupleConstructor.java 
b/src/main/groovy/groovy/transform/TupleConstructor.java
new file mode 100644
index 0000000..2cd2be7
--- /dev/null
+++ b/src/main/groovy/groovy/transform/TupleConstructor.java
@@ -0,0 +1,278 @@
+/*
+ *  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.transform;
+
+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;
+
+/**
+ * Class annotation used to assist in the creation of tuple constructors in 
classes.
+ * Should be used with care with other annotations which create constructors - 
see "Known
+ * Limitations" for more details.
+ * <p>
+ * It allows you to write classes in this shortened form:
+ * <pre class="groovyTestCase">
+ * {@code @groovy.transform.TupleConstructor} class Customer {
+ *     String first, last
+ *     int age
+ *     Date since
+ *     Collection favItems
+ * }
+ * def c1 = new Customer(first:'Tom', last:'Jones', age:21, since:new Date(), 
favItems:['Books', 'Games'])
+ * def c2 = new Customer('Tom', 'Jones', 21, new Date(), ['Books', 'Games'])
+ * def c3 = new Customer('Tom', 'Jones')
+ * </pre>
+ * The {@code @TupleConstructor} annotation instructs the compiler to execute 
an
+ * AST transformation which adds the necessary constructor method to your 
class.
+ * <p>
+ * A tuple constructor is created with a parameter for each property (and 
optionally field and
+ * super properties).
+ * A default value is provided (using Java's default values) for all 
parameters in the constructor.
+ * Groovy's normal conventions then allows any number of parameters to be left 
off the end of the parameter list
+ * including all of the parameters - giving a no-arg constructor which can be 
used with the map-style naming conventions.
+ * <p>
+ * The order of parameters is given by the properties of any super classes 
with most super first
+ * (if {@code includeSuperProperties} is set) followed by the properties of 
the class followed
+ * by the fields of the class (if {@code includeFields} is set). Within each 
grouping the order
+ * is as attributes appear within the respective class.
+ * <p>More examples:</p>
+ * <pre class="groovyTestCase">
+ * //--------------------------------------------------------------------------
+ * import groovy.transform.TupleConstructor
+ *
+ * &#64;TupleConstructor()
+ * class Person {
+ *     String name
+ *     List likes
+ *     private boolean active = false
+ * }
+ *
+ * def person = new Person('mrhaki', ['Groovy', 'Java'])
+ *
+ * assert person.name == 'mrhaki'
+ * assert person.likes == ['Groovy', 'Java']
+ *
+ * person = new Person('mrhaki')
+ *
+ * assert person.name == 'mrhaki'
+ * assert !person.likes
+ * </pre>
+ * <pre class="groovyTestCase">
+ * //--------------------------------------------------------------------------
+ * // includeFields in the constructor creation.
+ * import groovy.transform.TupleConstructor
+ *
+ * &#64;TupleConstructor(includeFields=true)
+ * class Person {
+ *     String name
+ *     List likes
+ *     private boolean active = false
+ *
+ *     boolean isActivated() { active }
+ * }
+ *
+ * def person = new Person('mrhaki', ['Groovy', 'Java'], true)
+ *
+ * assert person.name == 'mrhaki'
+ * assert person.likes == ['Groovy', 'Java']
+ * assert person.activated
+ * </pre>
+ * <pre class="groovyTestCase">
+ * //--------------------------------------------------------------------------
+ * // use force attribute to force creation of constructor
+ * // even if we define our own constructors.
+ * import groovy.transform.TupleConstructor
+ *
+ * &#64;TupleConstructor(force=true)
+ * class Person {
+ *     String name
+ *     List likes
+ *     private boolean active = false
+ *
+ *     Person(boolean active) {
+ *         this.active = active
+ *     }
+ *
+ *     boolean isActivated() { active }
+ * }
+ *
+ * def person = new Person('mrhaki', ['Groovy', 'Java'])
+ *
+ * assert person.name == 'mrhaki'
+ * assert person.likes == ['Groovy', 'Java']
+ * assert !person.activated
+ *
+ * person = new Person(true)
+ *
+ * assert person.activated
+ * </pre>
+ * <pre class="groovyTestCase">
+ * //--------------------------------------------------------------------------
+ * // include properties and fields from super class.
+ * import groovy.transform.TupleConstructor
+ *
+ * &#64;TupleConstructor(includeFields=true)
+ * class Person {
+ *     String name
+ *     List likes
+ *     private boolean active = false
+ *
+ *     boolean isActivated() { active }
+ * }
+ *
+ * &#64;TupleConstructor(callSuper=true, includeSuperProperties=true, 
includeSuperFields=true)
+ * class Student extends Person {
+ *     List courses
+ * }
+ *
+ * def student = new Student('mrhaki', ['Groovy', 'Java'], true, ['IT'])
+ *
+ * assert student.name == 'mrhaki'
+ * assert student.likes == ['Groovy', 'Java']
+ * assert student.activated
+ * assert student.courses == ['IT']
+ * </pre>
+ * <p>
+ * Known Limitations:
+ * <ul>
+ * <li>This AST transform might become a no-op if you are defining your own 
constructors or
+ * combining with other AST transforms which create constructors (e.g. {@code 
@InheritConstructors});
+ * the order in which the particular transforms are processed becomes 
important in that case.
+ * See the {@code force} attribute for further details about customizing this 
behavior.</li>
+ * <li>This AST transform normally uses default parameter values which creates 
multiple constructors under
+ * the covers. You should use with care if you are defining your own 
constructors or
+ * combining with other AST transforms which create constructors (e.g. {@code 
@InheritConstructors});
+ * the order in which the particular transforms are processed becomes 
important in that case.
+ * See the {@code defaults} attribute for further details about customizing 
this behavior.</li>
+ * <li>Groovy's normal map-style naming conventions will not be available if 
the first property (or field)
+ * has type {@code LinkedHashMap} or if there is a single Map, AbstractMap or 
HashMap property (or field)</li>
+ * </ul>
+ *
+ * @since 1.8.0
+ */
[email protected]
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE})
+@GroovyASTTransformationClass("org.codehaus.groovy.transform.TupleConstructorASTTransformation")
+public @interface TupleConstructor {
+    /**
+     * List of field and/or property names to exclude from the constructor.
+     * Must not be used if 'includes' is 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.
+     */
+    String[] excludes() default {};
+
+    /**
+     * List of field and/or property names to include within the constructor.
+     * Must not be used if 'excludes' is 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.
+     */
+    String[] includes() default {Undefined.STRING};
+
+    /**
+     * Include fields in the constructor.
+     */
+    boolean includeFields() default false;
+
+    /**
+     * Include properties in the constructor.
+     */
+    boolean includeProperties() default true;
+
+    /**
+     * Include fields from super classes in the constructor.
+     */
+    boolean includeSuperFields() default false;
+
+    /**
+     * Include properties from super classes in the constructor.
+     */
+    boolean includeSuperProperties() default false;
+
+    /**
+     * Should super properties be called within a call to the parent 
constructor
+     * rather than set as properties. Typically used in combination with 
{@code includeSuperProperties}.
+     * Can't be true if using {@code pre} with a {@code super} first statement.
+     */
+    boolean callSuper() default false;
+
+    /**
+     * By default, this annotation becomes a no-op if you provide your own 
constructor.
+     * By setting {@code force=true} then the tuple constructor(s) will be 
added regardless of
+     * whether existing constructors exist. It is up to you to avoid creating 
duplicate constructors.
+     */
+    boolean force() default false;
+
+    /**
+     * Used to set whether default value processing is enabled (the default) 
or disabled.
+     *
+     * By default, every constructor parameter is given a default value. This 
value will
+     * be Java's default for primitive types (zero or false) and null for 
Objects, unless
+     * an initial value is given when declaring the property or field. A 
consequence of
+     * this design is that you can leave off parameters from the right if the 
default
+     * value will suffice. As far as Java interoperability is concerned, 
Groovy will
+     * create additional constructors under the covers representing the 
constructors
+     * with parameters left off, all the way from the constructor with all 
arguments
+     * to the no-arg constructor.
+     *
+     * However, when set to false, default values are not allowed for 
properties and fields.
+     * Only the constructor containing all arguments will be provided.
+     * In particular, a no-arg constructor won't be provided and since this is 
currently
+     * used by Groovy when using named-arguments, the named-argument style 
won't be available.
+     */
+    boolean defaults() default true;
+
+    /**
+     * By default, properties are set directly using their respective field.
+     * By setting {@code useSetters=true} then a writable property will be set 
using its setter.
+     * If turning on this flag we recommend that setters that might be called 
are
+     * made null-safe wrt the parameter.
+     */
+    boolean useSetters() default false;
+
+    /**
+     * Whether to include all fields and/or properties within the constructor, 
including those with names that are
+     * considered internal.
+     *
+     * @since 2.5.0
+     */
+    boolean allNames() default false;
+
+    /**
+     * A Closure containing statements which will be prepended to the 
generated constructor. The first statement
+     * within the Closure may be {@code super(someArgs)} in which case the 
no-arg super constructor won't be called.
+     *
+     * @since 2.5.0
+     */
+    Class pre() default Undefined.CLASS.class;
+
+    /**
+     * A Closure containing statements which will be appended to the end of 
the generated constructor. Useful for validation steps or tweaking the 
populated fields/properties.
+     *
+     * @since 2.5.0
+     */
+    Class post() default Undefined.CLASS.class;
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/transform/TypeChecked.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/TypeChecked.java 
b/src/main/groovy/groovy/transform/TypeChecked.java
new file mode 100644
index 0000000..b902f3f
--- /dev/null
+++ b/src/main/groovy/groovy/transform/TypeChecked.java
@@ -0,0 +1,70 @@
+/*
+ *  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.transform;
+
+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;
+
+/**
+ * This will let the Groovy compiler use compile time checks in the style of 
Java.
+ * @author <a href="mailto:[email protected]";>Jochen "blackdrag" Theodorou</a>
+ */
[email protected]
+@Retention(RetentionPolicy.SOURCE)
+@Target({   ElementType.METHOD,         ElementType.TYPE,
+            ElementType.CONSTRUCTOR
+})
+@GroovyASTTransformationClass("org.codehaus.groovy.transform.StaticTypesTransformation")
+public @interface TypeChecked {
+    TypeCheckingMode value() default TypeCheckingMode.PASS;
+
+    /**
+     * The list of (classpath resources) paths to type checking DSL scripts, 
also known
+     * as type checking extensions.
+     * @return an array of paths to groovy scripts that must be on compile 
classpath
+     */
+    String[] extensions() default {};
+
+    /**
+     * This annotation is added by @TypeChecked on methods which have type 
checking turned on.
+     * It is used to embed type information into binary, so that the type 
checker can use this information,
+     * if available, for precompiled classes.
+     */
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public @interface TypeCheckingInfo {
+        /**
+         * Returns the type checker information protocol number. This is used 
if the format of the
+         * string used in {@link #inferredType()} changes.
+         * @return the protocol version
+         */
+        int version() default 0;
+
+        /**
+         * An encoded type information.
+         * @return the inferred type
+         */
+        String inferredType();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/transform/TypeCheckingMode.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/TypeCheckingMode.java 
b/src/main/groovy/groovy/transform/TypeCheckingMode.java
new file mode 100644
index 0000000..075bd71
--- /dev/null
+++ b/src/main/groovy/groovy/transform/TypeCheckingMode.java
@@ -0,0 +1,31 @@
+/*
+ *  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.transform;
+
+/**
+ * This enumeration can be used whenever it is preferred to annotate a class as
+ * {@link TypeChecked} in general, but where only one or more methods are 
"dynamic". This allows the user
+ * to annotate the class itself then annotate only the methods which require 
exclusion.
+ *
+ * @author Cedric Champeau
+ */
+public enum TypeCheckingMode {
+    PASS,
+    SKIP
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/transform/Undefined.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/Undefined.java 
b/src/main/groovy/groovy/transform/Undefined.java
new file mode 100644
index 0000000..35b360d
--- /dev/null
+++ b/src/main/groovy/groovy/transform/Undefined.java
@@ -0,0 +1,37 @@
+/*
+ *  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.transform;
+
+import org.codehaus.groovy.ast.ClassNode;
+
+/**
+ * Java doesn't allow you to have null as an attribute value. It wants you to 
indicate what you really
+ * mean by null, so that is what we do here - as ugly as it is.
+ */
+public final class Undefined {
+    private Undefined() {}
+    public static final String STRING = 
"<DummyUndefinedMarkerString-DoNotUse>";
+    public static final class CLASS {}
+    public static final class EXCEPTION extends RuntimeException {
+        private static final long serialVersionUID = -3960500360386581172L;
+    }
+    public static boolean isUndefined(String other) { return 
STRING.equals(other); }
+    public static boolean isUndefined(ClassNode other) { return 
CLASS.class.getName().equals(other.getName()); }
+    public static boolean isUndefinedException(ClassNode other) { return 
EXCEPTION.class.getName().equals(other.getName()); }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/transform/WithReadLock.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/WithReadLock.java 
b/src/main/groovy/groovy/transform/WithReadLock.java
new file mode 100644
index 0000000..475786a
--- /dev/null
+++ b/src/main/groovy/groovy/transform/WithReadLock.java
@@ -0,0 +1,107 @@
+/*
+ *  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.transform;
+
+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;
+
+/**
+ * This annotation is used in conjunction with {@link WithWriteLock} to 
support read and write synchronization on a method.
+ * <p>
+ * To use this annotation, declare {@code @WithReadLock} on your method. The 
method may be either an instance method or
+ * a static method. The resulting method will allow multiple threads to read 
the information at the same time.
+ * However, if some other method obtains a write lock, then this method will 
force callers to wait until the write is complete.
+ * <p>
+ * This annotation is a declarative wrapper around the JDK's 
<code>java.util.concurrent.locks.ReentrantReadWriteLock</code>.
+ * Objects containing this annotation will have a ReentrantReadWriteLock field 
named <code>$reentrantLock</code> added to the class,
+ * and method access is protected by the lock. If the method is static then 
the field is static and named <code>$REENTRANTLOCK</code>.
+ * <p>
+ * The annotation takes an optional parameter for the name of the field. This 
field must exist on the class and must be
+ * of type ReentrantReadWriteLock.
+ * <p>
+ * To understand how this annotation works, it is convenient to think in terms 
of the source code it replaces. The following
+ * is a typical usage of this annotation from Groovy:
+ * <pre>
+ * import groovy.transform.*;
+ *
+ * public class ResourceProvider {
+ *
+ *     private final Map&lt;String, String&gt; data = new HashMap&lt;String, 
String&gt;();
+ *
+ *    {@code @WithReadLock}
+ *     public String getResource(String key) throws Exception {
+ *             return data.get(key);
+ *     }
+ *
+ *    {@code @WithWriteLock}
+ *     public void refresh() throws Exception {
+ *             //reload the resources into memory
+ *     }
+ * }
+ * </pre>
+ * As part of the Groovy compiler, code resembling this is produced:
+ * <pre>
+ * import java.util.concurrent.locks.ReentrantReadWriteLock;
+ * import java.util.concurrent.locks.ReadWriteLock;
+ *
+ * public class ResourceProvider {
+ *
+ *     private final ReadWriteLock $reentrantlock = new 
ReentrantReadWriteLock();
+ *     private final Map&lt;String, String&gt; data = new HashMap&lt;String, 
String&gt;();
+ *
+ *     public String getResource(String key) throws Exception {
+ *         $reentrantlock.readLock().lock();
+ *         try {
+ *             return data.get(key);
+ *         } finally {
+ *             $reentrantlock.readLock().unlock();
+ *         }
+ *     }
+ *
+ *     public void refresh() throws Exception {
+ *         $reentrantlock.writeLock().lock();
+ *         try {
+ *             //reload the resources into memory
+ *         } finally {
+ *             $reentrantlock.writeLock().unlock();
+ *         }
+ *     }
+ * }
+ * </pre>
+ *
+ * @author Hamlet D'Arcy
+ * @since 1.8.0
+ */
[email protected]
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.METHOD})
+@GroovyASTTransformationClass("org.codehaus.groovy.transform.ReadWriteLockASTTransformation")
+public @interface WithReadLock {
+    /**
+     * @return if a user specified lock object with the given name should be 
used
+     *      the lock object must exist. If the annotated method is static then 
the 
+     *      lock object must be static. If the annotated method is not static 
then 
+     *      the lock object must not be static. 
+     */
+    String value () default "";
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/transform/WithWriteLock.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/WithWriteLock.java 
b/src/main/groovy/groovy/transform/WithWriteLock.java
new file mode 100644
index 0000000..1eeb7f0
--- /dev/null
+++ b/src/main/groovy/groovy/transform/WithWriteLock.java
@@ -0,0 +1,107 @@
+/*
+ *  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.transform;
+
+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;
+
+/**
+ * This annotation is used in conjunction with {@link WithReadLock} to support 
read and write synchronization on a method.
+ * <p>
+ * To use this annotation, declare {@code @WithWriteLock} on your method. The 
method may be either an instance method or
+ * a static method. The resulting method will allow only one thread access to 
the method at a time, and will wait to access
+ * the method until any other read locks have been released.
+ * <p>
+ * This annotation is a declarative wrapper around the JDK's 
<code>java.util.concurrent.locks.ReentrantReadWriteLock</code>.
+ * Objects containing this annotation will have a ReentrantReadWriteLock field 
named <code>$reentrantLock</code> added to the class,
+ * and method access is protected by the lock. If the method is static then 
the field is static and named <code>$REENTRANTLOCK</code>.
+ * <p>
+ * The annotation takes an optional parameter for the name of the field. This 
field must exist on the class and must be
+ * of type ReentrantReadWriteLock.
+ * <p>
+ * To understand how this annotation works, it is convenient to think in terms 
of the source code it replaces. The following
+ * is a typical usage of this annotation from Groovy:
+ * <pre>
+ * import groovy.transform.*;
+ *
+ * public class ResourceProvider {
+ *
+ *     private final Map&lt;String, String&gt; data = new HashMap&lt;String, 
String&gt;();
+ *
+ *    {@code @WithReadLock}
+ *     public String getResource(String key) throws Exception {
+ *             return data.get(key);
+ *     }
+ *
+ *    {@code @WithWriteLock}
+ *     public void refresh() throws Exception {
+ *             //reload the resources into memory
+ *     }
+ * }
+ * </pre>
+ * As part of the Groovy compiler, code resembling this is produced:
+ * <pre>
+ * import java.util.concurrent.locks.ReentrantReadWriteLock;
+ * import java.util.concurrent.locks.ReadWriteLock;
+ *
+ * public class ResourceProvider {
+ *
+ *     private final ReadWriteLock $reentrantlock = new 
ReentrantReadWriteLock();
+ *     private final Map&lt;String, String&gt; data = new HashMap&lt;String, 
String&gt;();
+ *
+ *     public String getResource(String key) throws Exception {
+ *         $reentrantlock.readLock().lock();
+ *         try {
+ *             return data.get(key);
+ *         } finally {
+ *             $reentrantlock.readLock().unlock();
+ *         }
+ *     }
+ *
+ *     public void refresh() throws Exception {
+ *         $reentrantlock.writeLock().lock();
+ *         try {
+ *             //reload the resources into memory
+ *         } finally {
+ *             $reentrantlock.writeLock().unlock();
+ *         }
+ *     }
+ * }
+ * </pre>
+ *
+ * @author Hamlet D'Arcy
+ * @since 1.8.0
+ */
[email protected]
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.METHOD})
+@GroovyASTTransformationClass("org.codehaus.groovy.transform.ReadWriteLockASTTransformation")
+public @interface WithWriteLock {
+    /**
+     * @return if a user specified lock object with the given name should be 
used
+     *      the lock object must exist. If the annotated method is static then 
the 
+     *      lock object must be static. If the annotated method is not static 
then 
+     *      the lock object must not be static. 
+     */
+    String value () default "";
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/transform/builder/Builder.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/builder/Builder.java 
b/src/main/groovy/groovy/transform/builder/Builder.java
new file mode 100644
index 0000000..93b6090
--- /dev/null
+++ b/src/main/groovy/groovy/transform/builder/Builder.java
@@ -0,0 +1,160 @@
+/*
+ *  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.transform.builder;
+
+import groovy.transform.Undefined;
+import org.codehaus.groovy.transform.GroovyASTTransformationClass;
+
+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;
+
+import static 
org.codehaus.groovy.transform.BuilderASTTransformation.BuilderStrategy;
+
+/**
+ * The {@code @Builder} AST transformation is used to help write classes that 
can be created using <em>fluent</em> api calls.<!-- -->
+ * The transform supports multiple building strategies to cover a range of 
cases and there are a number
+ * of configuration options to customize the building process.
+ *
+ * In addition, a number of annotation attributes let you customise the 
building process. Not all annotation attributes
+ * are supported by all strategies. See the individual strategy documentation 
for more details.
+ * If you're an AST hacker, you can also define your own strategy class.
+ *
+ * The following strategies are bundled with Groovy:
+ * <ul>
+ *     <li>{@link SimpleStrategy} for creating chained setters</li>
+ *     <li>{@link ExternalStrategy} where you annotate an explicit builder 
class while leaving some buildee class being built untouched</li>
+ *     <li>{@link DefaultStrategy} which creates a nested helper class for 
instance creation</li>
+ *     <li>{@link InitializerStrategy} which creates a nested helper class for 
instance creation which when used with {@code @CompileStatic} allows type-safe 
object creation</li>
+ * </ul>
+ *
+ * Note that Groovy provides other built-in mechanisms for easy creation of 
objects, e.g. the named-args constructor:
+ * <pre>
+ * new Person(firstName: "Robert", lastName: "Lewandowski", age: 21)
+ * </pre>
+ * or the with statement:
+ * <pre>
+ * new Person().with {
+ *     firstName = "Robert"
+ *     lastName = "Lewandowski"
+ *     age = 21
+ * }
+ * </pre>
+ * so you might not find value in using the builder transform at all. But if 
you need Java integration or in some cases improved type safety, the {@code 
@Builder} transform might prove very useful.
+ *
+ * @see groovy.transform.builder.SimpleStrategy
+ * @see groovy.transform.builder.ExternalStrategy
+ * @see groovy.transform.builder.DefaultStrategy
+ * @see groovy.transform.builder.InitializerStrategy
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.METHOD})
+@GroovyASTTransformationClass("org.codehaus.groovy.transform.BuilderASTTransformation")
+public @interface Builder {
+
+    /**
+     * A class for which builder methods should be created. It will be an 
error to leave
+     * this attribute with its default value for some strategies.
+     */
+    Class forClass() default Undefined.CLASS.class;
+
+    /**
+     * A class capturing the builder strategy
+     */
+    Class<? extends BuilderStrategy> builderStrategy() default 
DefaultStrategy.class;
+
+    /**
+     * The prefix to use when creating the setter methods.
+     * Default is determined by the strategy which might use "" or "set" but 
you can choose your own, e.g. "with".
+     * If non-empty the first letter of the property will be capitalized 
before being appended to the prefix.
+     */
+    String prefix() default Undefined.STRING;
+
+    /**
+     * For strategies which create a builder helper class, the class name to 
use for the helper class.
+     * Not used if using {@code forClass} since in such cases the builder 
class is explicitly supplied.
+     * Default is determined by the strategy, e.g. <em>TargetClass</em> + 
"Builder" or <em>TargetClass</em> + "Initializer".
+     */
+    String builderClassName() default Undefined.STRING;
+
+    /**
+     * For strategies which create a builder helper class that creates the 
instance, the method name to call to create the instance.
+     * Default is determined by the strategy, e.g. <em>build</em> or 
<em>create</em>.
+     */
+    String buildMethodName() default Undefined.STRING;
+
+    /**
+     * The method name to use for a builder factory method in the source class 
for easy access of the
+     * builder helper class for strategies which create such a helper class.
+     * Must not be used if using {@code forClass}.
+     * Default is determined by the strategy, e.g. <em>builder</em> or 
<em>createInitializer</em>.
+     */
+    String builderMethodName() default Undefined.STRING;
+
+    /**
+     * List of field and/or property names to exclude from generated builder 
methods.
+     * Must not be used if 'includes' is 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.
+     */
+    String[] excludes() default {};
+
+    /**
+     * List of field and/or property names to include within the generated 
builder methods.
+     * Must not be used if 'excludes' is 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.
+     */
+    String[] includes() default {Undefined.STRING};
+
+    /**
+     * By default, properties are set directly using their respective field.
+     * By setting {@code useSetters=true} then a writable property will be set 
using its setter.
+     * If turning on this flag we recommend that setters that might be called 
are
+     * made null-safe wrt the parameter.
+     */
+    boolean useSetters() default false;
+
+    /**
+     * Generate builder methods for properties from super classes.
+     */
+    boolean includeSuperProperties() default false;
+
+    /**
+     * Whether the generated builder should support all properties, including 
those with names that are considered internal.
+     *
+     * @since 2.5.0
+     */
+    boolean allNames() default false;
+
+    /**
+     * Whether to include all properties (as per the JavaBean spec) in the 
generated builder.
+     * Groovy recognizes any field-like definitions with no explicit 
visibility as property definitions
+     * and always includes them in the {@code @Builder} generated classes. 
Groovy also treats any explicitly created getXxx() or isYyy()
+     * methods as property getters as per the JavaBean specification. Old 
versions of Groovy did not.
+     * So set this flag to false for the old behavior or if you want to 
explicitly exclude such properties.
+     * Currently only supported by DefaultStrategy and ExternalStrategy.
+     *
+     * @since 2.5.0
+     */
+    boolean allProperties() default true;
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/transform/builder/DefaultStrategy.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/builder/DefaultStrategy.java 
b/src/main/groovy/groovy/transform/builder/DefaultStrategy.java
new file mode 100644
index 0000000..65d90e3
--- /dev/null
+++ b/src/main/groovy/groovy/transform/builder/DefaultStrategy.java
@@ -0,0 +1,293 @@
+/*
+ *  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.transform.builder;
+
+import groovy.transform.Undefined;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.transform.BuilderASTTransformation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.declS;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.params;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+import static 
org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
+import static 
org.codehaus.groovy.ast.tools.GenericsUtils.extractSuperClassGenerics;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.newClass;
+import static 
org.codehaus.groovy.transform.AbstractASTTransformation.getMemberStringValue;
+import static 
org.codehaus.groovy.transform.BuilderASTTransformation.NO_EXCEPTIONS;
+import static org.codehaus.groovy.transform.BuilderASTTransformation.NO_PARAMS;
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_STATIC;
+
+/**
+ * This strategy is used with the {@link Builder} AST transform to create a 
builder helper class
+ * for the fluent creation of instances of a specified class.&nbsp;It can be 
used at the class,
+ * static method or constructor levels.
+ *
+ * You use it as follows:
+ * <pre class="groovyTestCase">
+ * import groovy.transform.builder.*
+ *
+ * {@code @Builder}
+ * class Person {
+ *     String firstName
+ *     String lastName
+ *     int age
+ * }
+ * def person = 
Person.builder().firstName("Robert").lastName("Lewandowski").age(21).build()
+ * assert person.firstName == "Robert"
+ * assert person.lastName == "Lewandowski"
+ * assert person.age == 21
+ * </pre>
+ * The {@code prefix} annotation attribute can be used to create setters with 
a different naming convention. The default is the
+ * empty string but you could change that to "set" as follows:
+ * <pre class="groovyTestCase">
+ * {@code @groovy.transform.builder.Builder}(prefix='set')
+ * class Person {
+ *     String firstName
+ *     String lastName
+ *     int age
+ * }
+ * def p2 = 
Person.builder().setFirstName("Robert").setLastName("Lewandowski").setAge(21).build()
+ * </pre>
+ * or using a prefix of 'with' would result in usage like this:
+ * <pre>
+ * def p3 = 
Person.builder().withFirstName("Robert").withLastName("Lewandowski").withAge(21).build()
+ * </pre>
+ *
+ * You can also use the {@code @Builder} annotation in combination with this 
strategy on one or more constructor or
+ * static method instead of or in addition to using it at the class level. An 
example with a constructor follows:
+ * <pre class="groovyTestCase">
+ * import groovy.transform.ToString
+ * import groovy.transform.builder.Builder
+ *
+ * {@code @ToString}
+ * class Person {
+ *     String first, last
+ *     int born
+ *
+ *     {@code @Builder}
+ *     Person(String roleName) {
+ *         if (roleName == 'Jack Sparrow') {
+ *             first = 'Johnny'; last = 'Depp'; born = 1963
+ *         }
+ *     }
+ * }
+ * assert Person.builder().roleName("Jack Sparrow").build().toString() == 
'Person(Johnny, Depp, 1963)'
+ * </pre>
+ * In this case, the parameter(s) for the constructor or static method become 
the properties available
+ * in the builder. For the case of a static method, the return type of the 
static method becomes the
+ * class of the instance being created. For static factory methods, this is 
normally the class containing the
+ * static method but in general it can be any class.
+ *
+ * Note: if using more than one {@code @Builder} annotation, which is only 
possible when using static method
+ * or constructor variants, it is up to you to ensure that any generated 
helper classes or builder methods
+ * have unique names. E.g.&nbsp;we can modify the previous example to have 
three builders. At least two of the builders
+ * in our case will need to set the 'builderClassName' and 'builderMethodName' 
annotation attributes to ensure
+ * we have unique names. This is shown in the following example:
+ * <pre class="groovyTestCase">
+ * import groovy.transform.builder.*
+ * import groovy.transform.*
+ *
+ * {@code @ToString}
+ * {@code @Builder}
+ * class Person {
+ *     String first, last
+ *     int born
+ *
+ *     Person(){} // required to retain no-arg constructor
+ *
+ *     {@code @Builder}(builderClassName='MovieBuilder', 
builderMethodName='byRoleBuilder')
+ *     Person(String roleName) {
+ *         if (roleName == 'Jack Sparrow') {
+ *             this.first = 'Johnny'; this.last = 'Depp'; this.born = 1963
+ *         }
+ *     }
+ *
+ *     {@code @Builder}(builderClassName='SplitBuilder', 
builderMethodName='splitBuilder')
+ *     static Person split(String name, int year) {
+ *         def parts = name.split(' ')
+ *         new Person(first: parts[0], last: parts[1], born: year)
+ *     }
+ * }
+ *
+ * assert Person.splitBuilder().name("Johnny 
Depp").year(1963).build().toString() == 'Person(Johnny, Depp, 1963)'
+ * assert Person.byRoleBuilder().roleName("Jack Sparrow").build().toString() 
== 'Person(Johnny, Depp, 1963)'
+ * assert 
Person.builder().first("Johnny").last('Depp').born(1963).build().toString() == 
'Person(Johnny, Depp, 1963)'
+ * </pre>
+ *
+ * The 'forClass' annotation attribute for the {@code @Builder} transform 
isn't applicable for this strategy.
+ * The 'useSetters' annotation attribute for the {@code @Builder} transform is 
ignored by this strategy which always uses setters.
+ */
+public class DefaultStrategy extends 
BuilderASTTransformation.AbstractBuilderStrategy {
+    private static final Expression DEFAULT_INITIAL_VALUE = null;
+    private static final int PUBLIC_STATIC = ACC_PUBLIC | ACC_STATIC;
+
+    public void build(BuilderASTTransformation transform, AnnotatedNode 
annotatedNode, AnnotationNode anno) {
+        if (unsupportedAttribute(transform, anno, "forClass")) return;
+        if (annotatedNode instanceof ClassNode) {
+            buildClass(transform, (ClassNode) annotatedNode, anno);
+        } else if (annotatedNode instanceof MethodNode) {
+            buildMethod(transform, (MethodNode) annotatedNode, anno);
+        }
+    }
+
+    public void buildMethod(BuilderASTTransformation transform, MethodNode 
mNode, AnnotationNode anno) {
+        if (transform.getMemberValue(anno, "includes") != null || 
transform.getMemberValue(anno, "excludes") != null) {
+            transform.addError("Error during " + 
BuilderASTTransformation.MY_TYPE_NAME +
+                    " processing: includes/excludes only allowed on classes", 
anno);
+        }
+        ClassNode buildee = mNode.getDeclaringClass();
+        ClassNode builder = createBuilder(anno, buildee);
+        createBuilderFactoryMethod(anno, buildee, builder);
+        for (Parameter parameter : mNode.getParameters()) {
+            builder.addField(createFieldCopy(buildee, parameter));
+            builder.addMethod(createBuilderMethodForProp(builder, new 
PropertyInfo(parameter.getName(), parameter.getType()), getPrefix(anno)));
+        }
+        builder.addMethod(createBuildMethodForMethod(anno, buildee, mNode, 
mNode.getParameters()));
+    }
+
+    public void buildClass(BuilderASTTransformation transform, ClassNode 
buildee, AnnotationNode anno) {
+        List<String> excludes = new ArrayList<String>();
+        List<String> includes = new ArrayList<String>();
+        includes.add(Undefined.STRING);
+        if (!getIncludeExclude(transform, anno, buildee, excludes, includes)) 
return;
+        if (includes.size() == 1 && Undefined.isUndefined(includes.get(0))) 
includes = null;
+        ClassNode builder = createBuilder(anno, buildee);
+        createBuilderFactoryMethod(anno, buildee, builder);
+//        List<FieldNode> fields = getFields(transform, anno, buildee);
+        boolean allNames = transform.memberHasValue(anno, "allNames", true);
+        boolean allProperties = !transform.memberHasValue(anno, 
"allProperties", false);
+        List<PropertyInfo> props = getPropertyInfos(transform, anno, buildee, 
excludes, includes, allNames, allProperties);
+        for (PropertyInfo pi : props) {
+            ClassNode correctedType = getCorrectedType(buildee, pi.getType(), 
builder);
+            String fieldName = pi.getName();
+            builder.addField(createFieldCopy(buildee, fieldName, 
correctedType));
+            builder.addMethod(createBuilderMethodForProp(builder, new 
PropertyInfo(fieldName, correctedType), getPrefix(anno)));
+        }
+        builder.addMethod(createBuildMethod(anno, buildee, props));
+    }
+
+    private static ClassNode getCorrectedType(ClassNode buildee, ClassNode 
fieldType, ClassNode declaringClass) {
+        Map<String,ClassNode> genericsSpec = 
createGenericsSpec(declaringClass);
+        extractSuperClassGenerics(fieldType, buildee, genericsSpec);
+        return correctToGenericsSpecRecurse(genericsSpec, fieldType);
+    }
+
+    private static void createBuilderFactoryMethod(AnnotationNode anno, 
ClassNode buildee, ClassNode builder) {
+        buildee.getModule().addClass(builder);
+        buildee.addMethod(createBuilderMethod(anno, builder));
+    }
+
+    private static ClassNode createBuilder(AnnotationNode anno, ClassNode 
buildee) {
+        return new InnerClassNode(buildee, getFullName(anno, buildee), 
PUBLIC_STATIC, OBJECT_TYPE);
+    }
+
+    private static String getFullName(AnnotationNode anno, ClassNode buildee) {
+        String builderClassName = getMemberStringValue(anno, 
"builderClassName", buildee.getNameWithoutPackage() + "Builder");
+        return buildee.getName() + "$" + builderClassName;
+    }
+
+    private static String getPrefix(AnnotationNode anno) {
+        return getMemberStringValue(anno, "prefix", "");
+    }
+
+    private static MethodNode createBuildMethodForMethod(AnnotationNode anno, 
ClassNode buildee, MethodNode mNode, Parameter[] params) {
+        String buildMethodName = getMemberStringValue(anno, "buildMethodName", 
"build");
+        final BlockStatement body = new BlockStatement();
+        ClassNode returnType;
+        if (mNode instanceof ConstructorNode) {
+            returnType = newClass(buildee);
+            
body.addStatement(returnS(ctorX(newClass(mNode.getDeclaringClass()), 
args(params))));
+        } else {
+            
body.addStatement(returnS(callX(newClass(mNode.getDeclaringClass()), 
mNode.getName(), args(params))));
+            returnType = newClass(mNode.getReturnType());
+        }
+        return new MethodNode(buildMethodName, ACC_PUBLIC, returnType, 
NO_PARAMS, NO_EXCEPTIONS, body);
+    }
+
+    private static MethodNode createBuilderMethod(AnnotationNode anno, 
ClassNode builder) {
+        String builderMethodName = getMemberStringValue(anno, 
"builderMethodName", "builder");
+        final BlockStatement body = new BlockStatement();
+        body.addStatement(returnS(ctorX(builder)));
+        return new MethodNode(builderMethodName, PUBLIC_STATIC, builder, 
NO_PARAMS, NO_EXCEPTIONS, body);
+    }
+
+    private static MethodNode createBuildMethod(AnnotationNode anno, ClassNode 
buildee, List<PropertyInfo> props) {
+        String buildMethodName = getMemberStringValue(anno, "buildMethodName", 
"build");
+        final BlockStatement body = new BlockStatement();
+        body.addStatement(returnS(initializeInstance(buildee, props, body)));
+        return new MethodNode(buildMethodName, ACC_PUBLIC, newClass(buildee), 
NO_PARAMS, NO_EXCEPTIONS, body);
+    }
+
+    private MethodNode createBuilderMethodForProp(ClassNode builder, 
PropertyInfo pinfo, String prefix) {
+        ClassNode fieldType = pinfo.getType();
+        String fieldName = pinfo.getName();
+        String setterName = getSetterName(prefix, fieldName);
+        return new MethodNode(setterName, ACC_PUBLIC, newClass(builder), 
params(param(fieldType, fieldName)), NO_EXCEPTIONS, block(
+                stmt(assignX(propX(varX("this"), constX(fieldName)), 
varX(fieldName, fieldType))),
+                returnS(varX("this", builder))
+        ));
+    }
+
+    private static FieldNode createFieldCopy(ClassNode buildee, Parameter 
param) {
+        Map<String,ClassNode> genericsSpec = createGenericsSpec(buildee);
+        extractSuperClassGenerics(param.getType(), buildee, genericsSpec);
+        ClassNode correctedParamType = 
correctToGenericsSpecRecurse(genericsSpec, param.getType());
+        return new FieldNode(param.getName(), ACC_PRIVATE, correctedParamType, 
buildee, param.getInitialExpression());
+    }
+
+    private static FieldNode createFieldCopy(ClassNode buildee, String 
fieldName, ClassNode fieldType) {
+        return new FieldNode(fieldName, ACC_PRIVATE, fieldType, buildee, 
DEFAULT_INITIAL_VALUE);
+    }
+
+    private static Expression initializeInstance(ClassNode buildee, 
List<PropertyInfo> props, BlockStatement body) {
+        Expression instance = varX("_the" + buildee.getNameWithoutPackage(), 
buildee);
+        body.addStatement(declS(instance, ctorX(buildee)));
+        for (PropertyInfo pi : props) {
+            body.addStatement(stmt(assignX(propX(instance, pi.getName()), 
varX(pi.getName(), pi.getType()))));
+        }
+        return instance;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/transform/builder/ExternalStrategy.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/builder/ExternalStrategy.java 
b/src/main/groovy/groovy/transform/builder/ExternalStrategy.java
new file mode 100644
index 0000000..c482bef
--- /dev/null
+++ b/src/main/groovy/groovy/transform/builder/ExternalStrategy.java
@@ -0,0 +1,158 @@
+/*
+ *  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.transform.builder;
+
+import groovy.transform.Undefined;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.transform.BuilderASTTransformation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.declS;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.params;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.newClass;
+import static 
org.codehaus.groovy.transform.BuilderASTTransformation.MY_TYPE_NAME;
+import static 
org.codehaus.groovy.transform.BuilderASTTransformation.NO_EXCEPTIONS;
+import static org.codehaus.groovy.transform.BuilderASTTransformation.NO_PARAMS;
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+
+/**
+ * This strategy is used with the {@link Builder} AST transform to populate a 
builder helper class
+ * so that it can be used for the fluent creation of instances of a specified 
class.&nbsp;The specified class is not modified in any way and may be a Java 
class.
+ *
+ * You use it by creating and annotating an explicit builder class which will 
be filled in by during
+ * annotation processing with the appropriate build method and setters. An 
example is shown here:
+ * <pre class="groovyTestCase">
+ * import groovy.transform.builder.*
+ *
+ * class Person {
+ *     String firstName
+ *     String lastName
+ * }
+ *
+ * {@code @Builder}(builderStrategy=ExternalStrategy, forClass=Person)
+ * class PersonBuilder { }
+ *
+ * def person = new 
PersonBuilder().firstName("Robert").lastName("Lewandowski").build()
+ * assert person.firstName == "Robert"
+ * assert person.lastName == "Lewandowski"
+ * </pre>
+ * The {@code prefix} annotation attribute, which defaults to the empty String 
for this strategy, can be used to create setters with a different naming 
convention, e.g. with
+ * the {@code prefix} changed to 'set', you would use your setters as follows:
+ * <pre>
+ * def p1 = new 
PersonBuilder().setFirstName("Robert").setLastName("Lewandowski").setAge(21).build()
+ * </pre>
+ * or using a prefix of 'with':
+ * <pre>
+ * def p2 = new 
PersonBuilder().withFirstName("Robert").withLastName("Lewandowski").withAge(21).build()
+ * </pre>
+ *
+ * The properties to use can be filtered using either the 'includes' or 
'excludes' annotation attributes for {@code @Builder}.
+ * The {@code @Builder} 'buildMethodName' annotation attribute can be used for 
configuring the build method's name, default "build".
+ *
+ * The {@code @Builder} 'builderMethodName' and 'builderClassName' annotation 
attributes aren't applicable for this strategy.
+ * The {@code @Builder} 'useSetters' annotation attribute is ignored by this 
strategy which always uses setters.
+ */
+public class ExternalStrategy extends 
BuilderASTTransformation.AbstractBuilderStrategy {
+    private static final Expression DEFAULT_INITIAL_VALUE = null;
+
+    public void build(BuilderASTTransformation transform, AnnotatedNode 
annotatedNode, AnnotationNode anno) {
+        if (!(annotatedNode instanceof ClassNode)) {
+            transform.addError("Error during " + 
BuilderASTTransformation.MY_TYPE_NAME + " processing: building for " +
+                    annotatedNode.getClass().getSimpleName() + " not supported 
by " + getClass().getSimpleName(), annotatedNode);
+            return;
+        }
+        ClassNode builder = (ClassNode) annotatedNode;
+        String prefix = transform.getMemberStringValue(anno, "prefix", "");
+        ClassNode buildee = transform.getMemberClassValue(anno, "forClass");
+        if (buildee == null) {
+            transform.addError("Error during " + MY_TYPE_NAME + " processing: 
'forClass' must be specified for " + getClass().getName(), anno);
+            return;
+        }
+        List<String> excludes = new ArrayList<String>();
+        List<String> includes = new ArrayList<String>();
+        includes.add(Undefined.STRING);
+        if (!getIncludeExclude(transform, anno, buildee, excludes, includes)) 
return;
+        if (includes.size() == 1 && Undefined.isUndefined(includes.get(0))) 
includes = null;
+        if (unsupportedAttribute(transform, anno, "builderClassName")) return;
+        if (unsupportedAttribute(transform, anno, "builderMethodName")) return;
+        boolean allNames = transform.memberHasValue(anno, "allNames", true);
+        boolean allProperties = !transform.memberHasValue(anno, 
"allProperties", false);
+        List<PropertyInfo> props = getPropertyInfos(transform, anno, buildee, 
excludes, includes, allNames, allProperties);
+        if (includes != null) {
+            for (String name : includes) {
+                checkKnownProperty(transform, anno, name, props);
+            }
+        }
+        for (PropertyInfo prop : props) {
+            builder.addField(createFieldCopy(builder, prop));
+            builder.addMethod(createBuilderMethodForField(builder, prop, 
prefix));
+        }
+        builder.addMethod(createBuildMethod(transform, anno, buildee, props));
+    }
+
+    private static MethodNode createBuildMethod(BuilderASTTransformation 
transform, AnnotationNode anno, ClassNode sourceClass, List<PropertyInfo> 
fields) {
+        String buildMethodName = transform.getMemberStringValue(anno, 
"buildMethodName", "build");
+        final BlockStatement body = new BlockStatement();
+        Expression sourceClassInstance = initializeInstance(sourceClass, 
fields, body);
+        body.addStatement(returnS(sourceClassInstance));
+        return new MethodNode(buildMethodName, ACC_PUBLIC, sourceClass, 
NO_PARAMS, NO_EXCEPTIONS, body);
+    }
+
+    private MethodNode createBuilderMethodForField(ClassNode builderClass, 
PropertyInfo prop, String prefix) {
+        String propName = prop.getName().equals("class") ? "clazz" : 
prop.getName();
+        String setterName = getSetterName(prefix, prop.getName());
+        return new MethodNode(setterName, ACC_PUBLIC, newClass(builderClass), 
params(param(newClass(prop.getType()), propName)), NO_EXCEPTIONS, block(
+                stmt(assignX(propX(varX("this"), constX(propName)), 
varX(propName))),
+                returnS(varX("this", newClass(builderClass)))
+        ));
+    }
+
+    private static FieldNode createFieldCopy(ClassNode builderClass, 
PropertyInfo prop) {
+        String propName = prop.getName();
+        return new FieldNode(propName.equals("class") ? "clazz" : propName, 
ACC_PRIVATE, newClass(prop.getType()), builderClass, DEFAULT_INITIAL_VALUE);
+    }
+
+    private static Expression initializeInstance(ClassNode sourceClass, 
List<PropertyInfo> props, BlockStatement body) {
+        Expression instance = varX("_the" + 
sourceClass.getNameWithoutPackage(), sourceClass);
+        body.addStatement(declS(instance, ctorX(sourceClass)));
+        for (PropertyInfo prop : props) {
+            body.addStatement(stmt(assignX(propX(instance, prop.getName()), 
varX(prop.getName().equals("class") ? "clazz" : prop.getName(), 
newClass(prop.getType())))));
+        }
+        return instance;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/transform/builder/InitializerStrategy.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/builder/InitializerStrategy.java 
b/src/main/groovy/groovy/transform/builder/InitializerStrategy.java
new file mode 100644
index 0000000..c678c38
--- /dev/null
+++ b/src/main/groovy/groovy/transform/builder/InitializerStrategy.java
@@ -0,0 +1,388 @@
+/*
+ *  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.transform.builder;
+
+import groovy.transform.Undefined;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.transform.AbstractASTTransformation;
+import org.codehaus.groovy.transform.BuilderASTTransformation;
+import org.codehaus.groovy.transform.ImmutableASTTransformation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorSuperS;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorThisS;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.params;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+import static 
org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
+import static 
org.codehaus.groovy.ast.tools.GenericsUtils.extractSuperClassGenerics;
+import static 
org.codehaus.groovy.ast.tools.GenericsUtils.makeClassSafeWithGenerics;
+import static 
org.codehaus.groovy.transform.AbstractASTTransformation.getMemberStringValue;
+import static 
org.codehaus.groovy.transform.BuilderASTTransformation.NO_EXCEPTIONS;
+import static org.codehaus.groovy.transform.BuilderASTTransformation.NO_PARAMS;
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_STATIC;
+import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
+
+/**
+ * This strategy is used with the {@link Builder} AST transform to create a 
builder helper class
+ * for the fluent and type-safe creation of instances of a specified class.
+ *
+ * It is modelled roughly on the design outlined here:
+ * http://michid.wordpress.com/2008/08/13/type-safe-builder-pattern-in-java/
+ *
+ * You define classes which use the type-safe initializer pattern as follows:
+ * <pre>
+ * import groovy.transform.builder.*
+ * import groovy.transform.*
+ *
+ * {@code @ToString}
+ * {@code @Builder}(builderStrategy=InitializerStrategy) class Person {
+ *     String firstName
+ *     String lastName
+ *     int age
+ * }
+ * </pre>
+ * While it isn't required to do so, the benefit of this builder strategy 
comes in conjunction with static type-checking or static compilation. Typical 
usage is as follows:
+ * <pre>
+ * {@code @CompileStatic}
+ * def main() {
+ *     println new 
Person(Person.createInitializer().firstName("John").lastName("Smith").age(21))
+ * }
+ * </pre>
+ * which prints:
+ * <pre>
+ * Person(John, Smith, 21)
+ * </pre>
+ * If you don't initialise some of the properties, your code won't compile, 
e.g. if the method body above was changed to this:
+ * <pre>
+ * println new 
Person(Person.createInitializer().firstName("John").lastName("Smith"))
+ * </pre>
+ * then the following compile-time error would result:
+ * <pre>
+ * [Static type checking] - Cannot find matching method 
Person#<init>(Person$PersonInitializer 
<groovy.transform.builder.InitializerStrategy$SET, 
groovy.transform.builder.InitializerStrategy$SET, 
groovy.transform.builder.InitializerStrategy$UNSET>). Please check if the 
declared type is right and if the method exists.
+ * </pre>
+ * The message is a little cryptic, but it is basically the static compiler 
telling us that the third parameter, {@code age} in our case, is unset.
+ *
+ * You can also add this annotation to your predefined constructors. These 
will be made private and an initializer will be set up
+ * to call your constructor. Any parameters to your constructor become the 
properties expected by the initializer.
+ * If you use such a builder on a constructor as well as on the class or on 
more than one constructor, then it is up to you
+ * to define unique values for 'builderClassName' and 'builderMethodName' for 
each annotation.
+ */
+public class InitializerStrategy extends 
BuilderASTTransformation.AbstractBuilderStrategy {
+
+    /**
+     * Internal phantom type used by the {@code InitializerStrategy} to 
indicate that a property has been set. It is used in conjunction with the 
generated parameterized type helper class.
+     */
+    public abstract static class SET {
+    }
+
+    /**
+     * Internal phantom type used by the {@code InitializerStrategy} to 
indicate that a property remains unset. It is used in conjunction with the 
generated parameterized type helper class.
+     */
+    public abstract static class UNSET {
+    }
+
+    private static final int PUBLIC_STATIC = ACC_PUBLIC | ACC_STATIC;
+    private static final Expression DEFAULT_INITIAL_VALUE = null;
+
+    public void build(BuilderASTTransformation transform, AnnotatedNode 
annotatedNode, AnnotationNode anno) {
+        if (unsupportedAttribute(transform, anno, "forClass")) return;
+        if (unsupportedAttribute(transform, anno, "allProperties")) return;
+        boolean useSetters = transform.memberHasValue(anno, "useSetters", 
true);
+        boolean allNames = transform.memberHasValue(anno, "allNames", true);
+        if (annotatedNode instanceof ClassNode) {
+            createBuilderForAnnotatedClass(transform, (ClassNode) 
annotatedNode, anno, useSetters, allNames);
+        } else if (annotatedNode instanceof MethodNode) {
+            createBuilderForAnnotatedMethod(transform, (MethodNode) 
annotatedNode, anno, useSetters);
+        }
+    }
+
+    private void createBuilderForAnnotatedClass(BuilderASTTransformation 
transform, ClassNode buildee, AnnotationNode anno, boolean useSetters, boolean 
allNames) {
+        List<String> excludes = new ArrayList<String>();
+        List<String> includes = new ArrayList<String>();
+        includes.add(Undefined.STRING);
+        if (!getIncludeExclude(transform, anno, buildee, excludes, includes)) 
return;
+        if (includes.size() == 1 && Undefined.isUndefined(includes.get(0))) 
includes = null;
+        List<FieldNode> fields = getFields(transform, anno, buildee);
+        List<FieldNode> filteredFields = filterFields(fields, includes, 
excludes, allNames);
+        if (filteredFields.isEmpty()) {
+            transform.addError("Error during " + 
BuilderASTTransformation.MY_TYPE_NAME +
+                    " processing: at least one property is required for this 
strategy", anno);
+        }
+        ClassNode builder = createInnerHelperClass(buildee, 
getBuilderClassName(buildee, anno), filteredFields.size());
+        addFields(buildee, filteredFields, builder);
+
+        buildCommon(buildee, anno, filteredFields, builder);
+        createBuildeeConstructors(transform, buildee, builder, filteredFields, 
true, useSetters);
+    }
+
+    private void createBuilderForAnnotatedMethod(BuilderASTTransformation 
transform, MethodNode mNode, AnnotationNode anno, boolean useSetters) {
+        if (transform.getMemberValue(anno, "includes") != null || 
transform.getMemberValue(anno, "excludes") != null) {
+            transform.addError("Error during " + 
BuilderASTTransformation.MY_TYPE_NAME +
+                    " processing: includes/excludes only allowed on classes", 
anno);
+        }
+        if (mNode instanceof ConstructorNode) {
+            mNode.setModifiers(ACC_PRIVATE | ACC_SYNTHETIC);
+        } else {
+            if ((mNode.getModifiers() & ACC_STATIC) == 0) {
+                transform.addError("Error during " + 
BuilderASTTransformation.MY_TYPE_NAME +
+                        " processing: method builders only allowed on static 
methods", anno);
+            }
+            mNode.setModifiers(ACC_PRIVATE | ACC_SYNTHETIC | ACC_STATIC);
+        }
+        ClassNode buildee = mNode.getDeclaringClass();
+        Parameter[] parameters = mNode.getParameters();
+        if (parameters.length == 0) {
+            transform.addError("Error during " + 
BuilderASTTransformation.MY_TYPE_NAME +
+                    " processing: at least one parameter is required for this 
strategy", anno);
+        }
+        ClassNode builder = createInnerHelperClass(buildee, 
getBuilderClassName(buildee, anno), parameters.length);
+        List<FieldNode> convertedFields = convertParamsToFields(builder, 
parameters);
+
+        buildCommon(buildee, anno, convertedFields, builder);
+        if (mNode instanceof ConstructorNode) {
+            createBuildeeConstructors(transform, buildee, builder, 
convertedFields, false, useSetters);
+        } else {
+            createBuildeeMethods(buildee, mNode, builder, convertedFields);
+        }
+    }
+
+    private static String getBuilderClassName(ClassNode buildee, 
AnnotationNode anno) {
+        return getMemberStringValue(anno, "builderClassName", 
buildee.getNameWithoutPackage() + "Initializer");
+    }
+
+    private static void addFields(ClassNode buildee, List<FieldNode> 
filteredFields, ClassNode builder) {
+        for (FieldNode filteredField : filteredFields) {
+            builder.addField(createFieldCopy(buildee, filteredField));
+        }
+    }
+
+    private void buildCommon(ClassNode buildee, AnnotationNode anno, 
List<FieldNode> fieldNodes, ClassNode builder) {
+        String prefix = getMemberStringValue(anno, "prefix", "");
+        String buildMethodName = getMemberStringValue(anno, "buildMethodName", 
"create");
+        createBuilderConstructors(builder, buildee, fieldNodes);
+        buildee.getModule().addClass(builder);
+        String builderMethodName = getMemberStringValue(anno, 
"builderMethodName", "createInitializer");
+        buildee.addMethod(createBuilderMethod(buildMethodName, builder, 
fieldNodes.size(), builderMethodName));
+        for (int i = 0; i < fieldNodes.size(); i++) {
+            builder.addMethod(createBuilderMethodForField(builder, fieldNodes, 
prefix, i));
+        }
+        builder.addMethod(createBuildMethod(builder, buildMethodName, 
fieldNodes));
+    }
+
+    private static List<FieldNode> convertParamsToFields(ClassNode builder, 
Parameter[] parameters) {
+        List<FieldNode> fieldNodes = new ArrayList<FieldNode>();
+        for(Parameter parameter: parameters) {
+            Map<String,ClassNode> genericsSpec = createGenericsSpec(builder);
+            ClassNode correctedType = 
correctToGenericsSpecRecurse(genericsSpec, parameter.getType());
+            FieldNode fieldNode = new FieldNode(parameter.getName(), 
parameter.getModifiers(), correctedType, builder, DEFAULT_INITIAL_VALUE);
+            fieldNodes.add(fieldNode);
+            builder.addField(fieldNode);
+        }
+        return fieldNodes;
+    }
+
+    private static ClassNode createInnerHelperClass(ClassNode buildee, String 
builderClassName, int fieldsSize) {
+        final String fullName = buildee.getName() + "$" + builderClassName;
+        ClassNode builder = new InnerClassNode(buildee, fullName, 
PUBLIC_STATIC, OBJECT_TYPE);
+        GenericsType[] gtypes = new GenericsType[fieldsSize];
+        for (int i = 0; i < gtypes.length; i++) {
+            gtypes[i] = makePlaceholder(i);
+        }
+        builder.setGenericsTypes(gtypes);
+        return builder;
+    }
+
+    private static MethodNode createBuilderMethod(String buildMethodName, 
ClassNode builder, int numFields, String builderMethodName) {
+        final BlockStatement body = new BlockStatement();
+        body.addStatement(returnS(callX(builder, buildMethodName)));
+        ClassNode returnType = makeClassSafeWithGenerics(builder, 
unsetGenTypes(numFields));
+        return new MethodNode(builderMethodName, PUBLIC_STATIC, returnType, 
NO_PARAMS, NO_EXCEPTIONS, body);
+    }
+
+    private static GenericsType[] unsetGenTypes(int numFields) {
+        GenericsType[] gtypes = new GenericsType[numFields];
+        for (int i = 0; i < gtypes.length; i++) {
+            gtypes[i] = new GenericsType(ClassHelper.make(UNSET.class));
+        }
+        return gtypes;
+    }
+
+    private static GenericsType[] setGenTypes(int numFields) {
+        GenericsType[] gtypes = new GenericsType[numFields];
+        for (int i = 0; i < gtypes.length; i++) {
+            gtypes[i] = new GenericsType(ClassHelper.make(SET.class));
+        }
+        return gtypes;
+    }
+
+    private static void createBuilderConstructors(ClassNode builder, ClassNode 
buildee, List<FieldNode> fields) {
+        builder.addConstructor(ACC_PRIVATE, NO_PARAMS, NO_EXCEPTIONS, 
block(ctorSuperS()));
+        final BlockStatement body = new BlockStatement();
+        body.addStatement(ctorSuperS());
+        initializeFields(fields, body, false);
+        builder.addConstructor(ACC_PRIVATE, getParams(fields, buildee), 
NO_EXCEPTIONS, body);
+    }
+
+    private static void createBuildeeConstructors(BuilderASTTransformation 
transform, ClassNode buildee, ClassNode builder, List<FieldNode> fields, 
boolean needsConstructor, boolean useSetters) {
+        ConstructorNode initializer = createInitializerConstructor(buildee, 
builder, fields);
+        if (transform.hasAnnotation(buildee, 
ImmutableASTTransformation.MY_TYPE)) {
+            
initializer.putNodeMetaData(ImmutableASTTransformation.IMMUTABLE_SAFE_FLAG, 
Boolean.TRUE);
+        } else if (needsConstructor) {
+            final BlockStatement body = new BlockStatement();
+            body.addStatement(ctorSuperS());
+            initializeFields(fields, body, useSetters);
+            buildee.addConstructor(ACC_PRIVATE | ACC_SYNTHETIC, 
getParams(fields, buildee), NO_EXCEPTIONS, body);
+        }
+    }
+
+    private static void createBuildeeMethods(ClassNode buildee, MethodNode 
mNode, ClassNode builder, List<FieldNode> fields) {
+        ClassNode paramType = makeClassSafeWithGenerics(builder, 
setGenTypes(fields.size()));
+        List<Expression> argsList = new ArrayList<Expression>();
+        Parameter initParam = param(paramType, "initializer");
+        for (FieldNode fieldNode : fields) {
+            argsList.add(propX(varX(initParam), fieldNode.getName()));
+        }
+        String newName = "$" + mNode.getName(); // can't have private and 
public methods of the same name, so rename original
+        buildee.addMethod(mNode.getName(), PUBLIC_STATIC, 
mNode.getReturnType(), params(param(paramType, "initializer")), NO_EXCEPTIONS,
+                block(stmt(callX(buildee, newName, args(argsList)))));
+        renameMethod(buildee, mNode, newName);
+    }
+
+    // no rename so delete and add
+    private static void renameMethod(ClassNode buildee, MethodNode mNode, 
String newName) {
+        buildee.addMethod(newName, mNode.getModifiers(), 
mNode.getReturnType(), mNode.getParameters(), mNode.getExceptions(), 
mNode.getCode());
+        buildee.removeMethod(mNode);
+    }
+
+    private static Parameter[] getParams(List<FieldNode> fields, ClassNode 
cNode) {
+        Parameter[] parameters = new Parameter[fields.size()];
+        for (int i = 0; i < parameters.length; i++) {
+            FieldNode fNode = fields.get(i);
+            Map<String,ClassNode> genericsSpec = 
createGenericsSpec(fNode.getDeclaringClass());
+            extractSuperClassGenerics(fNode.getType(), cNode, genericsSpec);
+            ClassNode correctedType = 
correctToGenericsSpecRecurse(genericsSpec, fNode.getType());
+            parameters[i] = new Parameter(correctedType, fNode.getName());
+        }
+        return parameters;
+    }
+
+    private static ConstructorNode createInitializerConstructor(ClassNode 
buildee, ClassNode builder, List<FieldNode> fields) {
+        ClassNode paramType = makeClassSafeWithGenerics(builder, 
setGenTypes(fields.size()));
+        List<Expression> argsList = new ArrayList<Expression>();
+        Parameter initParam = param(paramType, "initializer");
+        for (FieldNode fieldNode : fields) {
+            argsList.add(propX(varX(initParam), fieldNode.getName()));
+        }
+        return buildee.addConstructor(ACC_PUBLIC, params(param(paramType, 
"initializer")), NO_EXCEPTIONS, block(ctorThisS(args(argsList))));
+    }
+
+    private static MethodNode createBuildMethod(ClassNode builder, String 
buildMethodName, List<FieldNode> fields) {
+        ClassNode returnType = makeClassSafeWithGenerics(builder, 
unsetGenTypes(fields.size()));
+        return new MethodNode(buildMethodName, PUBLIC_STATIC, returnType, 
NO_PARAMS, NO_EXCEPTIONS, block(returnS(ctorX(returnType))));
+    }
+
+    private MethodNode createBuilderMethodForField(ClassNode builder, 
List<FieldNode> fields, String prefix, int fieldPos) {
+        String fieldName = fields.get(fieldPos).getName();
+        String setterName = getSetterName(prefix, fieldName);
+        GenericsType[] gtypes = new GenericsType[fields.size()];
+        List<Expression> argList = new ArrayList<Expression>();
+        for (int i = 0; i < fields.size(); i++) {
+            gtypes[i] = i == fieldPos ? new 
GenericsType(ClassHelper.make(SET.class)) : makePlaceholder(i);
+            argList.add(i == fieldPos ? propX(varX("this"), constX(fieldName)) 
: varX(fields.get(i).getName()));
+        }
+        ClassNode returnType = makeClassSafeWithGenerics(builder, gtypes);
+        FieldNode fNode = fields.get(fieldPos);
+        Map<String,ClassNode> genericsSpec = 
createGenericsSpec(fNode.getDeclaringClass());
+        extractSuperClassGenerics(fNode.getType(), builder, genericsSpec);
+        ClassNode correctedType = correctToGenericsSpecRecurse(genericsSpec, 
fNode.getType());
+        return new MethodNode(setterName, ACC_PUBLIC, returnType, 
params(param(correctedType, fieldName)), NO_EXCEPTIONS, block(
+                stmt(assignX(propX(varX("this"), constX(fieldName)), 
varX(fieldName, correctedType))),
+                returnS(ctorX(returnType, args(argList)))
+        ));
+    }
+
+    private static GenericsType makePlaceholder(int i) {
+        ClassNode type = ClassHelper.makeWithoutCaching("T" + i);
+        type.setRedirect(OBJECT_TYPE);
+        type.setGenericsPlaceHolder(true);
+        return new GenericsType(type);
+    }
+
+    private static FieldNode createFieldCopy(ClassNode buildee, FieldNode 
fNode) {
+        Map<String,ClassNode> genericsSpec = 
createGenericsSpec(fNode.getDeclaringClass());
+        extractSuperClassGenerics(fNode.getType(), buildee, genericsSpec);
+        ClassNode correctedType = correctToGenericsSpecRecurse(genericsSpec, 
fNode.getType());
+        return new FieldNode(fNode.getName(), fNode.getModifiers(), 
correctedType, buildee, DEFAULT_INITIAL_VALUE);
+    }
+
+    private static List<FieldNode> filterFields(List<FieldNode> fieldNodes, 
List<String> includes, List<String> excludes, boolean allNames) {
+        List<FieldNode> fields = new ArrayList<FieldNode>();
+        for (FieldNode fNode : fieldNodes) {
+            if 
(AbstractASTTransformation.shouldSkipUndefinedAware(fNode.getName(), excludes, 
includes, allNames)) continue;
+            fields.add(fNode);
+        }
+        return fields;
+    }
+
+    private static void initializeFields(List<FieldNode> fields, 
BlockStatement body, boolean useSetters) {
+        for (FieldNode field : fields) {
+            String name = field.getName();
+            body.addStatement(
+                    stmt(useSetters && !field.isFinal()
+                                    ? callThisX(getSetterName(name), 
varX(param(field.getType(), name)))
+                                    : assignX(propX(varX("this"), 
field.getName()), varX(param(field.getType(), name)))
+                    )
+            );
+        }
+    }
+
+    private static String getSetterName(String name) {
+        return "set" + Verifier.capitalize(name);
+    }
+}

Reply via email to