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 }