1 /* 2 * Copyright (C) 2018 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; 18 19 import static dagger.internal.codegen.RequestKinds.requestType; 20 21 import com.google.auto.value.AutoValue; 22 import dagger.internal.codegen.langmodel.DaggerTypes; 23 import dagger.internal.codegen.serialization.BindingRequestProto; 24 import dagger.internal.codegen.serialization.FrameworkTypeWrapper; 25 import dagger.internal.codegen.serialization.RequestKindWrapper; 26 import dagger.model.DependencyRequest; 27 import dagger.model.Key; 28 import dagger.model.RequestKind; 29 import java.util.Optional; 30 import javax.lang.model.type.TypeMirror; 31 32 /** 33 * A request for a binding, which may be in the form of a request for a dependency to pass to a 34 * constructor or module method ({@link RequestKind}) or an internal request for a framework 35 * instance ({@link FrameworkType}). 36 */ 37 @AutoValue 38 abstract class BindingRequest { 39 /** Creates a {@link BindingRequest} for the given {@link DependencyRequest}. */ bindingRequest(DependencyRequest dependencyRequest)40 static BindingRequest bindingRequest(DependencyRequest dependencyRequest) { 41 return bindingRequest(dependencyRequest.key(), dependencyRequest.kind()); 42 } 43 44 /** 45 * Creates a {@link BindingRequest} for a normal dependency request for the given {@link Key} and 46 * {@link RequestKind}. 47 */ bindingRequest(Key key, RequestKind requestKind)48 static BindingRequest bindingRequest(Key key, RequestKind requestKind) { 49 // When there's a request that has a 1:1 mapping to a FrameworkType, the request should be 50 // associated with that FrameworkType as well, because we want to ensure that if a request 51 // comes in for that as a dependency first and as a framework instance later, they resolve to 52 // the same binding expression. 53 // TODO(cgdecker): Instead of doing this, make ComponentBindingExpressions create a 54 // BindingExpression for the RequestKind that simply delegates to the BindingExpression for the 55 // FrameworkType. Then there are separate BindingExpressions, but we don't end up doing weird 56 // things like creating two fields when there should only be one. 57 return new AutoValue_BindingRequest( 58 key, Optional.of(requestKind), FrameworkType.forRequestKind(requestKind)); 59 } 60 61 /** 62 * Creates a {@link BindingRequest} for a request for a framework instance for the given {@link 63 * Key} with the given {@link FrameworkType}. 64 */ bindingRequest(Key key, FrameworkType frameworkType)65 static BindingRequest bindingRequest(Key key, FrameworkType frameworkType) { 66 return new AutoValue_BindingRequest( 67 key, frameworkType.requestKind(), Optional.of(frameworkType)); 68 } 69 70 /** Creates a {@link BindingRequest} for the given {@link FrameworkDependency}. */ bindingRequest(FrameworkDependency frameworkDependency)71 static BindingRequest bindingRequest(FrameworkDependency frameworkDependency) { 72 return bindingRequest(frameworkDependency.key(), frameworkDependency.frameworkType()); 73 } 74 75 /** Returns the {@link Key} for the requested binding. */ key()76 abstract Key key(); 77 78 /** Returns the request kind associated with this request, if any. */ requestKind()79 abstract Optional<RequestKind> requestKind(); 80 81 /** Returns the framework type associated with this request, if any. */ frameworkType()82 abstract Optional<FrameworkType> frameworkType(); 83 84 /** Returns whether this request is of the given kind. */ isRequestKind(RequestKind requestKind)85 final boolean isRequestKind(RequestKind requestKind) { 86 return requestKind.equals(requestKind().orElse(null)); 87 } 88 requestedType(TypeMirror contributedType, DaggerTypes types)89 final TypeMirror requestedType(TypeMirror contributedType, DaggerTypes types) { 90 if (requestKind().isPresent()) { 91 return requestType(requestKind().get(), contributedType, types); 92 } 93 return types.wrapType(contributedType, frameworkType().get().frameworkClass()); 94 } 95 96 /** Returns a name that can be used for the kind of request this is. */ kindName()97 final String kindName() { 98 Object requestKindObject = 99 requestKind().isPresent() 100 ? requestKind().get() 101 : frameworkType().get().frameworkClass().getSimpleName(); 102 return requestKindObject.toString(); 103 } 104 105 /** Returns {@code true} if this request can be satisfied by a production binding. */ canBeSatisfiedByProductionBinding()106 final boolean canBeSatisfiedByProductionBinding() { 107 if (requestKind().isPresent()) { 108 return RequestKinds.canBeSatisfiedByProductionBinding(requestKind().get()); 109 } 110 return frameworkType().get().equals(FrameworkType.PRODUCER_NODE); 111 } 112 113 /** Creates a proto representation of this binding request. */ toProto()114 BindingRequestProto toProto() { 115 BindingRequestProto.Builder builder = 116 BindingRequestProto.newBuilder().setKey(KeyFactory.toProto(key())); 117 if (frameworkType().isPresent()) { 118 builder.setFrameworkType( 119 FrameworkTypeWrapper.FrameworkType.valueOf(frameworkType().get().name())); 120 } else { 121 builder.setRequestKind(RequestKindWrapper.RequestKind.valueOf(requestKind().get().name())); 122 } 123 return builder.build(); 124 } 125 } 126