http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/transform/TypeChecked.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/TypeChecked.java b/src/main/groovy/transform/TypeChecked.java deleted file mode 100644 index b902f3f..0000000 --- a/src/main/groovy/transform/TypeChecked.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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/10110145/src/main/groovy/transform/TypeCheckingMode.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/TypeCheckingMode.java b/src/main/groovy/transform/TypeCheckingMode.java deleted file mode 100644 index 075bd71..0000000 --- a/src/main/groovy/transform/TypeCheckingMode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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/10110145/src/main/groovy/transform/Undefined.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/Undefined.java b/src/main/groovy/transform/Undefined.java deleted file mode 100644 index 35b360d..0000000 --- a/src/main/groovy/transform/Undefined.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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/10110145/src/main/groovy/transform/WithReadLock.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/WithReadLock.java b/src/main/groovy/transform/WithReadLock.java deleted file mode 100644 index 475786a..0000000 --- a/src/main/groovy/transform/WithReadLock.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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<String, String> data = new HashMap<String, String>(); - * - * {@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<String, String> data = new HashMap<String, String>(); - * - * 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/10110145/src/main/groovy/transform/WithWriteLock.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/WithWriteLock.java b/src/main/groovy/transform/WithWriteLock.java deleted file mode 100644 index 1eeb7f0..0000000 --- a/src/main/groovy/transform/WithWriteLock.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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<String, String> data = new HashMap<String, String>(); - * - * {@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<String, String> data = new HashMap<String, String>(); - * - * 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/10110145/src/main/groovy/transform/builder/Builder.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/builder/Builder.java b/src/main/groovy/transform/builder/Builder.java deleted file mode 100644 index 93b6090..0000000 --- a/src/main/groovy/transform/builder/Builder.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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/10110145/src/main/groovy/transform/builder/DefaultStrategy.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/builder/DefaultStrategy.java b/src/main/groovy/transform/builder/DefaultStrategy.java deleted file mode 100644 index 65d90e3..0000000 --- a/src/main/groovy/transform/builder/DefaultStrategy.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * 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. 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. 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/10110145/src/main/groovy/transform/builder/ExternalStrategy.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/builder/ExternalStrategy.java b/src/main/groovy/transform/builder/ExternalStrategy.java deleted file mode 100644 index c482bef..0000000 --- a/src/main/groovy/transform/builder/ExternalStrategy.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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. 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/10110145/src/main/groovy/transform/builder/InitializerStrategy.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/builder/InitializerStrategy.java b/src/main/groovy/transform/builder/InitializerStrategy.java deleted file mode 100644 index e59dac5..0000000 --- a/src/main/groovy/transform/builder/InitializerStrategy.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * 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 correct 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); - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/transform/builder/SimpleStrategy.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/builder/SimpleStrategy.java b/src/main/groovy/transform/builder/SimpleStrategy.java deleted file mode 100644 index 7956ac6..0000000 --- a/src/main/groovy/transform/builder/SimpleStrategy.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.Parameter; -import org.codehaus.groovy.transform.AbstractASTTransformation; -import org.codehaus.groovy.transform.BuilderASTTransformation; -import org.objectweb.asm.Opcodes; - -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.callThisX; -import static org.codehaus.groovy.ast.tools.GeneralUtils.fieldX; -import static org.codehaus.groovy.ast.tools.GeneralUtils.getInstancePropertyFields; -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.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.AbstractASTTransformation.getMemberStringValue; -import static org.codehaus.groovy.transform.BuilderASTTransformation.NO_EXCEPTIONS; - -/** - * This strategy is used with the {@link Builder} AST transform to modify your Groovy objects so that the - * setter methods for properties return the original object, thus allowing chained usage of the setters. - * - * You use it as follows: - * <pre class="groovyTestCase"> - * import groovy.transform.builder.* - * - * {@code @Builder}(builderStrategy=SimpleStrategy) - * class Person { - * String firstName - * String lastName - * int age - * } - * def person = new Person().setFirstName("Robert").setLastName("Lewandowski").setAge(21) - * 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, e.g. with the prefix set to the empty String, you would use your setters as follows: - * <pre> - * def p1 = new Person().firstName("Robert").lastName("Lewandowski").age(21) - * </pre> - * or using a prefix of 'with': - * <pre> - * def p2 = new Person().withFirstName("Robert").withLastName("Lewandowski").withAge(21) - * </pre> - * When using the default prefix of "set", Groovy's normal setters will be replaced by the chained versions. When using - * a custom prefix, Groovy's unchained setters will still be available for use in the normal unchained fashion. - * - * The 'useSetters' annotation attribute can be used for writable properties as per the {@code Builder} transform documentation. - * The other annotation attributes for the {@code @Builder} transform for configuring the building process aren't applicable for this strategy. - * - * @author Paul King - */ -public class SimpleStrategy extends BuilderASTTransformation.AbstractBuilderStrategy { - 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 buildee = (ClassNode) annotatedNode; - if (unsupportedAttribute(transform, anno, "builderClassName")) return; - if (unsupportedAttribute(transform, anno, "buildMethodName")) return; - if (unsupportedAttribute(transform, anno, "builderMethodName")) return; - if (unsupportedAttribute(transform, anno, "forClass")) return; - if (unsupportedAttribute(transform, anno, "includeSuperProperties")) return; - if (unsupportedAttribute(transform, anno, "allProperties")) return; - boolean useSetters = transform.memberHasValue(anno, "useSetters", true); - boolean allNames = transform.memberHasValue(anno, "allNames", true); - - 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; - String prefix = getMemberStringValue(anno, "prefix", "set"); - List<FieldNode> fields = getFields(transform, anno, buildee); - if (includes != null) { - for (String name : includes) { - checkKnownField(transform, anno, name, fields); - } - } - for (FieldNode field : fields) { - String fieldName = field.getName(); - if (!AbstractASTTransformation.shouldSkipUndefinedAware(fieldName, excludes, includes, allNames)) { - String methodName = getSetterName(prefix, fieldName); - Parameter parameter = param(field.getType(), fieldName); - buildee.addMethod(methodName, Opcodes.ACC_PUBLIC, newClass(buildee), params(parameter), NO_EXCEPTIONS, block( - stmt(useSetters && !field.isFinal() - ? callThisX(getSetterName("set", fieldName), varX(parameter)) - : assignX(fieldX(field), varX(parameter)) - ), - returnS(varX("this"))) - ); - } - } - } - - @Override - protected List<FieldNode> getFields(BuilderASTTransformation transform, AnnotationNode anno, ClassNode buildee) { - return getInstancePropertyFields(buildee); - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/transform/stc/ClosureParams.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/stc/ClosureParams.java b/src/main/groovy/transform/stc/ClosureParams.java deleted file mode 100644 index e788d44..0000000 --- a/src/main/groovy/transform/stc/ClosureParams.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.stc; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Parameter annotation aimed at helping IDEs or the static type checker to infer the - * parameter types of a closure. Without this annotation, a method signature may look like - * this:<p> - * <code>public <T,R> List<R> doSomething(List<T> source, Closure<R> consumer)</code> - * <p> - * <p>The problem this annotation tries to solve is to define the expected parameter types of the - * <i>consumer</i> closure. The generics type defined in <code>Closure<R></code> correspond to the - * result type of the closure, but tell nothing about what the closure must accept as arguments.</p> - * <p></p> - * <p>There's no way in Java or Groovy to express the type signature of the expected closure call method from - * outside the closure itself, so we rely on an annotation here. Unfortunately, annotations also have limitations - * (like not being able to use generics placeholder as annotation values) that prevent us from expressing the - * type directly.</p> - * <p>Additionally, closures are polymorphic. This means that a single closure can be used with different, valid, - * parameter signatures. A typical use case can be found when a closure accepts either a {@link java.util.Map.Entry} - * or a (key,value) pair, like the {@link org.codehaus.groovy.runtime.DefaultGroovyMethods#each(java.util.Map, groovy.lang.Closure)} - * method.</p> - * <p>For those reasons, the {@link ClosureParams} annotation takes these arguments: - * <ul> - * <li>{@link ClosureParams#value()} defines a {@link groovy.transform.stc.ClosureSignatureHint} hint class - * that the compiler will use to infer the parameter types</li> - * <li>{@link ClosureParams#conflictResolutionStrategy()} defines a {@link groovy.transform.stc.ClosureSignatureConflictResolver} resolver - * class that the compiler will use to potentially reduce ambiguities remaining after initial inference calculations</li> - * <li>{@link ClosureParams#options()}, a set of options that are passed to the hint when the type is inferred (and also available to the resolver)</li> - * </ul> - * </p> - * <p>As a result, the previous signature can be written like this:</p> - * <code>public <T,R> List<R> doSomething(List<T> source, @ClosureParams(FirstParam.FirstGenericType.class) Closure<R> consumer)</code> - * <p>Which uses the {@link FirstParam.FirstGenericType} first generic type of the first argument</p> hint to tell that the only expected - * argument type corresponds to the type of the first generic argument type of the first method parameter. - */ -@Target(ElementType.PARAMETER) -@Retention(RetentionPolicy.RUNTIME) -public @interface ClosureParams { - Class<? extends ClosureSignatureHint> value(); - Class<? extends ClosureSignatureConflictResolver> conflictResolutionStrategy() default ClosureSignatureConflictResolver.class; - String[] options() default {}; -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/transform/stc/ClosureSignatureConflictResolver.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/transform/stc/ClosureSignatureConflictResolver.java b/src/main/groovy/transform/stc/ClosureSignatureConflictResolver.java deleted file mode 100644 index d727958..0000000 --- a/src/main/groovy/transform/stc/ClosureSignatureConflictResolver.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.stc; - -import org.codehaus.groovy.ast.ClassNode; -import org.codehaus.groovy.ast.MethodNode; -import org.codehaus.groovy.ast.expr.ClosureExpression; -import org.codehaus.groovy.ast.expr.Expression; -import org.codehaus.groovy.control.CompilationUnit; -import org.codehaus.groovy.control.SourceUnit; - -import java.util.List; - -/** - * If multiple candidate signatures are found after applying type hints, - * a conflict resolver can attempt to resolve the ambiguity. - * - * @since 2.5.0 - */ -public class ClosureSignatureConflictResolver { - /** - * - * @param candidates the list of signatures as determined after applying type hints and performing initial inference calculations - * @param receiver the receiver the method is being called on - * @param arguments the arguments for the closure - * @param closure the closure expression under analysis - * @param methodNode the method for which a {@link groovy.lang.Closure} parameter was annotated with {@link ClosureParams} - * @param sourceUnit the source unit of the file being compiled - * @param compilationUnit the compilation unit of the file being compiled - * @param options the options, corresponding to the {@link ClosureParams#options()} found on the annotation - * @return a non-null list of signatures, where a signature corresponds to an array of class nodes, each of them matching a parameter. A list with more than one element indicates that all ambiguities haven't yet been resolved. - */ - public List<ClassNode[]> resolve(List<ClassNode[]> candidates, ClassNode receiver, Expression arguments, ClosureExpression closure, - MethodNode methodNode, SourceUnit sourceUnit, CompilationUnit compilationUnit, String[] options) { - // do nothing by default - return candidates; - } -}
