1 /* 2 * Copyright (C) 2017 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.writing; 18 19 import static com.google.common.collect.Iterables.getOnlyElement; 20 import static dagger.internal.codegen.binding.BindingRequest.bindingRequest; 21 import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom; 22 import static dagger.internal.codegen.xprocessing.XProcessingEnvs.isPreJava8SourceVersion; 23 24 import androidx.room.compiler.processing.XProcessingEnv; 25 import com.squareup.javapoet.ClassName; 26 import com.squareup.javapoet.CodeBlock; 27 import com.squareup.javapoet.TypeName; 28 import dagger.assisted.Assisted; 29 import dagger.assisted.AssistedFactory; 30 import dagger.assisted.AssistedInject; 31 import dagger.internal.codegen.base.OptionalType; 32 import dagger.internal.codegen.base.OptionalType.OptionalKind; 33 import dagger.internal.codegen.binding.ProvisionBinding; 34 import dagger.internal.codegen.javapoet.Expression; 35 import dagger.internal.codegen.model.DependencyRequest; 36 import dagger.internal.codegen.model.RequestKind; 37 38 /** A binding expression for optional bindings. */ 39 final class OptionalRequestRepresentation extends RequestRepresentation { 40 private final ProvisionBinding binding; 41 private final ComponentRequestRepresentations componentRequestRepresentations; 42 private final XProcessingEnv processingEnv; 43 44 @AssistedInject OptionalRequestRepresentation( @ssisted ProvisionBinding binding, ComponentImplementation componentImplementation, ComponentRequestRepresentations componentRequestRepresentations, XProcessingEnv processingEnv)45 OptionalRequestRepresentation( 46 @Assisted ProvisionBinding binding, 47 ComponentImplementation componentImplementation, 48 ComponentRequestRepresentations componentRequestRepresentations, 49 XProcessingEnv processingEnv) { 50 this.binding = binding; 51 this.componentRequestRepresentations = componentRequestRepresentations; 52 this.processingEnv = processingEnv; 53 } 54 55 @Override getDependencyExpression(ClassName requestingClass)56 Expression getDependencyExpression(ClassName requestingClass) { 57 OptionalType optionalType = OptionalType.from(binding.key()); 58 OptionalKind optionalKind = optionalType.kind(); 59 if (binding.dependencies().isEmpty()) { 60 if (isPreJava8SourceVersion(processingEnv)) { 61 // When compiling with -source 7, javac's type inference isn't strong enough to detect 62 // Futures.immediateFuture(Optional.absent()) for keys that aren't Object. It also has 63 // issues 64 // when used as an argument to some members injection proxy methods (see 65 // https://github.com/google/dagger/issues/916) 66 if (isTypeAccessibleFrom( 67 binding.key().type().xprocessing(), requestingClass.packageName())) { 68 return Expression.create( 69 binding.key().type().xprocessing(), 70 optionalKind.parameterizedAbsentValueExpression(optionalType)); 71 } 72 } 73 return Expression.create( 74 binding.key().type().xprocessing(), optionalKind.absentValueExpression()); 75 } 76 DependencyRequest dependency = getOnlyElement(binding.dependencies()); 77 78 CodeBlock dependencyExpression = 79 componentRequestRepresentations 80 .getDependencyExpression(bindingRequest(dependency), requestingClass) 81 .codeBlock(); 82 83 boolean needsObjectExpression = !isTypeAccessibleFrom( 84 dependency.key().type().xprocessing(), requestingClass.packageName()) 85 || (isPreJava8SourceVersion(processingEnv) && dependency.kind() == RequestKind.PROVIDER); 86 87 return !needsObjectExpression 88 ? Expression.create( 89 binding.key().type().xprocessing(), 90 optionalKind.presentExpression(dependencyExpression)) 91 // If the dependency type is inaccessible, then we have to use Optional.<Object>of(...), or 92 // else we will get "incompatible types: inference variable has incompatible bounds. 93 : Expression.create( 94 processingEnv.getDeclaredType( 95 processingEnv.findTypeElement(optionalKind.className()), 96 processingEnv.findType(TypeName.OBJECT)), 97 optionalKind.presentObjectExpression(dependencyExpression)); 98 } 99 100 @AssistedFactory 101 static interface Factory { create(ProvisionBinding binding)102 OptionalRequestRepresentation create(ProvisionBinding binding); 103 } 104 } 105