| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package groovy.lang; |
| |
| import org.codehaus.groovy.transform.GroovyASTTransformationClass; |
| |
| import java.lang.annotation.ElementType; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.lang.annotation.Target; |
| |
| /** |
| * Annotation that supports writing constructor call expressions without the 'new' |
| * keyword. Instead they can be written "Ruby-style" as a method call to a 'new' |
| * method or "Python-style" by just omitting the 'new' keyword. |
| * <p> |
| * WARNING: For the Python style with class-name-matching pattern, the pattern should be chosen as to avoid matching |
| * method names if possible. If following Java/Groovy naming conventions, class names (contrary to method names) start |
| * with an uppercase letter. In this case {@code pattern="[A-Z].*"} (see {@link java.util.regex.Pattern} for supported |
| * Java pattern syntax) is the recommended pattern to allow all classes to be created without requiring a new keyword. |
| * Using a pattern that also matches method names (e.g. ".+", ".*" or "[a-zA-Z].*") might negatively impact build |
| * performance, since the Groovy compiler will have to match every class in context against any potential constructor |
| * call. |
| * <p> |
| * {@literal @Newify} allows you to write code snippets like this ("Python-style"): |
| * <pre> |
| * {@code @Newify([Tree,Leaf])} class MyTreeProcessor { |
| * def myTree = Tree(Tree(Leaf("A"), Leaf("B")), Leaf("C")) |
| * def process() { ... } |
| * } |
| * </pre> |
| * <pre> |
| * {@code // Any class whose name matches pattern can be created without new} |
| * {@code @Newify(pattern="[A-Z].*")} class MyTreeProcessor { |
| * final myTree = Tree(Tree(Leaf("A"), Leaf("B")), Leaf("C")) |
| * final sb = StringBuilder("...") |
| * def dir = File('.') |
| * def root = XmlSlurper().parseText(File(dir, sb.toString()).text) |
| * } |
| * </pre> |
| * or this ("Ruby-style"): |
| * <pre> |
| * {@code @Newify} class MyTreeProcessor { |
| * def myTree = Tree.new(Tree.new(Leaf.new("A"), Leaf.new("B")), Leaf.new("C")) |
| * def process() { ... } |
| * } |
| * </pre> |
| * |
| * After the AST transformation, the following code is passed on for further compilation: |
| * <pre> |
| * class MyTreeProcessor { |
| * def myTree = new Tree(new Tree(new Leaf("A"), new Leaf("B")), new Leaf("C")) |
| * def process() { ... } |
| * } |
| * </pre> |
| * The annotation can be used on a whole class as shown above or selectively on a particular |
| * method, constructor or field. |
| * <p> |
| * The "Ruby-style" new conversions occur automatically unless the 'auto=false' |
| * flag is given when using the annotation. You might do this if you create a new method |
| * using meta programming. |
| * <p> |
| * For the "Python-style" conversions you can either specify each class name on which you want them |
| * to apply, or supply a pattern to match class names against. The transformation then works by |
| * matching the basename of the provided classes to any |
| * similarly named instance method calls not specifically bound to an object, i.e. associated |
| * with the 'this' object. In other words <code>Leaf("A")</code> would be transformed to |
| * <code>new Leaf("A")</code> but <code>x.Leaf("A")</code> would not be touched. |
| * <p> |
| * An example showing how to use the annotation at different levels: |
| * <pre> |
| * {@code @Newify(auto=false, value=Foo)} |
| * class Main { |
| * {@code @Newify} // turn auto on for field |
| * def field1 = java.math.BigInteger.new(42) |
| * def field2, field3, field4 |
| * |
| * {@code @Newify(pattern="[A-z][A-Za-z0-9_]*")} // Any class name that starts with an uppercase letter |
| * def process() { |
| * field2 = A(Bb(Ccc("my bar"))) |
| * } |
| * |
| * {@code @Newify(Baz)} |
| * Main() { |
| * field3 = Foo("my foo") |
| * field4 = Baz("my baz") |
| * } |
| * } |
| * </pre> |
| * |
| * The annotation is intended to be used sparingly; perhaps in DSL scenarios or when |
| * using deeply nested structural types. In particular, there is no support for using |
| * the facility with two similarly named classes from different packages at the same time. |
| * Though it is OK to have different packages in different contexts. Also, there is |
| * no support for turning "Ruby-style" conversions off at the method, constructor or |
| * field level if already turned on at the class level. |
| */ |
| @java.lang.annotation.Documented |
| @Retention(RetentionPolicy.SOURCE) |
| @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.TYPE, ElementType.FIELD, ElementType.LOCAL_VARIABLE}) |
| @GroovyASTTransformationClass("org.codehaus.groovy.transform.NewifyASTTransformation") |
| public @interface Newify { |
| /** |
| * @return one or more classes where "Python-style" constructor notation will be supported |
| */ |
| Class<?>[] value() default {}; |
| |
| /** |
| * @return if automatic conversion of "Ruby-style" new method calls should occur |
| */ |
| boolean auto() default true; |
| |
| /** |
| * @since 2.5.0 |
| * @return a regex pattern for class names where "Python-style" constructor notation will be supported |
| */ |
| String pattern() default ""; |
| } |