groovy.lang.Newify Maven / Gradle / Ivy
/*
* 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.
*
* It allows you to write code snippets like this ("Python-style"):
*
* {@code @Newify([Tree,Leaf])} class MyTreeProcessor {
* def myTree = Tree(Tree(Leaf("A"), Leaf("B")), Leaf("C"))
* def process() { ... }
* }
*
* or this ("Ruby-style"):
*
* {@code @Newify} class MyTreeProcessor {
* def myTree = Tree.new(Tree.new(Leaf.new("A"), Leaf.new("B")), Leaf.new("C"))
* def process() { ... }
* }
*
*
* After the AST transformation, the following code is passed on for further compilation:
*
* class MyTreeProcessor {
* def myTree = new Tree(new Tree(new Leaf("A"), new Leaf("B")), new Leaf("C"))
* def process() { ... }
* }
*
* The annotation can be used on a whole class as shown above or selectively on a particular
* method, constructor or field.
*
* 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.
*
* The "Python-style" conversions require you to specify each class on which you want them
* to apply. 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 Leaf("A")
would be transformed to
* new Leaf("A")
but x.Leaf("A")
would not be touched.
*
* An example showing how to use the annotation at different levels:
*
* {@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(Bar)}
* def process() {
* field2 = Bar("my bar")
* }
*
* {@code @Newify(Baz)}
* Main() {
* field3 = Foo("my foo")
* field4 = Baz("my baz")
* }
* }
*
*
* 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.
*
* @author Paul King
*/
@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 {
Class>[] value() default {};
/**
* @return if automatic conversion of "Ruby-style" new method calls should occur
*/
boolean auto() default true;
}