001package arez.annotations; 002 003import arez.EqualityComparator; 004import arez.ObservableValue; 005import java.lang.annotation.Documented; 006import java.lang.annotation.ElementType; 007import java.lang.annotation.Target; 008import javax.annotation.Nonnull; 009 010/** 011 * Annotation applied to methods that expose an ObservableValue value in Arez. 012 * Methods annotated with this either query state or mutate state. The query 013 * method is expected to have 0 parameters and return a value and by default 014 * is named with "get" or "is" prefixed to the property name. The mutation 015 * method is expected to have a single parameter and return no value and by 016 * default is named with "set" prefixed to property name. The setter or getter 017 * can also be named matching the property name without the prefix. 018 * 019 * <p>Only one of the query or mutation method needs to be annotated with 020 * this annotation if the other method follows the normal conventions. If 021 * the other method does not conform to conventions, then you will need to 022 * annotate the pair and specify a value for {@link #name()}.</p> 023 * 024 * <p>The method should only invoked within the scope of a transaction. 025 * The mutation method requires that the transaction be READ_WRITE.</p> 026 * 027 * <p>The method that is annotated with this annotation must also comply with the following constraints:</p> 028 * <ul> 029 * <li>Must not be annotated with any other arez annotation</li> 030 * <li>Must not be private</li> 031 * <li>Must not be static</li> 032 * <li>Must not be final</li> 033 * <li>May be abstract but if abstract then the paired setter or getter must also be abstract</li> 034 * <li>Must be accessible to the class annotated by the {@link ArezComponent} annotation.</li> 035 * </ul> 036 * 037 * <p>This annotation is only supported on methods contained within a type annotated by 038 * {@link ArezComponent} or {@link ArezComponentLike}. Other usages will fail compilation.</p> 039 */ 040@Documented 041@Target( ElementType.METHOD ) 042public @interface Observable 043{ 044 /** 045 * Return the name of the ObservableValue relative to the component. If not specified 046 * will default to the name of the property by convention as described above. 047 * The value must conform to the requirements of a java identifier. 048 * The name must also be unique across {@link Observable}s, 049 * {@link Memoize}s and {@link Action}s within the scope of the 050 * {@link ArezComponent} annotated element. 051 * 052 * @return the name of the ObservableValue relative to the component. 053 */ 054 @Nonnull 055 String name() default "<default>"; 056 057 /** 058 * Set this to false if there is no setter method and the component is 059 * expected to use {@link ObservableValueRef} to indicate when value has changed. 060 * 061 * @return true if there is expected to be a setter, false if there should be no setter. 062 */ 063 boolean expectSetter() default true; 064 065 /** 066 * Indicate whether the generated component class should add a parameter to the constructor to initialize this property. 067 * This parameter should only be set to {@link Feature#ENABLE} when the observable property is defined by a 068 * pair of abstract methods. If set to {@link Feature#AUTODETECT} then an initializer will be added for an 069 * observable property if it is defined by a pair of abstract methods and the values is annotated with the 070 * {@link Nonnull} annotation and it is not annotated by {@link Inverse}. 071 * It is an error to set this parameter to {@link Feature#ENABLE} when the property has an 072 * {@link ObservableInitial} annotation. If {@link ObservableInitial} is present and this parameter is 073 * {@link Feature#AUTODETECT}, the initializer is treated as {@link Feature#DISABLE}. 074 * 075 * <p>The initializer parameters will be added as additional parameters at the end of the parameter list in 076 * the generated classes constructors. The initializers will be defined in the order that the observable 077 * properties are declared. They properties be assigned after the parent constructor has been invoked.</p> 078 * 079 * @return flag controlling whether a parameter should be added to the constructor to initialize the property. 080 */ 081 @Nonnull 082 Feature initializer() default Feature.AUTODETECT; 083 084 /** 085 * Indicate whether the observable can be read outside a transaction. 086 * If the value is {@link Feature#AUTODETECT} then the value will be derived from the 087 * {@link ArezComponent#defaultReadOutsideTransaction()} parameter on the {@link ArezComponent} annotation. If 088 * the value is set to {@link Feature#ENABLE} then the observable can be read outside a transaction and the 089 * {@link ObservableValue#reportObserved()} will only be invoked if the observables is accessed from within 090 * a tracking transaction (i.e. when an {@link arez.Observer} or {@link arez.ComputableValue} creates the 091 * transaction). Thus, {@link Action} annotated methods that only access observables that set the 092 * readOutsideTransaction parameter to {@link Feature#ENABLE} and neither access nor modify other arez elements 093 * no longer need to be annotated with {@link Action} annotations. 094 * 095 * @return flag that determines whether the observable allows reads outside a transaction, false to require a transaction to read the observable. 096 */ 097 Feature readOutsideTransaction() default Feature.AUTODETECT; 098 099 /** 100 * Return true if the observable will create an action if the write occurs outside a transaction. 101 * 102 * @return true to allow writes to create an action if needed, false to require a transaction to write observable. 103 */ 104 Feature writeOutsideTransaction() default Feature.AUTODETECT; 105 106 /** 107 * Return false if the setter should verify observable value has changed before propagating change. 108 * In some scenarios, the setter method will modify the value before updating the observable or may 109 * decide to abort the update. This setting will force the generated code to check the value of the 110 * observable property after the setter and only invoke {@link ObservableValue#reportChanged()} if 111 * a change has actually occurred. 112 * 113 * <p>This parameter should not be set to false if the associated setter is abstract. It is also 114 * invalid to set this value to false if {@link #expectSetter()} is false.</p> 115 * 116 * @return false if the setter should verify observable value has changed before propagating change. 117 */ 118 boolean setterAlwaysMutates() default true; 119 120 /** 121 * Return the strategy used to compare values when checking whether the observable has changed. 122 * If this parameter is left as {@link EqualityComparator} then the annotation processor will 123 * derive the comparator from the exact declared observable type when that type is annotated 124 * with {@link DefaultEqualityComparator}. If no type-level default is present then 125 * {@link arez.ObjectsEqualsComparator} will be used. 126 * 127 * <p>Explicitly specifying a comparator on the annotation overrides any type-level default. 128 * Type-level defaults are not derived for arrays, type-use annotations, or supertypes and 129 * interfaces other than the exact declared type.</p> 130 * 131 * @return the comparator type used when checking whether values are equal. 132 */ 133 @Nonnull 134 Class<? extends EqualityComparator> equalityComparator() default EqualityComparator.class; 135}