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 }