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