1 /* 2 * Copyright (C) 2015 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.cycle; 18 19 import dagger.Binds; 20 import dagger.Component; 21 import dagger.Lazy; 22 import dagger.Module; 23 import dagger.Provides; 24 import dagger.Subcomponent; 25 import dagger.multibindings.IntoMap; 26 import dagger.multibindings.StringKey; 27 import java.util.Map; 28 import javax.inject.Inject; 29 import javax.inject.Provider; 30 31 /** 32 * Cycle classes used for testing cyclic dependencies. 33 * 34 * <pre> 35 * {@literal A ← (E ← D ← B ← C ← Provider<A>, Lazy<A>), (B ← C ← Provider<A>, Lazy<A>)} 36 * {@literal S ← Provider<S>, Lazy<S>} 37 * </pre> 38 */ 39 final class Cycles { Cycles()40 private Cycles() {} 41 42 static class A { 43 public final B b; 44 public final E e; 45 46 @Inject A(E e, B b)47 A(E e, B b) { 48 this.e = e; 49 this.b = b; 50 } 51 } 52 53 static class B { 54 public final C c; 55 56 @Inject B(C c)57 B(C c) { 58 this.c = c; 59 } 60 } 61 62 static class C { 63 public final Provider<A> aProvider; 64 @Inject public Lazy<A> aLazy; 65 @Inject public Provider<Lazy<A>> aLazyProvider; 66 67 @Inject C(Provider<A> aProvider)68 C(Provider<A> aProvider) { 69 this.aProvider = aProvider; 70 } 71 } 72 73 static class D { 74 public final B b; 75 76 @Inject D(B b)77 D(B b) { 78 this.b = b; 79 } 80 } 81 82 static class E { 83 public final D d; 84 85 @Inject E(D d)86 E(D d) { 87 this.d = d; 88 } 89 } 90 91 static class S { 92 public final Provider<S> sProvider; 93 @Inject public Lazy<S> sLazy; 94 95 @Inject S(Provider<S> sProvider)96 S(Provider<S> sProvider) { 97 this.sProvider = sProvider; 98 } 99 } 100 101 static class X { 102 public final Y y; 103 104 @Inject X(Y y)105 X(Y y) { 106 this.y = y; 107 } 108 } 109 110 static class Y { 111 public final Map<String, Provider<X>> mapOfProvidersOfX; 112 public final Map<String, Provider<Y>> mapOfProvidersOfY; 113 114 @Inject Y(Map<String, Provider<X>> mapOfProvidersOfX, Map<String, Provider<Y>> mapOfProvidersOfY)115 Y(Map<String, Provider<X>> mapOfProvidersOfX, Map<String, Provider<Y>> mapOfProvidersOfY) { 116 this.mapOfProvidersOfX = mapOfProvidersOfX; 117 this.mapOfProvidersOfY = mapOfProvidersOfY; 118 } 119 } 120 121 @Module 122 abstract static class CycleMapModule { 123 @Binds 124 @IntoMap 125 @StringKey("X") x(X x)126 abstract X x(X x); 127 128 @Binds 129 @IntoMap 130 @StringKey("Y") y(Y y)131 abstract Y y(Y y); 132 } 133 134 @SuppressWarnings("dependency-cycle") 135 @Component(modules = CycleMapModule.class) 136 interface CycleMapComponent { y()137 Y y(); 138 } 139 140 @SuppressWarnings("dependency-cycle") 141 @Component(modules = CycleModule.class) 142 interface CycleComponent { a()143 A a(); 144 c()145 C c(); 146 child()147 ChildCycleComponent child(); 148 } 149 150 @Module 151 static class CycleModule { 152 @Provides provideObjectWithCycle(@uppressWarnings"unused") Provider<Object> object)153 static Object provideObjectWithCycle(@SuppressWarnings("unused") Provider<Object> object) { 154 return "object"; 155 } 156 } 157 158 @SuppressWarnings("dependency-cycle") 159 @Component 160 interface SelfCycleComponent { s()161 S s(); 162 } 163 164 @Subcomponent 165 interface ChildCycleComponent { 166 @SuppressWarnings("dependency-cycle") a()167 A a(); 168 169 @SuppressWarnings("dependency-cycle") object()170 Object object(); 171 } 172 173 interface Foo {} 174 175 static class Bar implements Foo { 176 @Inject Bar(Provider<Foo> fooProvider)177 Bar(Provider<Foo> fooProvider) {} 178 } 179 180 /** 181 * A component with a cycle in which a {@code @Binds} binding depends on the binding that has to 182 * be deferred. 183 */ 184 @Component(modules = BindsCycleModule.class) 185 interface BindsCycleComponent { bar()186 Bar bar(); 187 } 188 189 @Module 190 abstract static class BindsCycleModule { 191 @Binds foo(Bar bar)192 abstract Foo foo(Bar bar); 193 } 194 } 195