View Javadoc
1   /*
2    * Copyright © 2017, Saleforce.com, Inc
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    *     * Redistributions of source code must retain the above copyright
8    *       notice, this list of conditions and the following disclaimer.
9    *     * Redistributions in binary form must reproduce the above copyright
10   *       notice, this list of conditions and the following disclaimer in the
11   *       documentation and/or other materials provided with the distribution.
12   *     * Neither the name of the <organization> nor the
13   *       names of its contributors may be used to endorse or promote products
14   *       derived from this software without specific prior written permission.
15   *
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19   * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   */
27  package com.salesforce.aptspring;
28  
29  import java.lang.annotation.ElementType;
30  import java.lang.annotation.Retention;
31  import java.lang.annotation.RetentionPolicy;
32  import java.lang.annotation.Target;
33  
34  /**
35   * This marker annotation may only be used on Spring @Bean LITE and @Component classes.
36   * Combined with the AptSpringProcessor annotation processor to prevent errors from creeping in to your spring graph!
37   * <p>
38   * The APT parser will generate errors if any of the following restrictions are violated:
39   * </p>
40   * <p>
41   * Restrictions on @Bean Lite mode class definitions are:
42   * </p>
43   * <ul>
44   *  <li>All methods on the class are @Bean methods.</li>
45   *  <li>The class has a public no-parameter constructor.</li>
46   *  <li>The class must be the top level class in a the java file.</li>
47   *  <li>No uses of @ComponentScan on the classes, instead use @Import</li>
48   *  <li>All fields on the class must be {@code "private static final 'Type' 'name' = 'LITERAL_VALUE'";}</li>
49   *  <li>The class must not be annotated with @Component or @Configuration</li>
50   * </ul>
51   * <p>
52   * Bean Methods signatures have the following restrictions:
53   * </p>
54   * <ul>
55   *  <li>@Bean annotations define at least one name for the bean.</li>
56   *  <li>@Bean methods return an object (not void, not un-boxed values)</li>
57   *  <li>@Bean methods are public</li>
58   *  <li>@Bean methods are not static, final, native, or abstract (support may be added for BeanFactoryPostProcessors)</li>
59   *  <li>@Bean method parameters must have a @Qualifier of the bean name they expect as input or an @Value 
60   *  of the property they expect spring to inject (system property or other configuration).</li>
61   * </ul>
62   * <p>
63   * With the above restrictions in place, the following checks become feasible, and also occur at compile time:
64   * </p>
65   * <ul>
66   *  <li>Cycles in @Import class</li>
67   *  <li>Cycles in @Bean or @Component dependency definitions</li>
68   *  <li>Duplicate names in the directed acyclic graph of @Bean or @Component defined instances</li>
69   *  <li>Detect missing beans by their name reference</li>
70   *  <li>Allow classes to declare beans they expect (these are the only missing beans a graph may have),
71   *   see {@link Verified#expectedBeans()}</li>
72   *  <li>Detect when one of those expected beans is not used in the graph and flag it as an error.</li>
73   *  <li>Detect missing classes from an @Import</li>
74   *  <li>only @Verified classes may be @Imported in to a @Verified class</li>
75   *  <li>Detect when the declared output type of an @Bean method does not satisfy the type expected by
76   *   uses of bean's qualified name in an injection point.</li>
77   *  <li>Ensure expected beans passed in types are of compatible types.</li>
78   * </ul>
79   * <p>
80   * Restrictions on the use of @Value annotations.
81   * </p>
82   * <ul>
83   *   <li>@Value may only be used on @Bean method parameters or @Component constructors.</li>  
84   *   <li>@Value parameters and @Qualifier parameters may not be mixed on the same @Bean method or @Component constructor</li>
85   *   <li>It is highly encouraged that @Bean methods or @Component constructors with @Value parameters only have one parameters (more are allowed)</li>
86   *   <li>@Value annotations may only be used on classes that are marked as {@link Verified#root()} = true</li>
87   *   <li>No class may mark a {@link Verified#root()} = true class as an @Import</li>
88   *   <li>Instead @Import files should use {@link Verified#expectedBeans()} to expect beans that will be required
89   *   at runtime that will contain the properties they need to run</li>
90   *   <li>This is to encourage re-usable, testable @Bean lite classes, and to consolidate where all system properties are read
91   *   in to one location, namely the {@link Verified#root()} = true class</li>
92   * </ul>
93   * <p>
94   * Restrictions on @Component classes:
95   * </p>
96   * <ul>
97   *   <li>May only have one constructor, or one constructor marked @Autowired if it has multiple constructors.</li>
98   *   <li>All fields must be private static final literals, of private final variables set during instance construction.</li>  
99   * </ul>  
100  * <p>
101  * MetaAnnotations are supported.  @AliasFor will work as expected.
102  * </p>
103  * <p>
104  * Future checks to be added to the project will include but are not limited to:
105  * </p>
106  * <ul>
107  *   <li>No usage of banned classes {classes that contain static references to the Spring Context or system properties}</li>
108  *   <li>don't call any methods on the injected dependencies to a bean method in the bean method or object constructor, this
109  *   violates the https://en.wikipedia.org/wiki/Law_of_Demeter and makes code more coupled and error prone, instead only inject what you
110  *   need at runtime.</li>
111  * </ul>
112  * <p>
113  * Work I'd like to finish soon but likely wont have time:
114  * </p>
115  * <ul>
116  *  <li>Prune unneeded data from the persisted storage of @Bean lite classes data allowing for faster cycle detect.</li>
117  * </ul>
118  * <p>
119  * The processing is incremental, meaning that a file is generated to a target directory and read when available.
120  * This allows for decent performance on large graphs touching hundreds of files by preventing duplicate work.  SHA-256 digests
121  * are used to make sure no one gets clever and tries to swap out a jar underneath the working application.
122  * </p>
123  */
124 @Retention(RetentionPolicy.RUNTIME)
125 @Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE })
126 public @interface Verified {
127   
128   /**
129    * List of beans that are expected to be provided by an external Configuration that imports the Configuration class annotated with
130    * the list of expected beans.
131    * @return the list of expected beans.
132    */
133   String[] expectedBeans() default {};
134   
135   /**
136    * Only @Configuration files that are marked as "root" nodes may have @Value annotations used in their @Configuration. 
137    * Root @Configuration nodes may not be imported by other @Configuration nodes.
138    * @return whether or not this is a root @Configuration bean.
139    */
140   boolean root() default false;
141 }