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 ComponentDependency} or {@link CascadeDispose}.</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 * </ul>
044 */
045@Documented
046@Target( { ElementType.METHOD, ElementType.FIELD } )
047public @interface ComponentDependency
048{
049  /**
050   * The action to take when dependency is disposed.
051   */
052  enum Action
053  {
054    /**
055     * Remove the component.
056     */
057    CASCADE,
058    /**
059     * Set the {@link Observable} property that holds dependency to null.
060     */
061    SET_NULL
062  }
063
064  /**
065   * Return the action to take when the dependency is disposed.
066   * A {@link Action#CASCADE} value indicates that the component should be deleted, while a
067   * {@link Action#SET_NULL} value indicates that the observable field should be set to null.
068   * The {@link Action#SET_NULL} is only valid on {@link Observable} properties that have an
069   * associated setter and are not annotated with {@link javax.annotation.Nonnull}.
070   *
071   * @return the action to take when the dependency is disposed.
072   */
073  @Nonnull
074  Action action() default Action.CASCADE;
075
076  /**
077   * Return true and the value of the annotated field will be validated at runtime rather than at compile time.
078   * This is useful when the field is defined by an interface but the underlying field is guaranteed to implement
079   * {@link DisposeNotifier} at runtime.
080   *
081   * @return true to defer validation of types until runtime.
082   */
083  boolean validateTypeAtRuntime() default false;
084}