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}