001package react4j.annotations; 002 003import arez.annotations.ActAsComponent; 004import arez.annotations.ArezComponent; 005import arez.annotations.Memoize; 006import arez.annotations.Observable; 007import arez.annotations.Observe; 008import arez.component.Identifiable; 009import java.lang.annotation.Documented; 010import java.lang.annotation.ElementType; 011import java.lang.annotation.Target; 012import javax.annotation.Nonnull; 013import react4j.Keyed; 014 015/** 016 * Annotation used to specify an abstract method that returns a prop. 017 * The property is extracted from Reacts underlying props object. By default the prop is passed as 018 * a value in when creating the view but it can also be retrieved from the react context. 019 * 020 * <p>The method that is annotated with this annotation must also comply with the following constraints:</p> 021 * <ul> 022 * <li>Must not be annotated with any other react annotation</li> 023 * <li>Must have 0 parameters</li> 024 * <li>Must return a value</li> 025 * <li>Must be an abstract instance method</li> 026 * <li>Must not throw exceptions</li> 027 * <li>Must be accessible from the same package as the class annotated by {@link View}</li> 028 * <li> 029 * Should not be public as not expected to be invoked outside the view. A warning will be generated but can 030 * be suppressed by the {@link SuppressWarnings} or {@link SuppressReact4jWarnings} annotations with a key 031 * "React4j:PublicMethod". This warning is also suppressed by the annotation processor if it is implementing 032 * an interface method. 033 * </li> 034 * <li> 035 * Should not be protected if in the class annotated with the {@link View} annotation as the method is not 036 * expected to be invoked outside the view. A warning will be generated but can be suppressed by the 037 * {@link SuppressWarnings} or {@link SuppressReact4jWarnings} annotations with a key "React4j:ProtectedMethod". 038 * </li> 039 * <li> 040 * Should be annotated with either {@link javax.annotation.Nonnull} or {@link javax.annotation.Nullable} if the 041 * return type is not a primitive. A warning will be generated but can be suppressed by the {@link SuppressWarnings} 042 * or {@link SuppressReact4jWarnings} annotations with a key "React4j:MissingInputNullability". 043 * </li> 044 * </ul> 045 */ 046@Documented 047@Target( ElementType.METHOD ) 048public @interface Input 049{ 050 /** 051 * Return the name of the input. 052 * The name is the key used when accessing the input from the inputs object. It is also used when creating 053 * the builder steps associated with the inputs that set {@link #source()} to {@link Source#DEFAULT}. 054 * 055 * @return the name of the input. 056 */ 057 @Nonnull 058 String name() default "<default>"; 059 060 /** 061 * Return the qualifier used to access value from context. 062 * It must only be specified if {@link #source()} is set to {@link Source#CONTEXT}. 063 * 064 * @return the qualifier used to access value from context. 065 */ 066 @Nonnull 067 String qualifier() default ""; 068 069 /** 070 * The setting controlling where the input value is source from. 071 * If the source is set to {@link Source#CONTEXT} then the input is sometimes described as a "TreeInput" 072 * as it is transparently passed from a parent view to all child views. A "TreeInput" does not 073 * have to be specified by the user when creating the view. 074 * 075 * @return the setting controlling where the input value is source from. 076 */ 077 Source source() default Source.DEFAULT; 078 079 /** 080 * Setting indicating whether the input should be supplied when the view is constructed. 081 * This influences validation when enabled and how the Builder class is created. 082 * If set to {@link Feature#ENABLE} then the user MUST supply the input and the builder will require the user 083 * to specify the value. If set to {@link Feature#DISABLE} then the user can optionally supply the input. 084 * If set to {@link Feature#AUTODETECT} then the annotation processor will treat it as {@link Feature#DISABLE} 085 * if there is a corresponding {@link InputDefault} for the input or the {@link #source()} parameter is set to 086 * {@link Source#CONTEXT}, otherwise it will be treated as {@link Feature#ENABLE}. The value of this setting 087 * must not be {@link Feature#ENABLE} when {@link #source()} is set to {@link Source#CONTEXT}. 088 * 089 * @return the flag indicating whether the input needs to be supplied. 090 */ 091 Feature require() default Feature.AUTODETECT; 092 093 /** 094 * Indicate whether the input should be annotated by {@link Observable}. 095 * 096 * <p>If set to {@link Feature#AUTODETECT} then the input will be observable if and only if:</p> 097 * <ul> 098 * <li>{@link #immutable()} ()} is not set to {@code true}.</li> 099 * <li>the view has at least one method annotated with {@link Memoize} or {@link Observe}.</li> 100 * </ul> 101 * 102 * @return the enum indicating whether input is observable. 103 */ 104 Feature observable() default Feature.AUTODETECT; 105 106 /** 107 * Return an enum indicating whether the view should check whether the value of the input is disposed 108 * prior to rendering. If the value is disposed then the render method will exit early and return null. 109 * If this parameter is set to {@link Feature#AUTODETECT} then the annotation processor will inspect the 110 * type of the input and treat it as {@link Feature#ENABLE} if the type is annotated with the {@link ArezComponent} 111 * annotation or the {@link ActAsComponent} annotation. 112 * 113 * @return an enum indicating whether the view should check whether the value of the input is disposed prior to rendering. 114 */ 115 Feature disposable() default Feature.AUTODETECT; 116 117 /** 118 * Return an enum indicating whether the view should be disposed if the input is disposed. To enable this feature, 119 * the input MUST set {@link #immutable()} to <code>true</code>, {@link #disposable()} MUST resolve to 120 * {@link Feature#ENABLE}. The type of the input is expected to implement the {@link arez.component.DisposeNotifier} 121 * interface either directly or indirectly. If this parameter is set to {@link Feature#AUTODETECT} then the 122 * annotation processor will treat it as {@link Feature#ENABLE} if {@link #immutable()} is <code>true</code> and 123 * {@link #disposable()} resolves to {@link Feature#ENABLE}. 124 * 125 * @return an enum indicating whether the view should be disposed if the input is disposed. 126 */ 127 Feature dependency() default Feature.AUTODETECT; 128 129 /** 130 * True if the input is not expected to change after initial value is set. If the value of the input does change 131 * then it is expected that the view will be unmounted and a new view created. This is implemented 132 * by synthesizing a key for the view every time the view that is derived from this input. To enable this 133 * the annotation processor must be able to identify the type of the input so that a key can be synthesized. The 134 * following types are supported by the annotation processor; 135 * 136 * <ul> 137 * <li>primitive types (i.e. boolean, short etc) and their corresponding boxed types (i.e. {@link java.lang.Boolean}, {@link java.lang.Short} etc).</li> 138 * <li>the {@link java.lang.String} type</li> 139 * <li>any class that implements {@link Keyed}</li> 140 * <li>any class that is annotated with {@link ArezComponent} where the {@link ArezComponent#requireId()} parameter does not resolve to {@link arez.annotations.Feature#DISABLE}</li> 141 * <li>any class or interface that is annotated with {@link ActAsComponent}. It is assumed that every implementation is an Arez component where the {@link ArezComponent#requireId()} parameter does not resolve to {@link arez.annotations.Feature#DISABLE}</li> 142 * <li>any class or interface that is compatible with {@link Identifiable}</li> 143 * <li>if none of the above scenarios is valid then the code will attempt to derive the key at runtime. First via the {@link Keyed} interface, then the {@link Identifiable} interface and if these strategies are not possible then toString() will be invoked on the input.</li> 144 * </ul> 145 * 146 * <p>It should be noted that if a type implements {@link Keyed} and is annotated with either {@link ArezComponent} 147 * or {@link ActAsComponent} then the annotation processor will assume the {@link Keyed} interface is to used in 148 * preference to other alternative strategies.</p> 149 * 150 * @return true if changing the input recreates the view. 151 */ 152 boolean immutable() default false; 153 154 /** 155 * Enum where the input is sourced from. 156 */ 157 enum Source 158 { 159 /** 160 * The input value is passed to the view during construction. 161 */ 162 DEFAULT, 163 /** 164 * The input value is retrieved from the react context. 165 */ 166 CONTEXT 167 } 168}