001package arez.annotations; 002 003import arez.Arez; 004import arez.component.DisposeNotifier; 005import java.lang.annotation.Documented; 006import java.lang.annotation.ElementType; 007import java.lang.annotation.Target; 008import javax.annotation.Nonnull; 009 010/** 011 * Annotation that marks classes or interfaces to be processed by Arez annotation processor. 012 * Classes or interfaces with this annotation can contain {@link Observable} properties, 013 * {@link Memoize} properties, {@link Observe} methods and {@link Action} methods. 014 * 015 * <p>The annotation controls the way that contained actions and observables are 016 * named (if names are enabled in the system.</p> 017 * <ul> 018 * <li>The value returned by {@link #name()} indicates the type name for instances 019 * of this object. If not specified it will default to the SimpleName of the class. 020 * i.e. The class <code>com.biz.models.MyModel</code> will default to a name of 021 * "MyModel".</li> 022 * </ul> 023 * <p>The name of any elements contained within the component follows the pattern 024 * "<code>[ArezComponent.name].[ArezComponent.id].[Element.name]</code>".</p> 025 * 026 * <p>The type that is annotated with this annotation must comply with the additional constraints:</p> 027 * <ul> 028 * <li>Must be a class or an interface</li> 029 * <li>Must be abstract</li> 030 * <li>Must not be final</li> 031 * <li>Must not be a non-static nested class</li> 032 * <li>Must have at least one method annotated with {@link Action}, {@link Observe}, {@link Memoize} or {@link Observable}</li> 033 * </ul> 034 * 035 * <p>The annotation processor that handles this annotation will analyze all super classes and super 036 * interfaces. This includes analysis of default methods on interfaces. So it is perfectly valid to 037 * add annotations such as {@link Observable}, {@link Memoize}, {@link Action}, {@link PreDispose} and/or 038 * {@link PostDispose} to default methods on implemented interfaces.</p> 039 */ 040@Documented 041@Target( ElementType.TYPE ) 042@StingProvider( "[FlatEnclosingName]Arez_[SimpleName]" ) 043@ActAsStingConsumer 044@ActAsStingProvider 045public @interface ArezComponent 046{ 047 /** 048 * Return the name of the type. 049 * The value must conform to the requirements of a java identifier. 050 * 051 * @return the name of the type. 052 */ 053 @Nonnull 054 String name() default "<default>"; 055 056 /** 057 * Return true if the component does not need to explicitly declare elements. 058 * Otherwise if no elements (i.e. {@link Observable}s, {@link Action}s, {@link Observe}s etc) are defined 059 * on a component it will generate an error. 060 * 061 * @return true if the component does not need to explicitly declare elements, false otherwise. 062 */ 063 boolean allowEmpty() default false; 064 065 /** 066 * An enum controlling whether the component is treated like a service or an entity. 067 * A service is expected to be a long running component that exists based on the functionality of 068 * the application while an entity represents data within the application and may come and go based 069 * on changes in the application data. Within arez, the only practical effect is to change the default 070 * behaviour of other features. See the documentation for other parameters for further details. 071 * 072 * <p>If set as {@link Feature#AUTODETECT} or left as the default value, then Arez will assumes that if 073 * the component is injected using dependency injection, then the component is a service. Arez detects whether 074 * the type is annotated by the <a href="https://sting-ioc.github.io/">sting</a> annotations {@code sting.Named}, 075 * {@code sting.Typed} and {@code sting.Eager} or the jsr330 annotation {@code javax.inject.Named} or any 076 * annotation that is annotated with {@code javax.inject.Scope} annotation. If such an annotation is found then 077 * the component defaults to being treated like a service.</p> 078 * 079 * @return an enum controlling whether the component is treated like a service or an entity. 080 */ 081 Feature service() default Feature.AUTODETECT; 082 083 /** 084 * The enum to control whether the component should support being "observed" by implementing the 085 * {@link arez.component.ComponentObservable} interface and allowing invocation of the 086 * {@link arez.component.ComponentObservable#observe(Object)} method. If unset or explicitly set 087 * to {@link Feature#AUTODETECT} then the component will implement the interface if the 088 * {@link #disposeOnDeactivate()} parameter is {@code true}. 089 * 090 * @return enum to control whether the component should support being "observed". 091 */ 092 Feature observable() default Feature.AUTODETECT; 093 094 /** 095 * Return enum to control whether the component should support implement the {@link DisposeNotifier} interface. 096 * This will result in the component invoking dispose listener callbacks during dispose operation 097 * within the scope of the disposing transaction. 098 * 099 * <p>If the value of this parameter is {@link Feature#AUTODETECT} then the {@link DisposeNotifier} interface 100 * is not implemented if the {@link #service()} resolves to {@link Feature#ENABLE}.</p> 101 * 102 * @return Return enum to control whether the component should implement DisposeNotifier. 103 */ 104 Feature disposeNotifier() default Feature.AUTODETECT; 105 106 /** 107 * Return true if the component should dispose itself once it is no longer "observed". 108 * By "observed" it means that the component will have {@link arez.component.ComponentObservable#observe(Object)} 109 * called on it. This parameter MUST be false if {@link #observable()} has the value {@link Feature#DISABLE}. 110 * Components configured in this mode should not also be explicitly disposed by an owning component via 111 * {@link CascadeDispose}, otherwise the annotation processor will emit the suppressable warning 112 * {@code "Arez:ConflictingDisposeModel"}. 113 * 114 * @return true if the component should dispose itself once it is no longer "observed". 115 */ 116 boolean disposeOnDeactivate() default false; 117 118 /** 119 * Enum controlling whether sting integration is enabled. If enabled, the annotation processor will 120 * add sting annotations to the generated component implementation. If the value of this parameter is 121 * {@link Feature#AUTODETECT} then sting integration will be enabled if the {@link #service()} resolves 122 * to {@link Feature#ENABLE} and the {@code sting.Injector} class is present on the classpath. 123 * 124 * @return an enum controlling whether a sting integration is enabled. 125 */ 126 Feature sting() default Feature.AUTODETECT; 127 128 /** 129 * Indicate whether the {@link Object#hashCode()} and {@link Object#equals(Object)} methods need to be implemented. 130 * If set to {@link Feature#AUTODETECT} then the methods will not be generated. 131 * 132 * @return an enum whether the {@link Object#hashCode()} and {@link Object#equals(Object)} methods need to be implemented. 133 */ 134 Feature requireEquals() default Feature.AUTODETECT; 135 136 /** 137 * Indicates whether the component should support access of the id via {@link arez.component.Identifiable#getArezId(Object)}. 138 * The {@link Feature#AUTODETECT} will be treated as {@link Feature#ENABLE}. This feature must be enabled in 139 * the following scenarios: 140 * 141 * <ul> 142 * <li>a method annotated with the {@link Inverse} annotation is present.</li> 143 * <li>a method annotated with the {@link ComponentId} annotation is present.</li> 144 * <li>a method annotated with the {@link ComponentIdRef} annotation is present.</li> 145 * </ul> 146 * 147 * @return enum controlling whether a unique if of the component can be accessed via {@link arez.component.Identifiable#getArezId(Object)}. 148 */ 149 Feature requireId() default Feature.AUTODETECT; 150 151 /** 152 * Indicates whether the component should implement the interface {@link arez.component.Verifiable}. 153 * This feature is ignored unless {@link Arez#isVerifyEnabled()} is true. The {@link Feature#AUTODETECT} 154 * value will enable this feature if the component has any {@link Reference} methods or any {@link Inverse} methods. 155 * 156 * @return enum that indicates whether the component should implement the interface {@link arez.component.Verifiable}. 157 */ 158 Feature verify() default Feature.AUTODETECT; 159 160 /** 161 * Indicate whether references to the component should also be annotated with {@link CascadeDispose} or {@link ComponentDependency}. 162 * This is used to ensure that when a component is disposed that any reference to the component from another 163 * component is rectified. The annotation processor will warn if the above rules are violated. 164 * {@link Feature#ENABLE} will tell the annotation to warn if references to component are invalid. 165 * {@link Feature#DISABLE} disables the warning. {@link Feature#AUTODETECT} will enable the warning if 166 * the {@link #disposeNotifier()} resolves to {@link Feature#ENABLE}. 167 * 168 * @return enum controlling whether a references to components should be explicitly managed. 169 */ 170 Feature verifyReferencesToComponent() default Feature.AUTODETECT; 171 172 /** 173 * The default priority used by {@link Memoize} and {@link Observe} annotated methods. 174 * This parameter should only be specified if there are {@link Memoize} or {@link Observe} annotated 175 * methods present on the component. 176 * 177 * @return the default priority used by {@link Memoize} and {@link Observe} annotated methods. 178 */ 179 Priority defaultPriority() default Priority.NORMAL; 180 181 /** 182 * The default value for the readOutsideTransaction parameter of {@link Memoize} and {@link Observable} 183 * annotated methods. 184 * 185 * @return The flag indicating whether the default is to allow reads outside a transaction or to require a transaction to read observables and memoized values. 186 */ 187 Feature defaultReadOutsideTransaction() default Feature.AUTODETECT; 188 189 /** 190 * The default value for the writeOutsideTransaction parameter of {@link Observable} annotated methods. 191 * 192 * @return The flag indicating whether the default is to allow writes outside a transaction or to require a transaction to write observables values. 193 */ 194 Feature defaultWriteOutsideTransaction() default Feature.AUTODETECT; 195 196 /** 197 * The default value for the skipIfDisposed parameter of {@link Action} annotated methods. 198 * If an action has {@link Action#skipIfDisposed()} set to {@link Feature#AUTODETECT} then this parameter 199 * is consulted. If this parameter is also {@link Feature#AUTODETECT} then it is treated as 200 * {@link Feature#DISABLE}. 201 * 202 * @return The flag indicating whether the default is to skip actions after the owning component begins disposal. 203 */ 204 Feature defaultSkipIfDisposed() default Feature.AUTODETECT; 205}