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