1 /* 2 * Copyright (C) 2016 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.common.base.CaseFormat.UPPER_CAMEL; 20 import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE; 21 import static dagger.model.RequestKind.INSTANCE; 22 23 import com.google.common.util.concurrent.Futures; 24 import com.google.common.util.concurrent.ListenableFuture; 25 import com.squareup.javapoet.ClassName; 26 import com.squareup.javapoet.CodeBlock; 27 import com.squareup.javapoet.ParameterizedTypeName; 28 import com.squareup.javapoet.TypeName; 29 import dagger.Lazy; 30 import dagger.internal.DoubleCheck; 31 import dagger.internal.ProviderOfLazy; 32 import dagger.internal.codegen.base.RequestKinds; 33 import dagger.internal.codegen.javapoet.Expression; 34 import dagger.internal.codegen.langmodel.DaggerTypes; 35 import dagger.model.DependencyRequest; 36 import dagger.model.RequestKind; 37 import dagger.producers.Produced; 38 import dagger.producers.Producer; 39 import dagger.producers.internal.Producers; 40 import java.util.Optional; 41 import javax.inject.Provider; 42 import javax.lang.model.type.TypeMirror; 43 44 /** One of the core types initialized as fields in a generated component. */ 45 public enum FrameworkType { 46 /** A {@link Provider}. */ 47 PROVIDER { 48 @Override frameworkClass()49 public Class<?> frameworkClass() { 50 return Provider.class; 51 } 52 53 @Override requestKind()54 public Optional<RequestKind> requestKind() { 55 return Optional.of(RequestKind.PROVIDER); 56 } 57 58 @Override to(RequestKind requestKind, CodeBlock from)59 public CodeBlock to(RequestKind requestKind, CodeBlock from) { 60 switch (requestKind) { 61 case INSTANCE: 62 return CodeBlock.of("$L.get()", from); 63 64 case LAZY: 65 return CodeBlock.of("$T.lazy($L)", DoubleCheck.class, from); 66 67 case PROVIDER: 68 return from; 69 70 case PROVIDER_OF_LAZY: 71 return CodeBlock.of("$T.create($L)", ProviderOfLazy.class, from); 72 73 case PRODUCER: 74 return CodeBlock.of("$T.producerFromProvider($L)", Producers.class, from); 75 76 case FUTURE: 77 return CodeBlock.of("$T.immediateFuture($L)", Futures.class, to(INSTANCE, from)); 78 79 case PRODUCED: 80 return CodeBlock.of("$T.successful($L)", Produced.class, to(INSTANCE, from)); 81 82 default: 83 throw new IllegalArgumentException( 84 String.format("Cannot request a %s from a %s", requestKind, this)); 85 } 86 } 87 88 @Override to(RequestKind requestKind, Expression from, DaggerTypes types)89 public Expression to(RequestKind requestKind, Expression from, DaggerTypes types) { 90 CodeBlock codeBlock = to(requestKind, from.codeBlock()); 91 switch (requestKind) { 92 case INSTANCE: 93 return Expression.create(types.unwrapTypeOrObject(from.type()), codeBlock); 94 95 case PROVIDER: 96 return from; 97 98 case PROVIDER_OF_LAZY: 99 TypeMirror lazyType = types.rewrapType(from.type(), Lazy.class); 100 return Expression.create(types.wrapType(lazyType, Provider.class), codeBlock); 101 102 case FUTURE: 103 return Expression.create( 104 types.rewrapType(from.type(), ListenableFuture.class), codeBlock); 105 106 default: 107 return Expression.create( 108 types.rewrapType(from.type(), RequestKinds.frameworkClass(requestKind)), codeBlock); 109 } 110 } 111 }, 112 113 /** A {@link Producer}. */ 114 PRODUCER_NODE { 115 @Override frameworkClass()116 public Class<?> frameworkClass() { 117 // TODO(cgdecker): Replace this with new class for representing internal producer nodes. 118 // Currently the new class is CancellableProducer, but it may be changed to ProducerNode and 119 // made to not implement Producer. 120 return Producer.class; 121 } 122 123 @Override requestKind()124 public Optional<RequestKind> requestKind() { 125 return Optional.empty(); 126 } 127 128 @Override to(RequestKind requestKind, CodeBlock from)129 public CodeBlock to(RequestKind requestKind, CodeBlock from) { 130 switch (requestKind) { 131 case FUTURE: 132 return CodeBlock.of("$L.get()", from); 133 134 case PRODUCER: 135 return from; 136 137 default: 138 throw new IllegalArgumentException( 139 String.format("Cannot request a %s from a %s", requestKind, this)); 140 } 141 } 142 143 @Override to(RequestKind requestKind, Expression from, DaggerTypes types)144 public Expression to(RequestKind requestKind, Expression from, DaggerTypes types) { 145 switch (requestKind) { 146 case FUTURE: 147 return Expression.create( 148 types.rewrapType(from.type(), ListenableFuture.class), 149 to(requestKind, from.codeBlock())); 150 151 case PRODUCER: 152 return Expression.create(from.type(), to(requestKind, from.codeBlock())); 153 154 default: 155 throw new IllegalArgumentException( 156 String.format("Cannot request a %s from a %s", requestKind, this)); 157 } 158 } 159 }, 160 ; 161 162 /** Returns the framework type appropriate for fields for a given binding type. */ forBindingType(BindingType bindingType)163 public static FrameworkType forBindingType(BindingType bindingType) { 164 switch (bindingType) { 165 case PROVISION: 166 return PROVIDER; 167 case PRODUCTION: 168 return PRODUCER_NODE; 169 case MEMBERS_INJECTION: 170 } 171 throw new AssertionError(bindingType); 172 } 173 174 /** Returns the framework type that exactly matches the given request kind, if one exists. */ forRequestKind(RequestKind requestKind)175 public static Optional<FrameworkType> forRequestKind(RequestKind requestKind) { 176 switch (requestKind) { 177 case PROVIDER: 178 return Optional.of(FrameworkType.PROVIDER); 179 default: 180 return Optional.empty(); 181 } 182 } 183 184 /** The class of fields of this type. */ frameworkClass()185 public abstract Class<?> frameworkClass(); 186 187 /** Returns the {@link #frameworkClass()} parameterized with a type. */ frameworkClassOf(TypeName valueType)188 public ParameterizedTypeName frameworkClassOf(TypeName valueType) { 189 return ParameterizedTypeName.get(ClassName.get(frameworkClass()), valueType); 190 } 191 192 /** The request kind that an instance of this framework type can satisfy directly, if any. */ requestKind()193 public abstract Optional<RequestKind> requestKind(); 194 195 /** 196 * Returns a {@link CodeBlock} that evaluates to a requested object given an expression that 197 * evaluates to an instance of this framework type. 198 * 199 * @param requestKind the kind of {@link DependencyRequest} that the returned expression can 200 * satisfy 201 * @param from a {@link CodeBlock} that evaluates to an instance of this framework type 202 * @throws IllegalArgumentException if a valid expression cannot be generated for {@code 203 * requestKind} 204 */ to(RequestKind requestKind, CodeBlock from)205 public abstract CodeBlock to(RequestKind requestKind, CodeBlock from); 206 207 /** 208 * Returns an {@link Expression} that evaluates to a requested object given an expression that 209 * evaluates to an instance of this framework type. 210 * 211 * @param requestKind the kind of {@link DependencyRequest} that the returned expression can 212 * satisfy 213 * @param from an expression that evaluates to an instance of this framework type 214 * @throws IllegalArgumentException if a valid expression cannot be generated for {@code 215 * requestKind} 216 */ to(RequestKind requestKind, Expression from, DaggerTypes types)217 public abstract Expression to(RequestKind requestKind, Expression from, DaggerTypes types); 218 219 @Override toString()220 public String toString() { 221 return UPPER_UNDERSCORE.to(UPPER_CAMEL, super.toString()); 222 } 223 } 224