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}