0
# Utility Types
1
2
Dagger provides several utility types and interfaces that enhance the dependency injection experience, offering lazy evaluation, members injection, and other advanced features.
3
4
## Capabilities
5
6
### Lazy<T> Interface
7
8
Provides a handle to a lazily-computed value that is computed on the first call to get() and remembered for subsequent calls. Each Lazy<T> instance works independently.
9
10
```java { .api }
11
/**
12
* Handle to lazily-computed value - computes on first get(), remembers result
13
*/
14
interface Lazy<T> {
15
/**
16
* Returns the underlying value, computing it if necessary
17
* @return the lazily-computed value
18
*/
19
T get();
20
}
21
```
22
23
**Key Features:**
24
- Thread-safe: value computed at most once even with concurrent access
25
- Each Lazy<T> instance is independent (not singleton behavior)
26
- Different from @Singleton which shares the same instance across all clients
27
- Useful for expensive-to-create objects that may not be needed
28
29
**Usage Examples:**
30
31
```java
32
public class ExpensiveServiceClient {
33
private final Lazy<ExpensiveService> expensiveService;
34
private final RegularService regularService;
35
36
@Inject
37
public ExpensiveServiceClient(
38
Lazy<ExpensiveService> expensiveService,
39
RegularService regularService
40
) {
41
this.expensiveService = expensiveService;
42
this.regularService = regularService;
43
}
44
45
public void performOperation() {
46
// RegularService created immediately during injection
47
regularService.doSomething();
48
49
// ExpensiveService only created when first accessed
50
if (shouldUseExpensiveFeature()) {
51
expensiveService.get().performExpensiveOperation();
52
}
53
}
54
}
55
56
// Module providing lazy dependency
57
@Module
58
public class ServiceModule {
59
@Provides
60
@Singleton
61
ExpensiveService provideExpensiveService() {
62
// This won't be called until Lazy.get() is invoked
63
return new ExpensiveService();
64
}
65
}
66
```
67
68
### MembersInjector<T> Interface
69
70
Injects dependencies into the fields and methods of existing instances. Used when Dagger cannot create the object directly but needs to inject dependencies into it.
71
72
```java { .api }
73
/**
74
* Injects dependencies into fields and methods of instances
75
*/
76
interface MembersInjector<T> {
77
/**
78
* Injects dependencies into the given instance
79
* @param instance the instance to inject dependencies into
80
*/
81
void injectMembers(T instance);
82
}
83
```
84
85
**Key Features:**
86
- Injects @Inject-annotated fields and methods
87
- Does not perform constructor injection (object must already exist)
88
- Components automatically perform members injection after constructor injection
89
- Useful for framework integration where object creation is external
90
91
**Usage Examples:**
92
93
```java
94
// Class with members injection
95
public class ExternallyCreatedActivity {
96
@Inject UserService userService;
97
@Inject DatabaseService databaseService;
98
99
private String activityData;
100
101
// Constructor not managed by Dagger
102
public ExternallyCreatedActivity(String data) {
103
this.activityData = data;
104
}
105
106
@Inject
107
void init(ConfigService configService) {
108
// Method injection - called after field injection
109
configure(configService.getActivityConfig());
110
}
111
}
112
113
// Component with members injection
114
@Component(modules = ServiceModule.class)
115
public interface ActivityComponent {
116
// Members injection method
117
void inject(ExternallyCreatedActivity activity);
118
119
// Alternative: return injected instance
120
ExternallyCreatedActivity inject(ExternallyCreatedActivity activity);
121
122
// Direct MembersInjector access
123
MembersInjector<ExternallyCreatedActivity> activityInjector();
124
}
125
126
// Usage
127
public class ActivityManager {
128
private final ActivityComponent component;
129
130
@Inject
131
public ActivityManager(ActivityComponent component) {
132
this.component = component;
133
}
134
135
public void setupActivity(String data) {
136
// Create instance externally
137
ExternallyCreatedActivity activity = new ExternallyCreatedActivity(data);
138
139
// Inject dependencies
140
component.inject(activity);
141
142
// Alternative using MembersInjector directly
143
MembersInjector<ExternallyCreatedActivity> injector =
144
component.activityInjector();
145
injector.injectMembers(activity);
146
}
147
}
148
```
149
150
### Provider<T> Interface (JSR-330)
151
152
Standard JSR-330 interface for providing instances of a type. Every dependency in Dagger can be injected as Provider<T> to get new instances on each call.
153
154
```java { .api }
155
/**
156
* JSR-330 interface for providing instances of a type
157
*/
158
interface Provider<T> {
159
/**
160
* Provides an instance of type T
161
* @return an instance of T
162
*/
163
T get();
164
}
165
```
166
167
**Key Features:**
168
- Part of javax.inject standard
169
- get() may return different instances depending on scope
170
- Allows deferred/repeated instance creation
171
- Useful for factory patterns and optional dependencies
172
173
**Usage Examples:**
174
175
```java
176
public class UserController {
177
private final Provider<UserSession> sessionProvider;
178
private final UserService userService;
179
180
@Inject
181
public UserController(
182
Provider<UserSession> sessionProvider,
183
UserService userService
184
) {
185
this.sessionProvider = sessionProvider;
186
this.userService = userService;
187
}
188
189
public void handleRequest() {
190
// Get fresh session for each request
191
UserSession session = sessionProvider.get();
192
userService.processRequest(session);
193
}
194
}
195
196
// Scoped vs Unscoped behavior
197
@Module
198
public class SessionModule {
199
// Unscoped: Provider.get() returns new instance each time
200
@Provides
201
UserSession provideUserSession() {
202
return new UserSession();
203
}
204
205
// Scoped: Provider.get() returns same instance within scope
206
@Provides
207
@Singleton
208
UserPreferences provideUserPreferences() {
209
return new UserPreferences();
210
}
211
}
212
```
213
214
### Optional Injection
215
216
Dagger supports Optional<T> injection for dependencies that may or may not be present:
217
218
```java
219
public class FeatureService {
220
private final CoreService coreService;
221
private final Optional<AnalyticsService> analyticsService;
222
223
@Inject
224
public FeatureService(
225
CoreService coreService,
226
Optional<AnalyticsService> analyticsService
227
) {
228
this.coreService = coreService;
229
this.analyticsService = analyticsService;
230
}
231
232
public void performFeature() {
233
coreService.execute();
234
235
// Analytics may or may not be available
236
analyticsService.ifPresent(analytics ->
237
analytics.trackFeatureUsage("feature_performed"));
238
}
239
}
240
241
// Module declaring optional binding
242
@Module
243
public abstract class OptionalModule {
244
@BindsOptionalOf
245
abstract Optional<AnalyticsService> optionalAnalytics();
246
}
247
```
248
249
### Lazy Provider Combinations
250
251
Dagger supports combinations of lazy evaluation and provider patterns:
252
253
```java
254
public class ComplexDependencyClient {
255
private final Lazy<Provider<ExpensiveService>> lazyProvider;
256
private final Provider<Lazy<AnotherService>> providerLazy;
257
258
@Inject
259
public ComplexDependencyClient(
260
Lazy<Provider<ExpensiveService>> lazyProvider,
261
Provider<Lazy<AnotherService>> providerLazy
262
) {
263
this.lazyProvider = lazyProvider;
264
this.providerLazy = providerLazy;
265
}
266
267
public void complexOperation() {
268
// Lazy<Provider<T>>: Lazy evaluation of provider itself
269
Provider<ExpensiveService> provider = lazyProvider.get();
270
ExpensiveService service1 = provider.get();
271
ExpensiveService service2 = provider.get(); // May be different instance
272
273
// Provider<Lazy<T>>: Provider of lazy instances
274
Lazy<AnotherService> lazy1 = providerLazy.get();
275
Lazy<AnotherService> lazy2 = providerLazy.get(); // Different lazy instances
276
}
277
}
278
```
279
280
### Qualifier Integration
281
282
All utility types work with qualifiers:
283
284
```java
285
@Qualifier
286
@Retention(RetentionPolicy.RUNTIME)
287
public @interface Background {}
288
289
public class QualifiedUtilityExample {
290
@Inject
291
public QualifiedUtilityExample(
292
@Background Lazy<ExecutorService> backgroundExecutor,
293
@Background Provider<WorkerThread> backgroundWorkers,
294
@Background Optional<CacheService> backgroundCache
295
) {
296
// All utilities respect qualifiers
297
}
298
}
299
```
300
301
### Utility Types Best Practices
302
303
**Use Lazy for Expensive Objects:**
304
```java
305
// Good: Lazy evaluation for expensive creation
306
@Inject Lazy<DatabaseConnection> dbConnection;
307
308
// Avoid: Immediate creation if not always needed
309
@Inject DatabaseConnection dbConnection;
310
```
311
312
**Provider for Multiple Instances:**
313
```java
314
// Good: When you need fresh instances
315
@Inject Provider<UserSession> sessionProvider;
316
317
// Avoid: Provider when singleton behavior is desired
318
@Inject Provider<ApplicationConfig> configProvider; // Use direct injection
319
```
320
321
**MembersInjector for Framework Integration:**
322
```java
323
// Good: Framework objects Dagger can't create
324
public void onCreate(Bundle savedInstanceState) {
325
component.inject(this); // Android Activity
326
}
327
328
// Avoid: MembersInjector for regular objects
329
// Use constructor injection instead
330
```
331
332
**Optional for Truly Optional Dependencies:**
333
```java
334
// Good: Feature may not be available
335
@Inject Optional<AnalyticsService> analytics;
336
337
// Avoid: Required dependencies as Optional
338
@Inject Optional<DatabaseService> database; // Should be required
339
```