23
23
import static com .squareup .javapoet .TypeSpec .classBuilder ;
24
24
import static dagger .internal .codegen .AnnotationSpecs .SUPPRESS_WARNINGS_RAWTYPES ;
25
25
import static dagger .internal .codegen .AnnotationSpecs .SUPPRESS_WARNINGS_UNCHECKED ;
26
+ import static dagger .internal .codegen .TypeNames .PROVIDER ;
26
27
import static dagger .internal .codegen .TypeNames .lazyOf ;
27
28
import static dagger .internal .codegen .TypeNames .optionalOf ;
28
29
import static dagger .internal .codegen .TypeNames .providerOf ;
34
35
import com .google .common .base .Optional ;
35
36
import com .squareup .javapoet .CodeBlock ;
36
37
import com .squareup .javapoet .FieldSpec ;
38
+ import com .squareup .javapoet .MethodSpec ;
37
39
import com .squareup .javapoet .ParameterSpec ;
38
40
import com .squareup .javapoet .ParameterizedTypeName ;
39
41
import com .squareup .javapoet .TypeName ;
40
42
import com .squareup .javapoet .TypeSpec ;
41
43
import com .squareup .javapoet .TypeVariableName ;
44
+ import dagger .internal .InstanceFactory ;
42
45
import dagger .internal .Preconditions ;
46
+ import java .util .EnumMap ;
47
+ import java .util .Map ;
43
48
import javax .inject .Provider ;
44
49
45
- /** Factory class specifications for optional bindings. */
50
+ /**
51
+ * The nested class and static methods required by the component to implement optional bindings.
52
+ */
46
53
// TODO(dpb): Name classes correctly if a component uses both Guava and JDK Optional.
47
- final class OptionalFactoryClasses {
54
+ final class OptionalFactories {
48
55
49
56
/**
50
- * The class specification for a {@link Provider<Optional<T>>} that always returns {@code
57
+ * A field specification for a {@link Provider<Optional<T>>} that always returns {@code
51
58
* Optional.absent()}.
52
59
*/
53
- static final TypeSpec ABSENT_FACTORY_CLASS = absentFactoryClass ();
60
+ private static final FieldSpec ABSENT_OPTIONAL_PROVIDER_FIELD =
61
+ FieldSpec .builder (PROVIDER , "ABSENT_OPTIONAL_PROVIDER" , PRIVATE , STATIC , FINAL )
62
+ .addAnnotation (SUPPRESS_WARNINGS_RAWTYPES )
63
+ .initializer ("$T.create($T.absent())" , InstanceFactory .class , Optional .class )
64
+ .addJavadoc (
65
+ "A {@link $T} that returns {@code $T.absent()}." , Provider .class , Optional .class )
66
+ .build ();
54
67
55
- private static TypeSpec absentFactoryClass () {
56
- String className = "AbsentOptionalFactory" ;
57
- TypeVariableName typeVariable = TypeVariableName .get ("T" );
58
-
59
- return classBuilder (className )
60
- .addTypeVariable (typeVariable )
61
- .addModifiers (PRIVATE , STATIC , FINAL )
62
- .addSuperinterface (providerOf (optionalOf (typeVariable )))
63
- .addJavadoc ("A {@link $T} that returns {$T.absent()}." , Provider .class , Optional .class )
64
- .addField (FieldSpec .builder (Provider .class , "INSTANCE" , PRIVATE , STATIC , FINAL )
65
- .addAnnotation (SUPPRESS_WARNINGS_RAWTYPES )
66
- .initializer ("new $L()" , className )
67
- .build ())
68
- .addMethod (
69
- methodBuilder ("instance" )
70
- .addModifiers (PRIVATE , STATIC )
71
- .addTypeVariable (typeVariable )
72
- .returns (providerOf (optionalOf (typeVariable )))
73
- .addCode ("$L // safe covariant cast\n " , SUPPRESS_WARNINGS_UNCHECKED )
74
- .addCode ("$1T provider = ($1T) INSTANCE;" , providerOf (optionalOf (typeVariable )))
75
- .addCode ("return provider;" )
76
- .build ())
77
- .addMethod (
78
- methodBuilder ("get" )
79
- .addAnnotation (Override .class )
80
- .addModifiers (PUBLIC )
81
- .returns (optionalOf (typeVariable ))
82
- .addCode ("return $T.absent();" , Optional .class )
83
- .build ())
84
- .build ();
68
+ /**
69
+ * A method specification for a {@link Provider<Optional<T>>} that always returns {@code
70
+ * Optional.absent()}.
71
+ */
72
+ private static final MethodSpec ABSENT_OPTIONAL_PROVIDER_METHOD =
73
+ methodBuilder ("absentOptionalProvider" )
74
+ .addModifiers (PRIVATE , STATIC )
75
+ .addTypeVariable (TypeVariableName .get ("T" ))
76
+ .returns (providerOf (optionalOf (TypeVariableName .get ("T" ))))
77
+ .addJavadoc (
78
+ "Returns a {@link $T} that returns {@code $T.absent()}." ,
79
+ Provider .class ,
80
+ Optional .class )
81
+ .addCode ("$L // safe covariant cast\n " , SUPPRESS_WARNINGS_UNCHECKED )
82
+ .addCode (
83
+ "$1T provider = ($1T) $2N;" ,
84
+ providerOf (optionalOf (TypeVariableName .get ("T" ))),
85
+ ABSENT_OPTIONAL_PROVIDER_FIELD )
86
+ .addCode ("return provider;" )
87
+ .build ();
88
+
89
+ /**
90
+ * The factory classes that implement present optional bindings for a given kind of dependency
91
+ * request within the component.
92
+ */
93
+ private final Map <DependencyRequest .Kind , TypeSpec > presentFactoryClasses =
94
+ new EnumMap <>(DependencyRequest .Kind .class );
95
+
96
+ /**
97
+ * If the component contains any absent optional bindings, this will be the member select for a
98
+ * static method that returns a Provider<Optional<T>> that always returns {@link
99
+ * Optional#absent()}.
100
+ */
101
+ private Optional <CodeBlock > absentOptionalProviderMethod = Optional .absent ();
102
+
103
+ /**
104
+ * Returns an expression that calls a static method that returns a {@code Provider<Optional<T>>}
105
+ * for absent optional bindings.
106
+ */
107
+ CodeBlock absentOptionalProvider () {
108
+ if (!absentOptionalProviderMethod .isPresent ()) {
109
+ absentOptionalProviderMethod =
110
+ Optional .of (CodeBlock .of ("$N()" , ABSENT_OPTIONAL_PROVIDER_METHOD ));
111
+ }
112
+ return absentOptionalProviderMethod .get ();
85
113
}
86
114
87
115
/**
88
- * Returns the class specification for a {@link Provider} that returns a present value. The class
89
- * is generic in {@code T}.
116
+ * Returns an expression for an instance of a nested class that implements {@code
117
+ * Provider<Optional<T>>} for a present optional binding, where {@code T} represents dependency
118
+ * requests of that kind.
90
119
*
91
120
* <ul>
92
121
* <li>If {@code optionalRequestKind} is {@link DependencyRequest.Kind#INSTANCE}, the class
@@ -100,23 +129,44 @@ private static TypeSpec absentFactoryClass() {
100
129
* </ul>
101
130
*
102
131
* <p>Production requests are not yet supported.
132
+ *
133
+ * @param delegateProvider an expression for a {@link Provider} of the underlying type
134
+ */
135
+ CodeBlock presentOptionalProvider (DependencyRequest .Kind valueKind , CodeBlock delegateProvider ) {
136
+ if (!presentFactoryClasses .containsKey (valueKind )) {
137
+ presentFactoryClasses .put (valueKind , createPresentFactoryClass (valueKind ));
138
+ }
139
+ return CodeBlock .of ("$N.of($L)" , presentFactoryClasses .get (valueKind ), delegateProvider );
140
+ }
141
+
142
+ /**
143
+ * Adds classes and methods required by previous calls to {@link #absentOptionalProvider()} and
144
+ * {@link #presentOptionalProvider(DependencyRequest.Kind, CodeBlock)} to the top-level {@code
145
+ * component}.
103
146
*/
104
- static TypeSpec presentFactoryClass (DependencyRequest .Kind optionalValueKind ) {
147
+ void addMembers (TypeSpec .Builder component ) {
148
+ if (absentOptionalProviderMethod .isPresent ()) {
149
+ component .addField (ABSENT_OPTIONAL_PROVIDER_FIELD ).addMethod (ABSENT_OPTIONAL_PROVIDER_METHOD );
150
+ }
151
+ for (TypeSpec presentFactoryClass : presentFactoryClasses .values ()) {
152
+ component .addType (presentFactoryClass );
153
+ }
154
+ }
155
+
156
+ private TypeSpec createPresentFactoryClass (DependencyRequest .Kind valueKind ) {
105
157
String factoryClassName =
106
158
String .format (
107
- "PresentOptional%sFactory" ,
108
- UPPER_UNDERSCORE .to (UPPER_CAMEL , optionalValueKind .toString ()));
109
-
159
+ "PresentOptional%sFactory" , UPPER_UNDERSCORE .to (UPPER_CAMEL , valueKind .toString ()));
160
+
110
161
TypeVariableName typeVariable = TypeVariableName .get ("T" );
111
-
162
+
112
163
FieldSpec providerField =
113
164
FieldSpec .builder (providerOf (typeVariable ), "provider" , PRIVATE , FINAL ).build ();
114
-
165
+
115
166
ParameterSpec providerParameter =
116
167
ParameterSpec .builder (providerOf (typeVariable ), "provider" ).build ();
117
-
118
- ParameterizedTypeName optionalType = optionalType (optionalValueKind , typeVariable );
119
-
168
+
169
+ ParameterizedTypeName optionalType = optionalType (valueKind , typeVariable );
120
170
return classBuilder (factoryClassName )
121
171
.addTypeVariable (typeVariable )
122
172
.addModifiers (PRIVATE , STATIC , FINAL )
@@ -144,7 +194,7 @@ static TypeSpec presentFactoryClass(DependencyRequest.Kind optionalValueKind) {
144
194
.addCode (
145
195
"return $T.of($L);" ,
146
196
Optional .class ,
147
- FrameworkType .PROVIDER .to (optionalValueKind , CodeBlock .of ("$N" , providerField )))
197
+ FrameworkType .PROVIDER .to (valueKind , CodeBlock .of ("$N" , providerField )))
148
198
.build ())
149
199
.addMethod (
150
200
methodBuilder ("of" )
@@ -157,7 +207,7 @@ static TypeSpec presentFactoryClass(DependencyRequest.Kind optionalValueKind) {
157
207
.build ();
158
208
}
159
209
160
- private static ParameterizedTypeName optionalType (
210
+ private ParameterizedTypeName optionalType (
161
211
DependencyRequest .Kind optionalValueKind , TypeName valueType ) {
162
212
switch (optionalValueKind ) {
163
213
case INSTANCE :
0 commit comments