0
# Assisted Injection
1
2
Assisted injection in Dagger enables the creation of objects that require both injected dependencies and runtime parameters. This pattern uses factory interfaces to create instances where some parameters are provided by Dagger's dependency injection and others are passed at runtime.
3
4
## Capabilities
5
6
### @AssistedInject Annotation
7
8
Annotates constructors that require assisted injection, mixing dependencies injected by Dagger with parameters provided at runtime.
9
10
```java { .api }
11
/**
12
* Annotates constructors for assisted injection (runtime parameter passing)
13
*/
14
@Target(ElementType.CONSTRUCTOR)
15
@Retention(RetentionPolicy.RUNTIME)
16
@interface AssistedInject {}
17
```
18
19
**Key Features:**
20
- Cannot be used with scoping annotations (not scoped)
21
- Requires a corresponding @AssistedFactory
22
- Some parameters are injected by Dagger, others marked with @Assisted
23
- Only one constructor per class can have @AssistedInject
24
25
**Usage Examples:**
26
27
```java
28
public class UserSession {
29
private final UserService userService; // Injected by Dagger
30
private final User user; // Passed at runtime
31
private final String sessionId; // Passed at runtime
32
33
@AssistedInject
34
public UserSession(
35
UserService userService, // Dagger-provided
36
@Assisted User user, // Runtime parameter
37
@Assisted String sessionId // Runtime parameter
38
) {
39
this.userService = userService;
40
this.user = user;
41
this.sessionId = sessionId;
42
}
43
}
44
```
45
46
### @AssistedFactory Annotation
47
48
Annotates factory interfaces or abstract classes that create instances with assisted injection. The factory provides a clean API for creating objects with mixed parameter sources.
49
50
```java { .api }
51
/**
52
* Annotates factory interfaces/abstract classes for creating assisted injection types
53
*/
54
@Target(ElementType.TYPE)
55
@Retention(RetentionPolicy.RUNTIME)
56
@interface AssistedFactory {}
57
```
58
59
**Requirements:**
60
- Must be abstract class or interface
61
- Exactly one abstract method
62
- Return type must match the assisted injection type
63
- Method parameters must match @Assisted parameters in constructor
64
65
**Usage Examples:**
66
67
```java
68
@AssistedFactory
69
public interface UserSessionFactory {
70
UserSession create(User user, String sessionId);
71
}
72
73
// Usage
74
public class LoginService {
75
private final UserSessionFactory sessionFactory;
76
77
@Inject
78
public LoginService(UserSessionFactory sessionFactory) {
79
this.sessionFactory = sessionFactory;
80
}
81
82
public UserSession login(String username, String password) {
83
User user = authenticateUser(username, password);
84
String sessionId = generateSessionId();
85
return sessionFactory.create(user, sessionId);
86
}
87
}
88
```
89
90
### @Assisted Annotation
91
92
Annotates constructor parameters that are passed at runtime rather than injected by Dagger. Each @Assisted parameter must have a corresponding parameter in the factory method.
93
94
```java { .api }
95
/**
96
* Annotates constructor parameters that are passed at runtime (not injected)
97
*/
98
@Target(ElementType.PARAMETER)
99
@Retention(RetentionPolicy.RUNTIME)
100
@interface Assisted {
101
/**
102
* Identifier for distinguishing parameters of the same type
103
*/
104
String value() default "";
105
}
106
```
107
108
**Key Features:**
109
- Each @Assisted parameter uniquely identified by identifier + type
110
- Factory method parameters must match constructor @Assisted parameters
111
- Parameters without @Assisted are provided by Dagger
112
- Identifier helps distinguish multiple parameters of the same type
113
114
**Usage Examples:**
115
116
```java
117
public class DatabaseConnection {
118
private final ConnectionPool pool; // Injected
119
private final String host; // Runtime parameter
120
private final int port; // Runtime parameter
121
private final String database; // Runtime parameter
122
123
@AssistedInject
124
public DatabaseConnection(
125
ConnectionPool pool,
126
@Assisted String host,
127
@Assisted int port,
128
@Assisted String database
129
) {
130
this.pool = pool;
131
this.host = host;
132
this.port = port;
133
this.database = database;
134
}
135
}
136
137
@AssistedFactory
138
public interface DatabaseConnectionFactory {
139
DatabaseConnection create(String host, int port, String database);
140
}
141
```
142
143
### Assisted Parameters with Identifiers
144
145
When multiple parameters have the same type, use identifiers to distinguish them:
146
147
```java
148
public class Rectangle {
149
private final Graphics graphics; // Injected
150
private final int width; // Runtime parameter
151
private final int height; // Runtime parameter
152
153
@AssistedInject
154
public Rectangle(
155
Graphics graphics,
156
@Assisted("width") int width,
157
@Assisted("height") int height
158
) {
159
this.graphics = graphics;
160
this.width = width;
161
this.height = height;
162
}
163
}
164
165
@AssistedFactory
166
public interface RectangleFactory {
167
// Parameters must match identifiers and types
168
Rectangle create(@Assisted("width") int width, @Assisted("height") int height);
169
}
170
```
171
172
### Generic Assisted Injection
173
174
Assisted injection works with generic types:
175
176
```java
177
public class Repository<T> {
178
private final DatabaseService databaseService; // Injected
179
private final Class<T> entityClass; // Runtime parameter
180
private final String tableName; // Runtime parameter
181
182
@AssistedInject
183
public Repository(
184
DatabaseService databaseService,
185
@Assisted Class<T> entityClass,
186
@Assisted String tableName
187
) {
188
this.databaseService = databaseService;
189
this.entityClass = entityClass;
190
this.tableName = tableName;
191
}
192
}
193
194
@AssistedFactory
195
public interface RepositoryFactory {
196
<T> Repository<T> create(Class<T> entityClass, String tableName);
197
}
198
199
// Usage
200
public class UserService {
201
private final Repository<User> userRepository;
202
203
@Inject
204
public UserService(RepositoryFactory repositoryFactory) {
205
this.userRepository = repositoryFactory.create(User.class, "users");
206
}
207
}
208
```
209
210
### Complex Assisted Injection Patterns
211
212
**Multiple Factories:**
213
```java
214
public class ReportGenerator {
215
@AssistedInject
216
public ReportGenerator(
217
ReportService reportService,
218
@Assisted ReportType type,
219
@Assisted DateRange dateRange,
220
@Assisted("format") String format
221
) { /* ... */ }
222
}
223
224
// Different factories for different use cases
225
@AssistedFactory
226
public interface DailyReportFactory {
227
ReportGenerator create(
228
ReportType type,
229
@Assisted("format") String format
230
);
231
}
232
233
@AssistedFactory
234
public interface CustomReportFactory {
235
ReportGenerator create(
236
ReportType type,
237
DateRange dateRange,
238
@Assisted("format") String format
239
);
240
}
241
```
242
243
**Factory with Nullable Parameters:**
244
```java
245
public class EmailSender {
246
@AssistedInject
247
public EmailSender(
248
EmailService emailService,
249
@Assisted String recipient,
250
@Assisted @Nullable String cc,
251
@Assisted @Nullable String bcc
252
) { /* ... */ }
253
}
254
255
@AssistedFactory
256
public interface EmailSenderFactory {
257
EmailSender create(
258
String recipient,
259
@Nullable String cc,
260
@Nullable String bcc
261
);
262
}
263
```
264
265
### Integration with Components
266
267
Assisted factories must be explicitly bound in components:
268
269
```java
270
@Module
271
public abstract class AssistedInjectModule {
272
// No explicit binding needed - Dagger generates the factory implementation
273
}
274
275
@Component(modules = AssistedInjectModule.class)
276
public interface ApplicationComponent {
277
UserSessionFactory userSessionFactory();
278
DatabaseConnectionFactory databaseConnectionFactory();
279
RepositoryFactory repositoryFactory();
280
}
281
```
282
283
### Assisted Injection Best Practices
284
285
**Clear Parameter Naming:**
286
```java
287
// Good: Clear parameter purposes
288
@AssistedInject
289
public FileProcessor(
290
Logger logger, // Injected
291
@Assisted("input") File inputFile, // Runtime
292
@Assisted("output") File outputFile // Runtime
293
) { /* ... */ }
294
295
// Avoid: Ambiguous parameters
296
@AssistedInject
297
public FileProcessor(
298
Logger logger,
299
@Assisted File file1,
300
@Assisted File file2
301
) { /* ... */ }
302
```
303
304
**Factory Interface Design:**
305
```java
306
// Good: Descriptive factory methods
307
@AssistedFactory
308
public interface HttpClientFactory {
309
HttpClient createWithTimeout(int timeoutSeconds);
310
HttpClient createWithAuth(String token, int timeoutSeconds);
311
}
312
313
// Avoid: Generic create method
314
@AssistedFactory
315
public interface HttpClientFactory {
316
HttpClient create(Object... params);
317
}
318
```
319
320
**Error Handling:**
321
```java
322
public class SafeAssistedInjection {
323
@AssistedInject
324
public SafeAssistedInjection(
325
Validator validator,
326
@Assisted String input
327
) {
328
// Validate runtime parameters
329
if (input == null || input.trim().isEmpty()) {
330
throw new IllegalArgumentException("Input cannot be null or empty");
331
}
332
this.validator = validator;
333
this.input = validator.validate(input);
334
}
335
}
336
```