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