1 /* 2 * Copyright (C) 2019 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.internal.codegen.binding; 18 19 import static com.google.auto.common.MoreElements.isAnnotationPresent; 20 import static com.google.common.base.Ascii.toUpperCase; 21 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 22 import static dagger.internal.codegen.extension.DaggerStreams.valuesOf; 23 import static java.util.stream.Collectors.mapping; 24 25 import com.google.common.collect.ImmutableSet; 26 import dagger.Component; 27 import dagger.Subcomponent; 28 import dagger.internal.codegen.base.ComponentAnnotation; 29 import dagger.producers.ProductionComponent; 30 import dagger.producers.ProductionSubcomponent; 31 import java.lang.annotation.Annotation; 32 import java.util.stream.Collector; 33 import java.util.stream.Stream; 34 import javax.lang.model.element.TypeElement; 35 36 /** Simple representation of a component creator annotation type. */ 37 public enum ComponentCreatorAnnotation { 38 COMPONENT_BUILDER(Component.Builder.class), 39 COMPONENT_FACTORY(Component.Factory.class), 40 SUBCOMPONENT_BUILDER(Subcomponent.Builder.class), 41 SUBCOMPONENT_FACTORY(Subcomponent.Factory.class), 42 PRODUCTION_COMPONENT_BUILDER(ProductionComponent.Builder.class), 43 PRODUCTION_COMPONENT_FACTORY(ProductionComponent.Factory.class), 44 PRODUCTION_SUBCOMPONENT_BUILDER(ProductionSubcomponent.Builder.class), 45 PRODUCTION_SUBCOMPONENT_FACTORY(ProductionSubcomponent.Factory.class), 46 ; 47 48 private final Class<? extends Annotation> annotation; 49 private final ComponentCreatorKind creatorKind; 50 private final Class<? extends Annotation> componentAnnotation; 51 52 @SuppressWarnings("unchecked") // Builder/factory annotations live within their parent annotation. ComponentCreatorAnnotation(Class<? extends Annotation> annotation)53 ComponentCreatorAnnotation(Class<? extends Annotation> annotation) { 54 this.annotation = annotation; 55 this.creatorKind = ComponentCreatorKind.valueOf(toUpperCase(annotation.getSimpleName())); 56 this.componentAnnotation = (Class<? extends Annotation>) annotation.getEnclosingClass(); 57 } 58 59 /** The actual annotation type. */ annotation()60 public Class<? extends Annotation> annotation() { 61 return annotation; 62 } 63 64 /** The component annotation type that encloses this creator annotation type. */ componentAnnotation()65 public final Class<? extends Annotation> componentAnnotation() { 66 return componentAnnotation; 67 } 68 69 /** Returns {@code true} if the creator annotation is for a subcomponent. */ isSubcomponentCreatorAnnotation()70 public final boolean isSubcomponentCreatorAnnotation() { 71 return componentAnnotation().getSimpleName().endsWith("Subcomponent"); 72 } 73 74 /** 75 * Returns {@code true} if the creator annotation is for a production component or subcomponent. 76 */ isProductionCreatorAnnotation()77 public final boolean isProductionCreatorAnnotation() { 78 return componentAnnotation().getSimpleName().startsWith("Production"); 79 } 80 81 /** The creator kind the annotation is associated with. */ 82 // TODO(dpb): Remove ComponentCreatorKind. creatorKind()83 public ComponentCreatorKind creatorKind() { 84 return creatorKind; 85 } 86 87 @Override toString()88 public final String toString() { 89 return annotation().getName(); 90 } 91 92 /** Returns all component creator annotations. */ allCreatorAnnotations()93 public static ImmutableSet<Class<? extends Annotation>> allCreatorAnnotations() { 94 return stream().collect(toAnnotationClasses()); 95 } 96 97 /** Returns all root component creator annotations. */ rootComponentCreatorAnnotations()98 public static ImmutableSet<Class<? extends Annotation>> rootComponentCreatorAnnotations() { 99 return stream() 100 .filter( 101 componentCreatorAnnotation -> 102 !componentCreatorAnnotation.isSubcomponentCreatorAnnotation()) 103 .collect(toAnnotationClasses()); 104 } 105 106 /** Returns all subcomponent creator annotations. */ subcomponentCreatorAnnotations()107 public static ImmutableSet<Class<? extends Annotation>> subcomponentCreatorAnnotations() { 108 return stream() 109 .filter( 110 componentCreatorAnnotation -> 111 componentCreatorAnnotation.isSubcomponentCreatorAnnotation()) 112 .collect(toAnnotationClasses()); 113 } 114 115 /** Returns all production component creator annotations. */ productionCreatorAnnotations()116 public static ImmutableSet<Class<? extends Annotation>> productionCreatorAnnotations() { 117 return stream() 118 .filter( 119 componentCreatorAnnotation -> 120 componentCreatorAnnotation.isProductionCreatorAnnotation()) 121 .collect(toAnnotationClasses()); 122 } 123 124 /** Returns the legal creator annotations for the given {@code componentAnnotation}. */ creatorAnnotationsFor( ComponentAnnotation componentAnnotation)125 public static ImmutableSet<Class<? extends Annotation>> creatorAnnotationsFor( 126 ComponentAnnotation componentAnnotation) { 127 return stream() 128 .filter( 129 creatorAnnotation -> 130 creatorAnnotation 131 .componentAnnotation() 132 .getSimpleName() 133 .equals(componentAnnotation.simpleName())) 134 .collect(toAnnotationClasses()); 135 } 136 137 /** Returns all creator annotations present on the given {@code type}. */ getCreatorAnnotations(TypeElement type)138 public static ImmutableSet<ComponentCreatorAnnotation> getCreatorAnnotations(TypeElement type) { 139 return stream() 140 .filter(cca -> isAnnotationPresent(type, cca.annotation())) 141 .collect(toImmutableSet()); 142 } 143 stream()144 private static Stream<ComponentCreatorAnnotation> stream() { 145 return valuesOf(ComponentCreatorAnnotation.class); 146 } 147 148 private static Collector<ComponentCreatorAnnotation, ?, ImmutableSet<Class<? extends Annotation>>> toAnnotationClasses()149 toAnnotationClasses() { 150 return mapping(ComponentCreatorAnnotation::annotation, toImmutableSet()); 151 } 152 } 153