1 /* 2 * Copyright (C) 2019 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.functional.producers.aot; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import com.google.common.util.concurrent.ListenableFuture; 22 import com.google.common.util.concurrent.MoreExecutors; 23 import dagger.BindsOptionalOf; 24 import dagger.Provides; 25 import dagger.multibindings.IntoSet; 26 import dagger.producers.ProducerModule; 27 import dagger.producers.Produces; 28 import dagger.producers.Production; 29 import dagger.producers.ProductionComponent; 30 import dagger.producers.ProductionSubcomponent; 31 import java.util.Optional; 32 import java.util.Set; 33 import java.util.concurrent.Executor; 34 import javax.inject.Inject; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 import org.junit.runners.JUnit4; 38 39 @RunWith(JUnit4.class) 40 public class ProducesMethodShadowsInjectConstructorTest { 41 static class Multibound {} 42 static class Maybe {} 43 44 static class HasInjectConstructor { HasInjectConstructor()45 @Inject HasInjectConstructor() {} 46 } 47 48 static class DependsOnShadowingProducer {} 49 50 @ProducerModule 51 abstract static class LeafModule { 52 @Produces dependsOnShadowingProducer( HasInjectConstructor hasInjectConstructor, Optional<Maybe> maybe)53 static DependsOnShadowingProducer dependsOnShadowingProducer( 54 // When viewed just within the leaf, this will resolve HasInjectConstructor to the @Inject 55 // constructor (and will receive a producerFromProvider), but when viewed within an ancestor 56 // that defines a @Produces method for HasInjectConstructor, the binding will be a regular 57 // Producer 58 HasInjectConstructor hasInjectConstructor, 59 Optional<Maybe> maybe) { 60 return new DependsOnShadowingProducer(); 61 } 62 63 @Provides 64 @IntoSet provisionContribution()65 static Multibound provisionContribution() { 66 return new Multibound(); 67 } 68 69 @BindsOptionalOf maybe()70 abstract Maybe maybe(); 71 } 72 73 @ProductionSubcomponent(modules = LeafModule.class) 74 interface Leaf { dependsOnShadowingProducer()75 ListenableFuture<DependsOnShadowingProducer> dependsOnShadowingProducer(); shadowedProvisionMultibinding()76 ListenableFuture<Set<Multibound>> shadowedProvisionMultibinding(); emptyProvisionBindingToPresentProductionBinding()77 ListenableFuture<Optional<Maybe>> emptyProvisionBindingToPresentProductionBinding(); 78 } 79 80 @ProducerModule 81 static class RootModule { 82 @Produces shadowInjectConstructor()83 static HasInjectConstructor shadowInjectConstructor() { 84 return new HasInjectConstructor(); 85 } 86 87 @Produces 88 @IntoSet productionContribution()89 static Multibound productionContribution() { 90 return new Multibound(); 91 } 92 93 @Provides 94 @Production executor()95 static Executor executor() { 96 return MoreExecutors.directExecutor(); 97 } 98 99 @Produces presentMaybeInParent()100 static Maybe presentMaybeInParent() { 101 return new Maybe(); 102 } 103 } 104 105 @ProductionComponent(modules = RootModule.class) 106 interface Root { leaf()107 Leaf leaf(); 108 } 109 110 @Test shadowedInjectConstructorDoesNotCauseClassCast()111 public void shadowedInjectConstructorDoesNotCauseClassCast() throws Exception { 112 Leaf leaf = DaggerProducesMethodShadowsInjectConstructorTest_Root.create().leaf(); 113 leaf.dependsOnShadowingProducer().get(); 114 assertThat(leaf.shadowedProvisionMultibinding().get()).hasSize(2); 115 assertThat(leaf.emptyProvisionBindingToPresentProductionBinding().get()).isPresent(); 116 } 117 } 118