001package sting;
002
003import java.lang.annotation.Documented;
004import java.lang.annotation.ElementType;
005import java.lang.annotation.Retention;
006import java.lang.annotation.RetentionPolicy;
007import java.lang.annotation.Target;
008import java.util.function.Supplier;
009import javax.annotation.Nonnull;
010
011/**
012 * Annotates an interface for which a dependency-injected implementation is to be generated.
013 * The implementation builds a component graph from the {@link #includes() included} types and
014 * exposes the services declared on the injector interface.
015 *
016 * <h2>Component Graph</h2>
017 *
018 * <p>The component graph is created in multiple phases.</p>
019 *
020 * <p>The first phase involves collecting all the types that are declared via the {@link #includes()}
021 * property and adding a binding (a.k.a. a potential component) for every {@link Injectable} annotated
022 * type and a binding for every method in {@link Fragment} annotated types. </p>
023 *
024 * <p>The second phase involves building a set of actual components created by the injector. Any potential
025 * binding that is annotated with the {@link Eager} annotation is added to the set of components. The
026 * {@link #inputs() inputs} are also modelled as eager components. The compiler then examines the services
027 * declared by the <a href="#service-methods">service methods</a> and attempts to resolve the services into
028 * components. When a component is added to the list of component, the service dependencies are added to the
029 * sert of services to resolve. When there is no services left to resolve, the injector is considered
030 * complete and the compiler terminates this phase.</p>
031 *
032 * <p>The next phase will identify the binding for each component will mark the component as eager and if the
033 * binding is annotated with the {@link Eager} annotation. All dependencies  of the component that are not
034 * {@link Supplier} dependencies are marked as eager. This process is recursively applied to dependencies of
035 * dependencies. At the end of this phase the components are all categorized into those that are eager and
036 * created when the injector is instantiated and components that are lazy and are created on demand.</p>
037 *
038 * <p>The final phase performs validation and correctness checking. It is during this phase that circular
039 * dependencies are detected and rejected and that injection requests for injection of singular values with
040 * multiple bindings that satisfy are detected.</p>
041 *
042 * <h2>Resolving Services</h2>
043 *
044 * <p>A service is resolved into a component by looking at the set of bindings present in the injector.
045 * If a binding exists that publishes the same type with the same qualifier then the binding is considered
046 * a match.</p>
047 *
048 * <p>If the binding is marked as optional (i.e. the component is created by a method annotated with
049 * {@link javax.annotation.Nullable} in a type annotated with the {@link Fragment} annotation) and the service
050 * is not optional then the compiler generates an error as it is not able to determine statically that the
051 * service will be available.</p>
052 *
053 * <p>If no matching binding is found then the compiler will attempt to look for a class annotated with
054 * {@link Injectable} that has the same name as the type of the service. If found and the type matches the service
055 * then the class will be added to the set of components created. If not found and the service is not optional then
056 * the compiler will generate an error.</p>
057 *
058 * <h2>Generated Classname</h2>
059 *
060 * <p>The generated class will have the name of the type annotated with the {@code @Injector} annotation
061 * prepended with {@code Sting_}. For example, the class {@code mybiz.MyInjector} will produce
062 * an implementation named {@code mybiz.Sting_MyInjector}. Nested classes are also supported but their names
063 * have the {@code $} sign replaced with a {@code _}. i.e. The nested class named {@code mybiz.MyOuterClass.MyInjector}
064 * will generate an implementation named {@code mybiz.MyOuterClass_Sting_MyInjector}</p>
065 *
066 * <a name="service-methods">Service methods</a>
067 * <h2>Service methods</h2>
068 *
069 * <p>Instance methods defined on the injector allow access to services contained within the injector and
070 * also define the root services that are used to build the component graph. The instance methods must be
071 * abstract, have zero parameters, throw no exceptions and return services. The methods can be annotated with
072 * {@link Named} to qualify the service and {@link javax.annotation.Nullable} to mark the service as optional.</p>
073 *
074 * <h2>Instantiation</h2>
075 *
076 * <p>A injector is created by invoking the constructor of the generated class. The generated class is package
077 * access so unless you are only using the injector from within the package it was created, you need to expose
078 * a method to create the injector. The usual pattern is to define a static method named {@code create} on the
079 * injector interface that creates an instance of the injector.</p>
080 *
081 * <p>Example:</p>
082 *
083 * <pre><code>
084 * {@literal @}Injector(includes = {BackendFragment.class, FrontendFragment.class})
085 * public interface MyInjector {
086 *
087 *   public static MyInjector create() {
088 *     return new Sting_MyInjector();
089 *   }
090 *
091 *   MyWidget myWidget();
092 * }
093 *
094 * public class Main {
095 *   public static void main(String[] args) {
096 *     MyInjector injector = MyInjector.create();
097 *     ... injector.myWidget() ...
098 *   }
099 * }</code></pre>
100 *
101 *
102 * <p>The {@link Injector} annotation use the {@link #inputs()} parameter that declares services that are
103 * passed into the injector. These services are made available to components within the component graph and
104 * maybe be qualified and/or marked as optional. Each input service is supplied to the injector as a constructor
105 * parameter in the generated class.</p>
106 *
107 * <p>Example of using input services:</p>
108 *
109 * <pre><code>
110 * {@literal @}Injector( includes = {BackendFragment.class, FrontendFragment.class},
111 *            inputs = { {@literal @}Injector.Input( type = MyService.class ),
112 *                       {@literal @}Injector.Input( qualifier = "hostname", type = String.class ) } )
113 * interface MyInjector {
114 *   MyWidget myWidget();
115 * }
116 *
117 * public class Main {
118 *   public static void main(String[] args) {
119 *     MyService service = ...;
120 *     MyInjector injector = new Sting_MyInjector(service, "mybiz.com");
121 *   }
122 * }</code></pre>
123 *
124 * <h3>Circular Dependencies</h3>
125 *
126 * <p>Circular dependencies within the injector are detected and rejected during the compilation phase.
127 * Circular dependencies can be broken by passing a {@link Supplier} dependency. i.e The developer injects
128 * the type {@link Supplier Supplier&lt;OtherType>} instead of {@code OtherType} and then calls {@link Supplier#get()}
129 * on the supplier when access to the service is needed.</p>
130 */
131@Documented
132@Retention( RetentionPolicy.RUNTIME )
133@Target( ElementType.TYPE )
134@StingProvider( "[FlatEnclosingName]Sting_[SimpleName]_Provider" )
135public @interface Injector
136{
137  /**
138   * A list of types that contribute to the object graph.
139   * These types can be {@code @Fragment}-annotated interfaces or {@link Injectable @Injectable}-annotated classes.
140   * The de-duplicated contributions of the {@code @Fragment}-annotated interfaces in the
141   * {@code includes}, and of their inclusions recursively, are all contributed
142   * to the object graph.
143   *
144   * <p>If the annotation processor detects a dependency that is required but not explicitly included in the
145   * includes list then it will attempt to automatically add the type to the graph if it is annotated with
146   * {@link Injectable @Injectable}. The current implementation include types
147   * if they were compiled in the same invocation of the java compiler. In the future the annotation processor
148   * will load the descriptors from the filesystem.</p>
149   *
150   * @return a list of types that contribute to the injectors object graph.
151   */
152  @Nonnull
153  Class<?>[] includes() default {};
154
155  /**
156   * A list of services that must be passed into the injector.
157   * The annotation processor will generate a constructor with one parameter for every input. Each input
158   * value MUST specify the type parameter otherwise the annotation processor is unable to determine the
159   * type of the binding.
160   *
161   * @return a list of services that must be passed into the injector.
162   */
163  @Nonnull
164  Input[] inputs() default {};
165
166  /**
167   * A flag controlling whether the injector implementation can be added to other injectors.
168   * If set to true then the injector can be included in another injector. The {@link #inputs()}
169   * are services that need to be provided while the service methods will define services that this
170   * injector provides.
171   *
172   * @return true to make the injector able to be included in another injector, false otherwise.
173   */
174  boolean injectable() default false;
175
176  /**
177   * A flag controlling whether the injector implementation will be optimized for compilation by GWT.
178   * This primarily involves the addition of the {@code @DoNotInline} annotation to lazy component accessors
179   * within the injector implementation to avoid inlining a component accessor and all transitive lazy component
180   * accessors that can increase code-size, compilation time and run time.
181   *
182   * <p>If set to {@link Feature#AUTODETECT} then the optimization for gwt will be enabled if the class
183   * {@code javaemul.internal.annotations.DoNotInline} is present on the classpath.</p>
184   *
185   * @return true to optimize the injector implementation for transpilation to javascript, false otherwise.
186   */
187  @Nonnull
188  Feature gwt() default Feature.AUTODETECT;
189
190  /**
191   * A specification of a service that is supplied to an injector during construction.
192   * The service is added to the the component graph and is made available for other components to consume
193   */
194  @Retention( RetentionPolicy.RUNTIME )
195  @Documented
196  @Target( {} )
197  @interface Input
198  {
199    /**
200     * An opaque string that qualifies the service.
201     * The string is user-supplied and used to distinguish two different services with the same {@link #type()}
202     * but different semantics.
203     *
204     * @return an opaque qualifier string.
205     */
206    @Nonnull
207    String qualifier() default "";
208
209    /**
210     * The java type of the service.
211     *
212     * <p>Sting does not support classes defined with type parameters.</p>
213     *
214     * @return the java type of the service.
215     */
216    Class<?> type();
217
218    /**
219     * A flag indicating whether the input is optional and may be null or required.
220     *
221     * @return a flag indicating whether the input is optional and may be null or required.
222     */
223    boolean optional() default false;
224  }
225}