001package arez.annotations;
002
003import arez.component.DisposeNotifier;
004import java.lang.annotation.Documented;
005import java.lang.annotation.ElementType;
006import java.lang.annotation.Target;
007import javax.annotation.Nonnull;
008
009/**
010 * Methods and fields marked with this annotation are dependencies of the component.
011 * If the dependency is disposed then the component takes an action to cascade the dispose
012 * or null the property referencing the dependency. The dependency MUST implement the
013 * {@link DisposeNotifier} interface.
014 *
015 * <p>It should be noted that it is preferable for the field that defines the dependency is marked
016 * with this annotation rather than the method accessor. The reason is that the annotation processor
017 * will issue a warning if a field that the processor identifies as a potential dependency if it is
018 * not annotated with {@link AutoObserve}, {@link CascadeDispose} or {@link ComponentDependency}.</p>
019 *
020 * <p>If the element annotated is a method then the method must comply with the additional constraints:</p>
021 * <ul>
022 * <li>Must not be annotated with any other arez annotation except {@link Observable}</li>
023 * <li>If not annotated with {@link Observable} then must be final</li>
024 * <li>Must have 0 parameters</li>
025 * <li>
026 *   Must return a value that implements {@link DisposeNotifier} or is annotated with {@link ArezComponent}.
027 *   This will be checked at compile-time unless {@link #validateTypeAtRuntime()} set to <code>true</code>.
028 * </li>
029 * <li>Must not be private</li>
030 * <li>Must not be static</li>
031 * <li>If not annotated with {@link Observable} then must not be abstract</li>
032 * <li>Must not throw exceptions</li>
033 * <li>Must be accessible to the class annotated by the {@link ArezComponent} annotation.</li>
034 * </ul>
035 *
036 * <p>If the element annotated is a field then the field must comply with the additional constraints:</p>
037 * <ul>
038 * <li>Must be final</li>
039 * <li>Must be a type that implements {@link DisposeNotifier} or is annotated with {@link ArezComponent}</li>
040 * <li>Must not be private</li>
041 * <li>Must not be static</li>
042 * <li>Must be accessible to the class annotated by the {@link ArezComponent} annotation.</li>
043 * <li>Should not be public. A warning will be generated but can be suppressed by the {@link SuppressWarnings} or {@link SuppressArezWarnings} annotations with a key "Arez:PublicField".</li>
044 * <li>
045 *   Should not be protected if in the class annotated with the {@link ArezComponent} annotation as the field is not
046 *   expected to be accessed outside the component. A warning will be generated but can be suppressed by the
047 *   {@link SuppressWarnings} or {@link SuppressArezWarnings} annotations with a key "Arez:ProtectedField".
048 * </li>
049 * </ul>
050 *
051 * <p>This annotation is only supported on elements contained within a type annotated by
052 * {@link ArezComponent} or {@link ArezComponentLike}. Other usages will fail compilation.</p>
053 */
054@Documented
055@Target( { ElementType.METHOD, ElementType.FIELD } )
056public @interface ComponentDependency
057{
058  /**
059   * The action to take when dependency is disposed.
060   */
061  enum Action
062  {
063    /**
064     * Remove the component.
065     */
066    CASCADE,
067    /**
068     * Set the {@link Observable} property that holds dependency to null.
069     */
070    SET_NULL
071  }
072
073  /**
074   * Return the action to take when the dependency is disposed.
075   * A {@link Action#CASCADE} value indicates that the component should be deleted, while a
076   * {@link Action#SET_NULL} value indicates that the observable field should be set to null.
077   * The {@link Action#SET_NULL} is only valid on {@link Observable} properties that have an
078   * associated setter and are not annotated with {@link javax.annotation.Nonnull}.
079   *
080   * @return the action to take when the dependency is disposed.
081   */
082  @Nonnull
083  Action action() default Action.CASCADE;
084
085  /**
086   * Return true and the value of the annotated field will be validated at runtime rather than at compile time.
087   * This is useful when the field is defined by an interface but the underlying field is guaranteed to implement
088   * {@link DisposeNotifier} at runtime.
089   *
090   * @return true to defer validation of types until runtime.
091   */
092  boolean validateTypeAtRuntime() default false;
093}