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]" )
043public @interface ArezComponent
044{
045  /**
046   * Return the name of the type.
047   * The value must conform to the requirements of a java identifier.
048   *
049   * @return the name of the type.
050   */
051  @Nonnull
052  String name() default "<default>";
053
054  /**
055   * Return true if the component does not need to explicitly declare elements.
056   * Otherwise if no elements (i.e. {@link Observable}s, {@link Action}s, {@link Observe}s etc) are defined
057   * on a component it will generate an error.
058   *
059   * @return true if the component does not need to explicitly declare elements, false otherwise.
060   */
061  boolean allowEmpty() default false;
062
063  /**
064   * An enum controlling whether the component is treated like a service or an entity.
065   * A service is expected to be a long running component that exists based on the functionality of
066   * the application while an entity represents data within the application and may come and go based
067   * on changes in the application data. Within arez, the only practical effect is to change the default
068   * behaviour of other features. See the documentation for other parameters for further details.
069   *
070   * <p>If set as {@link Feature#AUTODETECT} or left as the default value, then Arez will assumes that if
071   * the component is injected using dependency injection, then the component is a service. Arez detects whether
072   * the type is annotated by the <a href="https://sting-ioc.github.io/">sting</a> annotations {@code sting.Named},
073   * {@code sting.Typed} and {@code sting.Eager} or the jsr330 annotation {@code javax.inject.Named} or any
074   * annotation that is annotated with {@code javax.inject.Scope} annotation. If such an annotation is found then
075   * the component defaults to being treated like a service.</p>
076   *
077   * @return an enum controlling whether the component is treated like a service or an entity.
078   */
079  Feature service() default Feature.AUTODETECT;
080
081  /**
082   * The enum to control whether the component should support being "observed" by implementing the
083   * {@link arez.component.ComponentObservable} interface and allowing invocation of the
084   * {@link arez.component.ComponentObservable#observe(Object)} method. If unset or explicitly set
085   * to {@link Feature#AUTODETECT} then the component will implement the interface if the
086   * {@link #disposeOnDeactivate()} parameter is {@code true}.
087   *
088   * @return enum to control whether the component should support being "observed".
089   */
090  Feature observable() default Feature.AUTODETECT;
091
092  /**
093   * Return enum to control whether the component should support implement the {@link DisposeNotifier} interface.
094   * This will result in the component invoking dispose listener callbacks during dispose operation
095   * within the scope of the disposing transaction.
096   *
097   * <p>If the value of this parameter is {@link Feature#AUTODETECT} then the {@link DisposeNotifier} interface
098   * is not implemented if the {@link #service()} resolves to {@link Feature#ENABLE}.</p>
099   *
100   * @return Return enum to control whether the component should implement DisposeNotifier.
101   */
102  Feature disposeNotifier() default Feature.AUTODETECT;
103
104  /**
105   * Return true if the component should dispose itself once it is no longer "observed".
106   * By "observed" it means that the component will have {@link arez.component.ComponentObservable#observe(Object)}
107   * called on it. This parameter MUST be false if {@link #observable()} has the value {@link Feature#DISABLE}.
108   *
109   * @return true if the component should dispose itself once it is no longer "observed".
110   */
111  boolean disposeOnDeactivate() default false;
112
113  /**
114   * Enum controlling whether sting integration is enabled. If enabled, the annotation processor will
115   * add sting annotations to the generated component implementation. If the value of this parameter is
116   * {@link Feature#AUTODETECT} then sting integration will be enabled if the {@link #service()} resolves
117   * to {@link Feature#ENABLE} and the {@code sting.Injector} class is present on the classpath.
118   *
119   * @return an enum controlling whether a sting integration is enabled.
120   */
121  Feature sting() default Feature.AUTODETECT;
122
123  /**
124   * Indicate whether the {@link Object#hashCode()} and {@link Object#equals(Object)} methods need to be implemented.
125   * If set to {@link Feature#AUTODETECT} then the methods will not be generated.
126   *
127   * @return an enum whether the {@link Object#hashCode()} and {@link Object#equals(Object)} methods need to be implemented.
128   */
129  Feature requireEquals() default Feature.AUTODETECT;
130
131  /**
132   * Indicates whether the component should support access of the id via {@link arez.component.Identifiable#getArezId(Object)}.
133   * The {@link Feature#AUTODETECT} will be treated as {@link Feature#ENABLE}. This feature must be enabled in
134   * the following scenarios:
135   *
136   * <ul>
137   * <li>a method annotated with the {@link Inverse} annotation is present.</li>
138   * <li>a method annotated with the {@link ComponentId} annotation is present.</li>
139   * <li>a method annotated with the {@link ComponentIdRef} annotation is present.</li>
140   * </ul>
141   *
142   * @return enum controlling whether a unique if of the component can be accessed via {@link arez.component.Identifiable#getArezId(Object)}.
143   */
144  Feature requireId() default Feature.AUTODETECT;
145
146  /**
147   * Indicates whether the component should implement the interface {@link arez.component.Verifiable}.
148   * This feature is ignored unless {@link Arez#isVerifyEnabled()} is true. The {@link Feature#AUTODETECT}
149   * value will enable this feature if the component has any {@link Reference} methods or any {@link Inverse} methods.
150   *
151   * @return enum that indicates whether the component should implement the interface {@link arez.component.Verifiable}.
152   */
153  Feature verify() default Feature.AUTODETECT;
154
155  /**
156   * Indicate whether references to the component should also be annotated with {@link CascadeDispose} or {@link ComponentDependency}.
157   * This is used to ensure that when a component is disposed that any reference to the component from another
158   * component is rectified. The annotation processor will warn if the above rules are violated.
159   * {@link Feature#ENABLE} will tell the annotation to warn if references to component are invalid.
160   * {@link Feature#DISABLE} disables the warning. {@link Feature#AUTODETECT} will enable the warning if
161   * the {@link #disposeNotifier()} resolves to {@link Feature#ENABLE}.
162   *
163   * @return enum controlling whether a references to components should be explicitly managed.
164   */
165  Feature verifyReferencesToComponent() default Feature.AUTODETECT;
166
167  /**
168   * The default priority used by {@link Memoize} and {@link Observe} annotated methods.
169   * This parameter should only be specified if there are {@link Memoize} or {@link Observe} annotated
170   * methods present on the component.
171   *
172   * @return the default priority used by {@link Memoize} and {@link Observe} annotated methods.
173   */
174  Priority defaultPriority() default Priority.NORMAL;
175
176  /**
177   * The default value for the readOutsideTransaction parameter of {@link Memoize} and {@link Observable}
178   * annotated methods.
179   *
180   * @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.
181   */
182  Feature defaultReadOutsideTransaction() default Feature.AUTODETECT;
183
184  /**
185   * The default value for the writeOutsideTransaction parameter of {@link Observable} annotated methods.
186   *
187   * @return The flag indicating whether the default is to allow writes outside a transaction or to require a transaction to write observables values.
188   */
189  Feature defaultWriteOutsideTransaction() default Feature.AUTODETECT;
190}