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