| 
01 /*02  * Copyright 2008-2017 the original author or authors.
 03  *
 04  * Licensed under the Apache License, Version 2.0 (the "License");
 05  * you may not use this file except in compliance with the License.
 06  * You may obtain a copy of the License at
 07  *
 08  *     http://www.apache.org/licenses/LICENSE-2.0
 09  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 package griffon.transform;
 17
 18 import org.codehaus.groovy.transform.GroovyASTTransformationClass;
 19
 20 import java.lang.annotation.ElementType;
 21 import java.lang.annotation.Retention;
 22 import java.lang.annotation.RetentionPolicy;
 23 import java.lang.annotation.Target;
 24
 25 /**
 26  * <p>Annotates a property.</p>
 27  * <p>This transformation provides a convenient way to register MapChangeListeners
 28  * on an ObservableMap by leveraging Groovy's closures and the Groovy cast operator.</p>
 29  * <p/>
 30  * <p>The following code exemplifies what must be written by hand in order to register a ChangeListener.
 31  * <pre>
 32  * import griffon.transform.MapChangeListener
 33  * import griffon.transform.FXObservable
 34  * import javafx.collections.FXCollections
 35  * import javafx.collections.ObservableMap
 36  * import griffon.core.artifact.GriffonModel
 37  *
 38  * @griffon.metadata.ArtifactProviderFor(GriffonModel)
 39  * class SampleModel {
 40  *     def controller
 41  *
 42  *     @FXObservable
 43  *     @MapChangeListener(snoop)
 44  *     ObservableMap map = FXCollections.observableHashMap()
 45  *
 46  *     def snoop = { change -> ... }
 47  * }
 48  * </pre>
 49  * <p/>
 50  * <p>Applying @ChangeListener to the previous snippet results in the following code</p>
 51  * <pre>
 52  * import javafx.collections.MapChangeListener
 53  * import javafx.collections.FXCollections
 54  * import javafx.collections.ObservableMap
 55  * import griffon.core.artifact.GriffonModel
 56  *
 57  * @griffon.metadata.ArtifactProviderFor(GriffonModel)
 58  * class SampleModel {
 59  *    def controller
 60  *
 61  *     @FXObservable ObservableMap map = FXCollections.observableHashMap()
 62  *
 63  *     def snoop = { change -> ... }
 64  *
 65  *     SampleModel() {
 66  *         mapProperty().addListener(snoopAll as MapChangeListener)
 67  *     }
 68  * }
 69  * </pre>
 70  * <p>
 71  * Any closures found as the annotation's value will be either transformed
 72  * into inner classes that implement MapChangeListener (when the value
 73  * is a closure defined in place) or be casted as a proxy of MapChangeListener
 74  * (when the value is a property reference found in the same class).<p>
 75  * List of closures are also supported.
 76  *
 77  * @author Andres Almiray
 78  * @since 2.4.0
 79  */
 80 @Retention(RetentionPolicy.SOURCE)
 81 @Target({ElementType.FIELD})
 82 @GroovyASTTransformationClass("org.codehaus.griffon.compile.core.ast.transform.MapChangeListenerASTTransformation")
 83 public @interface MapChangeListener {
 84     String value();
 85
 86     /**
 87      * If the {@code MapChangeListener} should be wrapped with a {@code WeakMapChangeListener} or not
 88      */
 89     boolean weak() default false;
 90 }
 |