1 /* 2 * Copyright (C) 2014 Google, Inc. 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 package dagger.internal.codegen; 17 18 import com.google.auto.common.MoreTypes; 19 import com.google.auto.value.AutoValue; 20 import com.google.common.base.Optional; 21 import com.google.common.collect.ImmutableList; 22 import com.google.common.collect.ImmutableSet; 23 import com.google.common.collect.Sets; 24 import com.google.common.util.concurrent.ListenableFuture; 25 import dagger.Provides; 26 import dagger.producers.Produces; 27 import java.util.Set; 28 import javax.lang.model.element.ExecutableElement; 29 import javax.lang.model.element.TypeElement; 30 import javax.lang.model.type.DeclaredType; 31 import javax.lang.model.type.ExecutableType; 32 import javax.lang.model.type.TypeKind; 33 import javax.lang.model.type.TypeMirror; 34 import javax.lang.model.util.Types; 35 36 import static com.google.common.base.Preconditions.checkArgument; 37 import static com.google.common.base.Preconditions.checkNotNull; 38 import static javax.lang.model.element.ElementKind.METHOD; 39 40 /** 41 * A value object representing the mechanism by which a {@link Key} can be produced. New instances 42 * should be created using an instance of the {@link Factory}. 43 * 44 * @author Jesse Beder 45 * @since 2.0 46 */ 47 @AutoValue 48 abstract class ProductionBinding extends ContributionBinding { 49 50 @Override bindingType()51 Binding.Type bindingType() { 52 return Binding.Type.PRODUCTION; 53 } 54 55 @Override provisionType()56 Provides.Type provisionType() { 57 return Provides.Type.valueOf(productionType().name()); 58 } 59 60 @Override implicitDependencies()61 Set<DependencyRequest> implicitDependencies() { 62 // Similar optimizations to ContributionBinding.implicitDependencies(). 63 if (!monitorRequest().isPresent()) { 64 return super.implicitDependencies(); 65 } else { 66 return Sets.union(monitorRequest().asSet(), super.implicitDependencies()); 67 } 68 } 69 70 /** Returns provision type that was used to bind the key. */ productionType()71 abstract Produces.Type productionType(); 72 73 /** Returns the list of types in the throws clause of the method. */ thrownTypes()74 abstract ImmutableList<? extends TypeMirror> thrownTypes(); 75 76 /** If this production requires a monitor, this will be the corresponding request. */ monitorRequest()77 abstract Optional<DependencyRequest> monitorRequest(); 78 79 @Override contributionType()80 ContributionType contributionType() { 81 switch (productionType()) { 82 case SET: 83 case SET_VALUES: 84 return ContributionType.SET; 85 case MAP: 86 return ContributionType.MAP; 87 case UNIQUE: 88 return ContributionType.UNIQUE; 89 default: 90 throw new AssertionError("Unknown production type: " + productionType()); 91 } 92 } 93 94 static final class Factory { 95 private final Types types; 96 private final Key.Factory keyFactory; 97 private final DependencyRequest.Factory dependencyRequestFactory; 98 Factory( Types types, Key.Factory keyFactory, DependencyRequest.Factory dependencyRequestFactory)99 Factory( 100 Types types, Key.Factory keyFactory, DependencyRequest.Factory dependencyRequestFactory) { 101 this.types = types; 102 this.keyFactory = keyFactory; 103 this.dependencyRequestFactory = dependencyRequestFactory; 104 } 105 forProducesMethod( ExecutableElement producesMethod, TypeMirror contributedBy)106 ProductionBinding forProducesMethod( 107 ExecutableElement producesMethod, TypeMirror contributedBy) { 108 checkNotNull(producesMethod); 109 checkArgument(producesMethod.getKind().equals(METHOD)); 110 checkArgument(contributedBy.getKind().equals(TypeKind.DECLARED)); 111 Produces producesAnnotation = producesMethod.getAnnotation(Produces.class); 112 checkArgument(producesAnnotation != null); 113 DeclaredType declaredContainer = MoreTypes.asDeclared(contributedBy); 114 ExecutableType resolvedMethod = 115 MoreTypes.asExecutable(types.asMemberOf(declaredContainer, producesMethod)); 116 Key key = keyFactory.forProducesMethod(resolvedMethod, producesMethod); 117 ImmutableSet<DependencyRequest> dependencies = 118 dependencyRequestFactory.forRequiredResolvedVariables( 119 declaredContainer, 120 producesMethod.getParameters(), 121 resolvedMethod.getParameterTypes()); 122 DependencyRequest monitorRequest = 123 dependencyRequestFactory.forProductionComponentMonitorProvider(); 124 Kind kind = MoreTypes.isTypeOf(ListenableFuture.class, producesMethod.getReturnType()) 125 ? Kind.FUTURE_PRODUCTION 126 : Kind.IMMEDIATE; 127 return new AutoValue_ProductionBinding( 128 key, 129 producesMethod, 130 dependencies, 131 findBindingPackage(key), 132 false, 133 ConfigurationAnnotations.getNullableType(producesMethod), 134 Optional.of(MoreTypes.asTypeElement(declaredContainer)), 135 Optional.<DependencyRequest>absent(), 136 kind, 137 producesAnnotation.type(), 138 ImmutableList.copyOf(producesMethod.getThrownTypes()), 139 Optional.of(monitorRequest)); 140 } 141 implicitMapOfProducerBinding(DependencyRequest mapOfValueRequest)142 ProductionBinding implicitMapOfProducerBinding(DependencyRequest mapOfValueRequest) { 143 checkNotNull(mapOfValueRequest); 144 Optional<Key> implicitMapOfProducerKey = 145 keyFactory.implicitMapProducerKeyFrom(mapOfValueRequest.key()); 146 checkArgument( 147 implicitMapOfProducerKey.isPresent(), "%s is not for a Map<K, V>", mapOfValueRequest); 148 DependencyRequest implicitMapOfProducerRequest = 149 dependencyRequestFactory.forImplicitMapBinding( 150 mapOfValueRequest, implicitMapOfProducerKey.get()); 151 return new AutoValue_ProductionBinding( 152 mapOfValueRequest.key(), 153 implicitMapOfProducerRequest.requestElement(), 154 ImmutableSet.of(implicitMapOfProducerRequest), 155 findBindingPackage(mapOfValueRequest.key()), 156 false, 157 Optional.<DeclaredType>absent(), 158 Optional.<TypeElement>absent(), 159 Optional.<DependencyRequest>absent(), 160 Kind.SYNTHETIC, 161 Produces.Type.MAP, 162 ImmutableList.<TypeMirror>of(), 163 Optional.<DependencyRequest>absent()); 164 } 165 forComponentMethod(ExecutableElement componentMethod)166 ProductionBinding forComponentMethod(ExecutableElement componentMethod) { 167 checkNotNull(componentMethod); 168 checkArgument(componentMethod.getKind().equals(METHOD)); 169 checkArgument(componentMethod.getParameters().isEmpty()); 170 checkArgument(MoreTypes.isTypeOf(ListenableFuture.class, componentMethod.getReturnType())); 171 return new AutoValue_ProductionBinding( 172 keyFactory.forProductionComponentMethod(componentMethod), 173 componentMethod, 174 ImmutableSet.<DependencyRequest>of(), 175 Optional.<String>absent(), 176 false, 177 Optional.<DeclaredType>absent(), 178 Optional.<TypeElement>absent(), 179 Optional.<DependencyRequest>absent(), 180 Kind.COMPONENT_PRODUCTION, 181 Produces.Type.UNIQUE, 182 ImmutableList.copyOf(componentMethod.getThrownTypes()), 183 Optional.<DependencyRequest>absent()); 184 } 185 } 186 } 187